From 1b3f7610d47ba5464e7aa2e16b5b1a27b7d0f5a3 Mon Sep 17 00:00:00 2001 From: cbdev Date: Fri, 6 Mar 2020 23:46:43 +0100 Subject: Implement openpixelcontrol broadcast (strip 0) input --- backends/openpixelcontrol.c | 191 +++++++++++++++++++++++++++++-------------- backends/openpixelcontrol.md | 3 + 2 files changed, 131 insertions(+), 63 deletions(-) (limited to 'backends') diff --git a/backends/openpixelcontrol.c b/backends/openpixelcontrol.c index 62cdb68..ca395d3 100644 --- a/backends/openpixelcontrol.c +++ b/backends/openpixelcontrol.c @@ -1,4 +1,5 @@ #define BACKEND_NAME "openpixelcontrol" +#define DEBUG #include @@ -115,7 +116,7 @@ static ssize_t openpixel_buffer_find(openpixel_instance_data* data, uint8_t stri static int openpixel_buffer_extend(openpixel_instance_data* data, uint8_t strip, uint8_t input, uint16_t length){ ssize_t buffer = openpixel_buffer_find(data, strip, input); - + //length is in component-channels, round it to the nearest rgb-triplet //this guarantees that any allocated buffer has at least three bytes, which is important to parts of the receive handler length = (length % 3) ? ((length / 3) + 1) * 3 : length; @@ -340,12 +341,86 @@ static int openpixel_client_new(instance* inst, int fd){ return mm_manage_fd(fd, BACKEND_NAME, 1, inst); } -static ssize_t openpixel_client_pixeldata(instance* inst, openpixel_client* client, uint8_t* buffer, size_t bytes_left){ - openpixel_instance_data* data = (openpixel_instance_data*) inst->impl; +static size_t openpixel_strip_pixeldata8(instance* inst, openpixel_client* client, uint8_t* data, openpixel_buffer* buffer, size_t bytes_left){ + channel* chan = NULL; + channel_value val; size_t u; + + for(u = 0; u < bytes_left; u++){ + //if over buffer length, ignore + if(u + client->offset >= buffer->bytes){ + client->buffer = -2; + break; + } + + //FIXME if at start of trailing non-multiple of 3, ignore + + //update changed channels + if(buffer->data.u8[u + client->offset] != data[u]){ + buffer->data.u8[u + client->offset] = data[u]; + chan = mm_channel(inst, ((uint64_t) buffer->strip << 32) | (u + client->offset + 1), 0); + if(chan){ + //push event + val.raw.u64 = data[u]; + val.normalised = (double) data[u] / 255.0; + if(mm_channel_event(chan, val)){ + LOG("Failed to push channel event to core"); + } + } + } + } + return u; +} + +static size_t openpixel_strip_pixeldata16(instance* inst, openpixel_client* client, uint8_t* data, openpixel_buffer* buffer, size_t bytes_left){ channel* chan = NULL; channel_value val; + size_t u; + for(u = 0; u < bytes_left; u++){ + //if over buffer length, ignore + if(u + client->offset >= buffer->bytes){ + client->buffer = -2; + break; + } + + //if at start of trailing non-multiple of 6, ignore + if((client->offset + u) >= (client->offset + client->left) - ((client->offset + client->left) % 6)){ + client->buffer = -2; + break; + } + + //byte-order conversion may be on message boundary, do it via a buffer + client->boundary.u8[(client->offset + u) % 2] = data[u]; + + //detect and update changed channels + if((client->offset + u) % 2 + && buffer->data.u16[(u + client->offset) / 2] != be16toh(client->boundary.u16)){ + buffer->data.u16[(u + client->offset) / 2] = be16toh(client->boundary.u16); + chan = mm_channel(inst, ((uint64_t) buffer->strip << 32) | ((u + client->offset) / 2 + 1), 0); + if(chan){ + //push event + val.raw.u64 = be16toh(client->boundary.u16);; + val.normalised = (double) val.raw.u64 / 65535.0; + if(mm_channel_event(chan, val)){ + LOG("Failed to push channel event to core"); + } + } + + } + } + return u; +} + +static ssize_t openpixel_client_pixeldata(instance* inst, openpixel_client* client, uint8_t* buffer, size_t bytes_left){ + openpixel_instance_data* data = (openpixel_instance_data*) inst->impl; + openpixel_client temp_client = { + .fd = -1 + }; + ssize_t u, p; + uint8_t processing_done = 1; + + //ignore data if(client->buffer == -2){ //ignore data u = min(client->left, bytes_left); @@ -353,71 +428,55 @@ static ssize_t openpixel_client_pixeldata(instance* inst, openpixel_client* clie client->left -= u; return u; } - else{ - if(data->mode == rgb8){ - for(u = 0; u < bytes_left; u++){ - //if over buffer length, ignore - if(u + client->offset >= data->buffer[client->buffer].bytes){ - client->buffer = -2; - break; + //handle broadcast data + else if(client->buffer == -3){ + //iterate all input strips + for(p = 0; p < data->buffers; p++){ + if(data->buffer[p].flags & OPENPIXEL_INPUT){ + //prepare temporary client + temp_client.buffer = p; + temp_client.hdr = client->hdr; + temp_client.hdr.strip = data->buffer[p].strip; + temp_client.offset = client->offset; + temp_client.left = client->left; + + //run processing on strip + if(data->mode == rgb8){ + openpixel_strip_pixeldata8(inst, &temp_client, buffer, data->buffer + p, bytes_left); } - - //FIXME if at start of trailing non-multiple of 3, ignore - - //update changed channels - if(data->buffer[client->buffer].data.u8[u + client->offset] != buffer[u]){ - data->buffer[client->buffer].data.u8[u + client->offset] = buffer[u]; - chan = mm_channel(inst, ((uint64_t) client->hdr.strip << 32) | (u + client->offset + 1), 0); - if(chan){ - //push event - val.raw.u64 = buffer[u]; - val.normalised = (double) buffer[u] / 255.0; - if(mm_channel_event(chan, val)){ - LOG("Failed to push channel event to core"); - } - } + else{ + openpixel_strip_pixeldata16(inst, &temp_client, buffer, data->buffer + p, bytes_left); + } + if(temp_client.buffer != -2){ + processing_done = 0; } } - - //update offsets - client->offset += u; - client->left -= u; - return u; } - else{ - for(u = 0; u < bytes_left; u++){ - //if over buffer length, ignore - if(u + client->offset >= data->buffer[client->buffer].bytes){ - client->buffer = -2; - break; - } - - //if at start of trailing non-multiple of 6, ignore - if((client->offset + u) >= (client->offset + client->left) - ((client->offset + client->left) % 6)){ - client->buffer = -2; - break; - } - //byte-order conversion may be on message boundary, do it via a buffer - client->boundary.u8[(client->offset + u) % 2] = buffer[u]; - - //detect and update changed channels - if((client->offset + u) % 2 - && data->buffer[client->buffer].data.u16[(u + client->offset) / 2] != be16toh(client->boundary.u16)){ - data->buffer[client->buffer].data.u16[(u + client->offset) / 2] = be16toh(client->boundary.u16); - chan = mm_channel(inst, ((uint64_t) client->hdr.strip << 32) | ((u + client->offset) / 2 + 1), 0); - if(chan){ - //push event - val.raw.u64 = be16toh(client->boundary.u16);; - val.normalised = (double) val.raw.u64 / 65535.0; - if(mm_channel_event(chan, val)){ - LOG("Failed to push channel event to core"); - } - } + //if all strips report being done, ignore the rest of the data + if(processing_done){ + client->buffer = -2; + } - } - } + //remove data + u = min(client->left, bytes_left); + client->offset += u; + client->left -= u; + return u; + } + //process data + else{ + if(data->mode == rgb8){ + u = openpixel_strip_pixeldata8(inst, client, buffer, data->buffer + client->buffer, bytes_left); + } + else{ + u = openpixel_strip_pixeldata16(inst, client, buffer, data->buffer + client->buffer, bytes_left); } + + //update offsets + client->offset += u; + client->left -= u; + return u; } return -1; } @@ -431,8 +490,14 @@ static ssize_t openpixel_client_headerdata(instance* inst, openpixel_client* cli //if done, resolve buffer if(sizeof(openpixel_header) - client->offset <= bytes_left){ - client->buffer = openpixel_buffer_find(data, client->hdr.strip, 1); - //TODO handle broadcast strip input + //if broadcast strip, mark broadcast + if(client->hdr.strip == 0 + && data->mode == client->hdr.mode){ + client->buffer = -3; + } + else{ + client->buffer = openpixel_buffer_find(data, client->hdr.strip, 1); + } //if no buffer or mode mismatch, ignore data if(client->buffer < 0 || data->mode != client->hdr.mode){ diff --git a/backends/openpixelcontrol.md b/backends/openpixelcontrol.md index 5a8686f..d09d412 100644 --- a/backends/openpixelcontrol.md +++ b/backends/openpixelcontrol.md @@ -50,3 +50,6 @@ This behaviour may be changed in future releases. While acting as an OpenPixelControl server, the backend allows multiple clients to connect. This may lead to confusing data output when multiple clients are trying to control the same strip. + +When acting as a 16bit OpenPixelControl server, input on the broadcast strip (strip 0) may cause erratic +value events on a few channels, especially with longer strips and inputs. -- cgit v1.2.3