From: AC0BI Date: Wed, 2 Mar 2022 04:44:26 +0000 (-0700) Subject: raspberrypi-pico: Cleanup whitespace, add a serial_close to api.c scan function X-Git-Url: https://sigrok.org/gitaction?a=commitdiff_plain;h=ac132f837f0b8c2dbf603e2b4ef0b98ab7f65340;p=libsigrok.git raspberrypi-pico: Cleanup whitespace, add a serial_close to api.c scan function --- diff --git a/src/hardware/raspberrypi-pico/api.c b/src/hardware/raspberrypi-pico/api.c index df058b9b..8f78d01f 100644 --- a/src/hardware/raspberrypi-pico/api.c +++ b/src/hardware/raspberrypi-pico/api.c @@ -33,247 +33,256 @@ #define SERIALCOMM "115200/8n1" static const uint32_t scanopts[] = { - SR_CONF_CONN, //Required OS name for the port, i.e. /dev/ttyACM0 - SR_CONF_SERIALCOMM, //Optional config of the port, i.e. 115200/8n1 + SR_CONF_CONN, //Required OS name for the port, i.e. /dev/ttyACM0 + SR_CONF_SERIALCOMM, //Optional config of the port, i.e. 115200/8n1 }; //PulseView reads a sample rate config list as a min, max and step. //If step is 1 then it creates a 1,2,5,10 set of selects, as well as the max. //If step is not 1, then it gives a place to enter any value, which gives the greatest flexibility static const uint64_t samplerates[] = { - SR_HZ(10), - SR_MHZ(120), - SR_HZ(2), + SR_HZ(10), + SR_MHZ(120), + SR_HZ(2), }; static const uint32_t drvopts[] = { - SR_CONF_OSCILLOSCOPE, - SR_CONF_LOGIC_ANALYZER, + SR_CONF_OSCILLOSCOPE, + SR_CONF_LOGIC_ANALYZER, }; + //SW trigger requires this static const int32_t trigger_matches[] = { - SR_TRIGGER_ZERO, - SR_TRIGGER_ONE, - SR_TRIGGER_RISING, - SR_TRIGGER_FALLING, - SR_TRIGGER_EDGE, + SR_TRIGGER_ZERO, + SR_TRIGGER_ONE, + SR_TRIGGER_RISING, + SR_TRIGGER_FALLING, + SR_TRIGGER_EDGE, }; static const uint32_t devopts[] = { //CLI prefers LIMIT_SAMPLES to be a list of high,low - SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, - SR_CONF_TRIGGER_MATCH | SR_CONF_LIST, - SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET, + SR_CONF_LIMIT_SAMPLES | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, + SR_CONF_TRIGGER_MATCH | SR_CONF_LIST, + SR_CONF_CAPTURE_RATIO | SR_CONF_GET | SR_CONF_SET, //pulseview needs a list return to allow sample rate setting - SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, + SR_CONF_SAMPLERATE | SR_CONF_GET | SR_CONF_SET | SR_CONF_LIST, }; static struct sr_dev_driver raspberrypi_pico_driver_info; -static GSList *scan(struct sr_dev_driver *di, GSList *options) +static GSList *scan(struct sr_dev_driver *di, GSList * options) { - struct sr_config *src; - struct sr_dev_inst *sdi; - struct sr_serial_dev_inst *serial; - struct dev_context *devc; - struct sr_channel *ch; - GSList *l; - int num_read; - unsigned int i; - const char *conn, *serialcomm; - char buf[32]; - int len; - uint8_t num_a,num_d,a_size; - gchar *channel_name; - - conn = serialcomm = NULL; - for (l = options; l; l = l->next) { - src = l->data; - switch (src->key) { - case SR_CONF_CONN: - conn = g_variant_get_string(src->data, NULL); - break; - case SR_CONF_SERIALCOMM: - serialcomm = g_variant_get_string(src->data, NULL); - break; - } - } - if (!conn) - return NULL; - - if (!serialcomm) - serialcomm = SERIALCOMM; - - serial = sr_serial_dev_inst_new(conn, serialcomm); - sr_info("Opening %s.", conn); - if (serial_open(serial, SERIAL_RDWR) != SR_OK){ - sr_err("1st serial open fail"); - return NULL; - } - - sr_info("Reseting device with *s at %s.", conn); - send_serial_char(serial,'*'); - g_usleep(10000); - //drain any inflight data - do{ - sr_warn("Drain reads"); - len=serial_read_blocking(serial, buf,32,100); - sr_warn("Drain reads done"); - if(len) sr_dbg("Dropping in flight serial data"); - }while(len>0); - - - //Send identify - num_read=send_serial_w_resp(serial,"i\n",buf,17); - if(num_read<16){ - sr_err("1st identify failed"); - serial_close(serial); - g_usleep(100000); - if (serial_open(serial, SERIAL_RDWR) != SR_OK){ - sr_err("2st serial open fail"); - return NULL; - } - g_usleep(100000); - sr_err("Send second *"); - send_serial_char(serial,'*'); - g_usleep(100000); - num_read=send_serial_w_resp(serial,"i\n",buf,17); - if(num_read<10){ - sr_err("Second attempt failed"); - return NULL; - } - } - //Expected ID response is SRPICO,AxxyDzz,VV - //where xx are number of analog channels, y is bytes per analog sample - //and zz is number of digital channels, and VV is two digit version# which must be 00 - if((num_read<16) - ||(strncmp(buf,"SRPICO,A",8)) - ||(buf[11]!='D') - ||(buf[15]!='0') - ||(buf[16]!='0')){ - sr_err("ERROR:Bad response string %s %d",buf,num_read); - return NULL; - } - a_size=buf[10]-'0'; - buf[10]='\0'; //Null to end the str for atois - buf[14]='\0'; //Null to end the str for atois - num_a=atoi(&buf[8]); - num_d=atoi(&buf[12]); - - sdi = g_malloc0(sizeof(struct sr_dev_inst)); - sdi->status = SR_ST_INACTIVE; - sdi->vendor = g_strdup("Raspberry Pi"); - sdi->model = g_strdup("PICO"); - sdi->version = g_strdup("00"); - sdi->conn = serial; - sdi->driver = &raspberrypi_pico_driver_info; - sdi->inst_type = SR_INST_SERIAL; - sdi->serial_num = g_strdup("N/A"); - if(((num_a==0)&&(num_d==0)) - ||(num_a>MAX_ANALOG_CHANNELS) - ||(num_d>MAX_DIGITAL_CHANNELS) - ||(a_size<1) - ||(a_size>4)){ - sr_err("ERROR: invalid channel config a %d d %d asz %d",num_a,num_d,a_size); - return NULL; - } - devc = g_malloc0(sizeof(struct dev_context)); - devc->a_size=a_size; - //multiple bytes per analog sample not supported - if((num_a>0)&&(devc->a_size!=1)){ - sr_err("Only Analog Size of 1 supported\n\r"); - return NULL; - } - devc->num_a_channels=num_a; - devc->num_d_channels=num_d; - devc->a_chan_mask=((1<d_chan_mask=((1<next) { + src = l->data; + switch (src->key) { + case SR_CONF_CONN: + conn = g_variant_get_string(src->data, NULL); + break; + case SR_CONF_SERIALCOMM: + serialcomm = g_variant_get_string(src->data, NULL); + break; + } + } + if (!conn) + return NULL; + + if (!serialcomm) + serialcomm = SERIALCOMM; + + serial = sr_serial_dev_inst_new(conn, serialcomm); + sr_info("Opening %s.", conn); + if (serial_open(serial, SERIAL_RDWR) != SR_OK) { + sr_err("1st serial open fail"); + return NULL; + } + + sr_info("Reseting device with *s at %s.", conn); + send_serial_char(serial, '*'); + g_usleep(10000); + //drain any inflight data + do { + sr_warn("Drain reads"); + len = serial_read_blocking(serial, buf, 32, 100); + sr_warn("Drain reads done"); + if (len) + sr_dbg("Dropping in flight serial data"); + } while (len > 0); + + + //Send identify + num_read = send_serial_w_resp(serial, "i\n", buf, 17); + if (num_read < 16) { + sr_err("1st identify failed"); + serial_close(serial); + g_usleep(100000); + if (serial_open(serial, SERIAL_RDWR) != SR_OK) { + sr_err("2st serial open fail"); + return NULL; + } + g_usleep(100000); + sr_err("Send second *"); + send_serial_char(serial, '*'); + g_usleep(100000); + num_read = send_serial_w_resp(serial, "i\n", buf, 17); + if (num_read < 10) { + sr_err("Second attempt failed"); + return NULL; + } + } + //Expected ID response is SRPICO,AxxyDzz,VV + //where xx are number of analog channels, y is bytes per analog sample + //and zz is number of digital channels, and VV is two digit version# which must be 00 + if ((num_read < 16) + || (strncmp(buf, "SRPICO,A", 8)) + || (buf[11] != 'D') + || (buf[15] != '0') + || (buf[16] != '0')) { + sr_err("ERROR:Bad response string %s %d", buf, num_read); + return NULL; + } + a_size = buf[10] - '0'; + buf[10] = '\0'; //Null to end the str for atois + buf[14] = '\0'; //Null to end the str for atois + num_a = atoi(&buf[8]); + num_d = atoi(&buf[12]); + + sdi = g_malloc0(sizeof(struct sr_dev_inst)); + sdi->status = SR_ST_INACTIVE; + sdi->vendor = g_strdup("Raspberry Pi"); + sdi->model = g_strdup("PICO"); + sdi->version = g_strdup("00"); + sdi->conn = serial; + sdi->driver = &raspberrypi_pico_driver_info; + sdi->inst_type = SR_INST_SERIAL; + sdi->serial_num = g_strdup("N/A"); + if (((num_a == 0) && (num_d == 0)) + || (num_a > MAX_ANALOG_CHANNELS) + || (num_d > MAX_DIGITAL_CHANNELS) + || (a_size < 1) + || (a_size > 4)) { + sr_err("ERROR: invalid channel config a %d d %d asz %d", + num_a, num_d, a_size); + return NULL; + } + devc = g_malloc0(sizeof(struct dev_context)); + devc->a_size = a_size; + //multiple bytes per analog sample not supported + if ((num_a > 0) && (devc->a_size != 1)) { + sr_err("Only Analog Size of 1 supported\n\r"); + return NULL; + } + devc->num_a_channels = num_a; + devc->num_d_channels = num_d; + devc->a_chan_mask = ((1 << num_a) - 1); + devc->d_chan_mask = ((1 << num_d) - 1); //The number of bytes that each digital sample in the buffers sent to the session. //All logical channels are packed together, where a slice of N channels takes roundup(N/8) bytes //This never changes even if channels are disabled because PV expects disabled channels to still //be accounted for in the packing - devc->dig_sample_bytes=((devc->num_d_channels+7)/8); - //These are the slice sizes of the data on the wire - //1 7 bit field per byte - devc->bytes_per_slice=(devc->num_a_channels*devc->a_size); - if(devc->num_d_channels>0){ - // logic sent in groups of 7 - devc->bytes_per_slice+=(devc->num_d_channels+6)/7; - } - sr_dbg("num channels a %d d %d bps %d dsb %d",num_a,num_d,devc->bytes_per_slice,devc->dig_sample_bytes); + devc->dig_sample_bytes = ((devc->num_d_channels + 7) / 8); + //These are the slice sizes of the data on the wire + //1 7 bit field per byte + devc->bytes_per_slice = (devc->num_a_channels * devc->a_size); + if (devc->num_d_channels > 0) { + // logic sent in groups of 7 + devc->bytes_per_slice += (devc->num_d_channels + 6) / 7; + } + sr_dbg("num channels a %d d %d bps %d dsb %d", num_a, num_d, + devc->bytes_per_slice, devc->dig_sample_bytes); //Each analog channel is it's own group //Digital are just channels //Grouping of channels is rather arbitrary as parameters like sample rate and number of samples //apply to all changes. Analog channels do have a scale and offset, but that is applied //without involvement of the session. - devc->analog_groups = g_malloc0(sizeof(struct sr_channel_group *) * - devc->num_a_channels); - for (i = 0; i < devc->num_a_channels; i++) { - channel_name = g_strdup_printf("A%d", i ); - //sdi, index, type, enabled,name - ch = sr_channel_new(sdi, i, SR_CHANNEL_ANALOG, TRUE, channel_name); - devc->analog_groups[i] = g_malloc0(sizeof(struct sr_channel_group)); - devc->analog_groups[i]->name = channel_name; - devc->analog_groups[i]->channels = g_slist_append(NULL, ch); - sdi->channel_groups = g_slist_append(sdi->channel_groups, - devc->analog_groups[i]); - } - - if (devc->num_d_channels>0) { - for (i = 0; i < devc->num_d_channels; i++){ - //Name digital channels starting at D2 to match pico board pin names - channel_name = g_strdup_printf("D%d", i+2); - sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE, - channel_name); - g_free(channel_name); - } - - } - //In large sample usages we get the call to receive with large transfers. - //Since the CDC serial implemenation can silenty lose data as it gets close to full, allocate - //storage for a half buffer which in a worst case scenario has 2x ratio of transmitted bytes - // to storage bytes. - //Note: The intent of making this buffer large is to prevent CDC serial buffer overflows. - //However, it is likely that if the host is running slow (i.e. it's a raspberry pi model 3) that it becomes - //compute bound and doesn't service CDC serial responses in time to not overflow the internal CDC buffers. - //And thus no serial buffer is large enough. But, it's only 256K.... - devc->serial_buffer_size=256000; - devc->buffer=NULL; - sr_dbg("Setting serial buffer size: %i.", devc->serial_buffer_size); - devc->cbuf_wrptr=0; - //While slices are sent as a group of one sample across all channels, sigrok wants analog - //channel data sent as separate packets. - //Logical trace values are packed together. - //A serial byte in normal mode never represent more than one sample so a 2x multiplier is plenty. - //In D4 mode a serial byte can represents 100s of samples due to RLE, but process_D4 ensures that - //it breaks up the rle_memset calls to prevent overflowing the sample buffer. - //that it doesn't overflow the sample buffers. - devc->sample_buf_size=devc->serial_buffer_size*2; - for(i=0;inum_a_channels;i++){ - devc->a_data_bufs[i]=NULL; - devc->a_pretrig_bufs[i]=NULL; - } - devc->d_data_buf=NULL; - devc->sample_rate=5000; - devc->capture_ratio=10; - devc->rxstate=RX_IDLE; - sdi->priv = devc; - //Set an initial value as various code relies on an inital value. - devc->limit_samples=1000; - - if(raspberrypi_pico_get_dev_cfg(sdi)!=SR_OK){ - return NULL; - }; - - sr_err("sr_err level logging enabled"); - sr_warn("sr_warn level logging enabled"); - sr_info("sr_info level logging enabled"); - sr_dbg("sr_dbg level logging enabled"); - sr_spew("sr_spew level logging enabled"); - - return std_scan_complete(di, g_slist_append(NULL, sdi)); + devc->analog_groups = g_malloc0(sizeof(struct sr_channel_group *) * + devc->num_a_channels); + for (i = 0; i < devc->num_a_channels; i++) { + channel_name = g_strdup_printf("A%d", i); + //sdi, index, type, enabled,name + ch = sr_channel_new(sdi, i, SR_CHANNEL_ANALOG, TRUE, + channel_name); + devc->analog_groups[i] = + g_malloc0(sizeof(struct sr_channel_group)); + devc->analog_groups[i]->name = channel_name; + devc->analog_groups[i]->channels = + g_slist_append(NULL, ch); + sdi->channel_groups = + g_slist_append(sdi->channel_groups, + devc->analog_groups[i]); + } + + if (devc->num_d_channels > 0) { + for (i = 0; i < devc->num_d_channels; i++) { + //Name digital channels starting at D2 to match pico board pin names + channel_name = g_strdup_printf("D%d", i + 2); + sr_channel_new(sdi, i, SR_CHANNEL_LOGIC, TRUE, + channel_name); + g_free(channel_name); + } + + } + //In large sample usages we get the call to receive with large transfers. + //Since the CDC serial implemenation can silenty lose data as it gets close to full, allocate + //storage for a half buffer which in a worst case scenario has 2x ratio of transmitted bytes + // to storage bytes. + //Note: The intent of making this buffer large is to prevent CDC serial buffer overflows. + //However, it is likely that if the host is running slow (i.e. it's a raspberry pi model 3) that it becomes + //compute bound and doesn't service CDC serial responses in time to not overflow the internal CDC buffers. + //And thus no serial buffer is large enough. But, it's only 256K.... + devc->serial_buffer_size = 256000; + devc->buffer = NULL; + sr_dbg("Setting serial buffer size: %i.", + devc->serial_buffer_size); + devc->cbuf_wrptr = 0; + //While slices are sent as a group of one sample across all channels, sigrok wants analog + //channel data sent as separate packets. + //Logical trace values are packed together. + //A serial byte in normal mode never represent more than one sample so a 2x multiplier is plenty. + //In D4 mode a serial byte can represents 100s of samples due to RLE, but process_D4 ensures that + //it breaks up the rle_memset calls to prevent overflowing the sample buffer. + //that it doesn't overflow the sample buffers. + devc->sample_buf_size = devc->serial_buffer_size * 2; + for (i = 0; i < devc->num_a_channels; i++) { + devc->a_data_bufs[i] = NULL; + devc->a_pretrig_bufs[i] = NULL; + } + devc->d_data_buf = NULL; + devc->sample_rate = 5000; + devc->capture_ratio = 10; + devc->rxstate = RX_IDLE; + sdi->priv = devc; + //Set an initial value as various code relies on an inital value. + devc->limit_samples = 1000; + + if (raspberrypi_pico_get_dev_cfg(sdi) != SR_OK) { + return NULL; + }; + + sr_err("sr_err level logging enabled"); + sr_warn("sr_warn level logging enabled"); + sr_info("sr_info level logging enabled"); + sr_dbg("sr_dbg level logging enabled"); + sr_spew("sr_spew level logging enabled"); + serial_close(serial); + return std_scan_complete(di, g_slist_append(NULL, sdi)); } @@ -281,411 +290,490 @@ static GSList *scan(struct sr_dev_driver *di, GSList *options) //Note that on the initial driver load we pull all values into local storage. //Thus gets can return local data, but sets have to issue commands to device. -static int config_set(uint32_t key, GVariant *data, - const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) +static int config_set(uint32_t key, GVariant * data, + const struct sr_dev_inst *sdi, + const struct sr_channel_group *cg) { - struct dev_context *devc; - int ret; - (void)cg; - if (!sdi) - return SR_ERR_ARG; - devc=sdi->priv; - ret = SR_OK; - sr_dbg("Got config_set key %d \n",key); - switch (key) { - case SR_CONF_SAMPLERATE: - devc->sample_rate = g_variant_get_uint64(data); - sr_dbg("config_set sr %llu\n",devc->sample_rate); - break; - case SR_CONF_LIMIT_SAMPLES: - devc->limit_samples = g_variant_get_uint64(data); - sr_dbg("config_set slimit %lld\n",devc->limit_samples); - break; - case SR_CONF_CAPTURE_RATIO: - devc->capture_ratio = g_variant_get_uint64(data); - break; - - default: - sr_err("ERROR:config_set undefine %d\n",key); - ret = SR_ERR_NA; - } - - return ret; + struct dev_context *devc; + int ret; + (void) cg; + if (!sdi) + return SR_ERR_ARG; + devc = sdi->priv; + ret = SR_OK; + sr_dbg("Got config_set key %d \n", key); + switch (key) { + case SR_CONF_SAMPLERATE: + devc->sample_rate = g_variant_get_uint64(data); + sr_dbg("config_set sr %llu\n", devc->sample_rate); + break; + case SR_CONF_LIMIT_SAMPLES: + devc->limit_samples = g_variant_get_uint64(data); + sr_dbg("config_set slimit %lld\n", devc->limit_samples); + break; + case SR_CONF_CAPTURE_RATIO: + devc->capture_ratio = g_variant_get_uint64(data); + break; + + default: + sr_err("ERROR:config_set undefine %d\n", key); + ret = SR_ERR_NA; + } + + return ret; } -static int config_get(uint32_t key, GVariant **data, - const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) +static int config_get(uint32_t key, GVariant ** data, + const struct sr_dev_inst *sdi, + const struct sr_channel_group *cg) { - struct dev_context *devc; - sr_dbg("at config_get key %d",key); - (void)cg; - if (!sdi) - return SR_ERR_ARG; - - devc = sdi->priv; - switch (key) { - case SR_CONF_SAMPLERATE: - *data = g_variant_new_uint64(devc->sample_rate); - sr_spew("sample rate get of %lld",devc->sample_rate); - break; - case SR_CONF_CAPTURE_RATIO: - if (!sdi) - return SR_ERR; - devc = sdi->priv; - *data = g_variant_new_uint64(devc->capture_ratio); - break; - case SR_CONF_LIMIT_SAMPLES: - sr_spew("config_get limit_samples of %llu",devc->limit_samples); - *data = g_variant_new_uint64(devc->limit_samples); - break; - default: - sr_spew("unsupported cfg_get key %d",key); - return SR_ERR_NA; - } - return SR_OK; + struct dev_context *devc; + sr_dbg("at config_get key %d", key); + (void) cg; + if (!sdi) + return SR_ERR_ARG; + + devc = sdi->priv; + switch (key) { + case SR_CONF_SAMPLERATE: + *data = g_variant_new_uint64(devc->sample_rate); + sr_spew("sample rate get of %lld", devc->sample_rate); + break; + case SR_CONF_CAPTURE_RATIO: + if (!sdi) + return SR_ERR; + devc = sdi->priv; + *data = g_variant_new_uint64(devc->capture_ratio); + break; + case SR_CONF_LIMIT_SAMPLES: + sr_spew("config_get limit_samples of %llu", + devc->limit_samples); + *data = g_variant_new_uint64(devc->limit_samples); + break; + default: + sr_spew("unsupported cfg_get key %d", key); + return SR_ERR_NA; + } + return SR_OK; } -static int config_list(uint32_t key, GVariant **data, - const struct sr_dev_inst *sdi, const struct sr_channel_group *cg) +static int config_list(uint32_t key, GVariant ** data, + const struct sr_dev_inst *sdi, + const struct sr_channel_group *cg) { - (void)cg; - //scan or device options are the only ones that can be called without a defined instance - if((key==SR_CONF_SCAN_OPTIONS)||(key==SR_CONF_DEVICE_OPTIONS)){ - return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, drvopts, devopts); - } - if (!sdi){ - sr_err("ERROR:\n\r\n\r\n\r Call to config list with null sdi\n\r\n\r"); - return SR_ERR_ARG; - } - sr_dbg("start config_list with key %X\n",key); - switch(key){ + (void) cg; + //scan or device options are the only ones that can be called without a defined instance + if ((key == SR_CONF_SCAN_OPTIONS) + || (key == SR_CONF_DEVICE_OPTIONS)) { + return STD_CONFIG_LIST(key, data, sdi, cg, scanopts, + drvopts, devopts); + } + if (!sdi) { + sr_err + ("ERROR:\n\r\n\r\n\r Call to config list with null sdi\n\r\n\r"); + return SR_ERR_ARG; + } + sr_dbg("start config_list with key %X\n", key); + switch (key) { //Pulseview in pulseview/pv/toolbars/mainbar.cpp requires list support for frequencies as a triple //of min,max,step. If step is 1, then it proves a 1,2,5,10 select, but if not 1 it allows a spin box - case SR_CONF_SAMPLERATE: - sr_dbg("Return sample rate list"); - *data = std_gvar_samplerates_steps(ARRAY_AND_SIZE(samplerates)); - break; + case SR_CONF_SAMPLERATE: + sr_dbg("Return sample rate list"); + *data = + std_gvar_samplerates_steps(ARRAY_AND_SIZE + (samplerates)); + break; //This must be set to get SW trigger support - case SR_CONF_TRIGGER_MATCH: - *data = std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches)); - break; - case SR_CONF_LIMIT_SAMPLES: - //Really this limit is up to the memory capacity of the host, - //and users that pick huge values deserve what they get. - //But setting this limit to prevent really crazy things. - *data = std_gvar_tuple_u64(1LL,1000000000LL); - sr_dbg("sr_config_list limit samples "); - break; - default: - sr_dbg("reached default statement of config_list"); - - return SR_ERR_NA; - } - - return SR_OK; + case SR_CONF_TRIGGER_MATCH: + *data = + std_gvar_array_i32(ARRAY_AND_SIZE(trigger_matches)); + break; + case SR_CONF_LIMIT_SAMPLES: + //Really this limit is up to the memory capacity of the host, + //and users that pick huge values deserve what they get. + //But setting this limit to prevent really crazy things. + *data = std_gvar_tuple_u64(1LL, 1000000000LL); + sr_dbg("sr_config_list limit samples "); + break; + default: + sr_dbg("reached default statement of config_list"); + + return SR_ERR_NA; + } + + return SR_OK; } static int dev_acquisition_start(const struct sr_dev_inst *sdi) { - struct sr_serial_dev_inst *serial; - struct dev_context *devc; - struct sr_channel *ch; - struct sr_trigger *trigger; - char tmpstr[20]; - GSList *l; - int a_enabled=0,d_enabled=0,len; - serial = sdi->conn; - int i; - devc = sdi->priv; - sr_dbg("Enter acq start"); - sr_dbg("dsbstart %d",devc->dig_sample_bytes); - devc->buffer = g_malloc(devc->serial_buffer_size); - if(!(devc->buffer)){sr_err("ERROR:serial buffer malloc fail");return SR_ERR_MALLOC;} - //Get device in idle state - if(serial_drain(serial)!=SR_OK){sr_err("Initial Drain Failed\n\r");return SR_ERR;} - send_serial_char(serial,'*'); - if(serial_drain(serial)!=SR_OK){sr_err("Second Drain Failed\n\r");return SR_ERR;} - - for (l = sdi->channels; l; l = l->next) { - ch = l->data; - sr_dbg("c %d enabled %d name %s\n",ch->index,ch->enabled,ch->name); - - if(ch->name[0]=='A'){ - devc->a_chan_mask&=~(1<index); - if(ch->enabled) { - devc->a_chan_mask|=(ch->enabled<index); - a_enabled++; - } + struct sr_serial_dev_inst *serial; + struct dev_context *devc; + struct sr_channel *ch; + struct sr_trigger *trigger; + char tmpstr[20]; + GSList *l; + int a_enabled = 0, d_enabled = 0, len; + serial = sdi->conn; + int i; + devc = sdi->priv; + sr_dbg("Enter acq start"); + sr_dbg("dsbstart %d", devc->dig_sample_bytes); + devc->buffer = g_malloc(devc->serial_buffer_size); + if (!(devc->buffer)) { + sr_err("ERROR:serial buffer malloc fail"); + return SR_ERR_MALLOC; + } + //Get device in idle state + if (serial_drain(serial) != SR_OK) { + sr_err("Initial Drain Failed\n\r"); + return SR_ERR; + } + send_serial_char(serial, '*'); + if (serial_drain(serial) != SR_OK) { + sr_err("Second Drain Failed\n\r"); + return SR_ERR; + } + + for (l = sdi->channels; l; l = l->next) { + ch = l->data; + sr_dbg("c %d enabled %d name %s\n", ch->index, ch->enabled, + ch->name); + + if (ch->name[0] == 'A') { + devc->a_chan_mask &= ~(1 << ch->index); + if (ch->enabled) { + devc->a_chan_mask |= + (ch->enabled << ch->index); + a_enabled++; + } // sr_dbg("A%d en %d mask 0x%X",ch->index,ch->enabled,devc->a_chan_mask); - - } - if(ch->name[0]=='D'){ - devc->d_chan_mask&=~(1<index); - if(ch->enabled) { - devc->d_chan_mask|=(ch->enabled<index); - d_enabled++; - // sr_dbg("D%d en %d mask 0x%X",ch->index,ch->enabled,devc->d_chan_mask); - } - } - sr_info("Channel enable masks D 0x%X A 0x%X",devc->d_chan_mask,devc->a_chan_mask); - sprintf(tmpstr,"%c%d%d\n",ch->name[0],ch->enabled,ch->index); - if (send_serial_w_ack(serial,tmpstr) != SR_OK){ - sr_err("ERROR:Channel enable fail"); - return SR_ERR; - } else{ - - } - }//for all channels - //ensure data channels are continuous - int invalid=0; - for(i=0;i<32;i++){ - if((devc->d_chan_mask>>i)&1){ - if(invalid){ - sr_err("Digital channel mask 0x%X not continous\n\r",devc->d_chan_mask); - return SR_ERR; - } - } - else{ - invalid=1; - } - } - //recalculate bytes_per_slice. - devc->bytes_per_slice=(a_enabled*devc->a_size); - - for(i=0;inum_d_channels;i+=7){ - if(((devc->d_chan_mask)>>i)&(0x7F)){(devc->bytes_per_slice)++;} - } - if((a_enabled==0)&&(d_enabled==0)){ - sr_err("ERROR:No channels enabled"); - return SR_ERR; - } - sr_dbg("bps %d\n",devc->bytes_per_slice); - - //Apply sample rate limits - //Save off the lower rate values which are hacked way of getting configs to the device - uint8_t cfg_bits; - cfg_bits=(devc->sample_rate%10&0x6); //Only bits 2&1 are used as cfg_bits - devc->sample_rate-=cfg_bits; - sr_warn("Capture device cfg_bits of 0x%X from sample rate %lld",cfg_bits,devc->sample_rate); - if((a_enabled==3)&&(devc->sample_rate>166660)){ - sr_err("ERROR:3 channel ADC sample rate dropped to 166.660khz"); - devc->sample_rate=166660; - } - if((a_enabled==2)&&(devc->sample_rate>250000)){ - sr_err("ERROR:2 channel ADC sample rate dropped to 250khz"); - devc->sample_rate=250000; - } - if((a_enabled==1)&&(devc->sample_rate>500000)){ - sr_err("ERROR:1 channel ADC sample rate dropped to 500khz"); - devc->sample_rate=500000; - } - //Depending on channel configs, rates below 5ksps are possible - //but such a low rate can easily stream and this eliminates a lot - //of special cases. - if(devc->sample_rate<5000){ - sr_err("Sample rate override to min of 5ksps"); - devc->sample_rate=5000; - } - if(devc->sample_rate>120000000){ - sr_err("Sample rate override to max of 120Msps"); - devc->sample_rate=12000000; - } - //It may take a very large number of samples to notice, but if digital and analog are enabled - //and either PIO or ADC are fractional the samples will skew over time. - //24Mhz is the max common divisor to the 120Mhz and 48Mhz ADC clock - //so force an integer divisor to it. - if((a_enabled>0)&&(d_enabled>0)){ - if(24000000ULL%(devc->sample_rate)){ - uint32_t commondivint=24000000ULL/(devc->sample_rate); - //Always increment the divisor so that we go down in frequency to avoid max sample rate issues - commondivint++; - devc->sample_rate=24000000ULL/commondivint; - //While the common divisor is an integer, that does not mean the resulting sample rate is, and - //we want to keep the sample_rate divisible by 10 to support the cfg_bits - while((devc->sample_rate%10)&&(commondivint<4800)){ - commondivint++; - devc->sample_rate=24000000ULL/commondivint; - //sr_err(" sample rate of %llu div %u\n\r",devc->sample_rate,commondivint); - } - //Make sure the divisor increement didn't make use go too low. - if(devc->sample_rate<5000){devc->sample_rate=50000;} - sr_err("WARN: Forcing common integer divisor sample rate of %llu div %u\n\r",devc->sample_rate,commondivint); - } - - } - //If we are only digital only or only analog print a warning that the - //fractional divisors aren't a true PLL fractional feedback loop and thus - //could have sample to sample variation. - if(a_enabled>0){ - if(48000000ULL%(devc->sample_rate*a_enabled)){ - sr_warn("WARN: Non integer ADC divisor of 48Mhz clock for sample rate %llu may cause sample to sample variability.",devc->sample_rate); - } - } - if(d_enabled>0){ - if(120000000ULL%(devc->sample_rate)){ - sr_warn("WARN: Non integer PIO divisor of 120Mhz for sample rate %llu may cause sample to sample variability.",devc->sample_rate); - } - } - - - //modulo 10 to add cfg_bits back in - //All code above should create overrides that are multiples of 10, but add a check just in case. - if(devc->sample_rate%10){ - sr_err("Output sample rate %llu not mod 10",devc->sample_rate); - devc->sample_rate=(devc->sample_rate/10)*10; - } - - devc->sample_rate+=cfg_bits; - if(cfg_bits){ - sr_warn("Embedding cfg_bits of 0x%X in sample_rate %lld\n\r",cfg_bits,devc->sample_rate); - } - sprintf(&tmpstr[0],"R%llu\n", devc->sample_rate); - if(send_serial_w_ack(serial, tmpstr)!=SR_OK) { - sr_err("Sample rate to device failed"); - return SR_ERR; - } - sprintf(tmpstr,"L%lld\n", devc->limit_samples); - if(send_serial_w_ack(serial, tmpstr)!=SR_OK) { - sr_err("Sample limit to device failed"); - return SR_ERR; - } - - - devc->sent_samples=0; - devc->byte_cnt=0; - devc->bytes_avail=0; - devc->wrptr=0; - devc->cbuf_wrptr=0; - len=serial_read_blocking(serial, devc->buffer, devc->serial_buffer_size,serial_timeout(serial, 4)); - if(len>0){ - sr_info("Pre-ARM drain had %d characters:",len); - devc->buffer[len]=0; - sr_info("%s",devc->buffer); - } - - for(i=0;inum_a_channels;i++){ - devc->a_data_bufs[i]=g_malloc(devc->sample_buf_size*sizeof(float)); - if(!(devc->a_data_bufs[i])){sr_err("ERROR:analog buffer malloc fail");return SR_ERR_MALLOC;} - } - if(devc->num_d_channels>0){ - devc->d_data_buf=g_malloc(devc->sample_buf_size*devc->dig_sample_bytes); - if(!(devc->d_data_buf)){sr_err("ERROR:logic buffer malloc fail");return SR_ERR_MALLOC;} - } - - if ((trigger = sr_session_trigger_get(sdi->session))) { - devc->pretrig_entries = (devc->capture_ratio * devc->limit_samples) / 100; - devc->stl = soft_trigger_logic_new(sdi, trigger, devc->pretrig_entries); - if (!devc->stl) - return SR_ERR_MALLOC; - devc->trigger_fired=FALSE; - if(devc->pretrig_entries>0){ - sr_dbg("Allocating pretrig buffers size %d",devc->pretrig_entries); - for(i=0;inum_a_channels;i++){ - if((devc->a_chan_mask>>i)&1){ - devc->a_pretrig_bufs[i] = g_malloc0(sizeof(float)*devc->pretrig_entries); - if(!devc->a_pretrig_bufs[i]){ - sr_err("ERROR:Analog pretrigger buffer malloc failure, disabling"); - devc->trigger_fired=TRUE; - } - }//if chan_mask - }//for num_a_channels - }//if pre_trigger - sr_info("Entering sw triggered mode"); - //post the receive before starting the device to ensure we are ready to receive data ASAP - serial_source_add(sdi->session, serial, G_IO_IN, 200,raspberrypi_pico_receive, (void *) sdi); - sprintf(tmpstr,"C\n"); - if(send_serial_str(serial, tmpstr) != SR_OK) - return SR_ERR; - - } else{ - devc->trigger_fired=TRUE; - devc->pretrig_entries=0; - sr_info("Entering fixed sample mode"); - serial_source_add(sdi->session, serial, G_IO_IN, 200,raspberrypi_pico_receive, (void *) sdi); - sprintf(tmpstr,"F\n"); - if(send_serial_str(serial,tmpstr) != SR_OK) - return SR_ERR; - } - std_session_send_df_header(sdi); - - sr_dbg("dsbstartend %d",devc->dig_sample_bytes); - - if(devc->trigger_fired) std_session_send_df_trigger(sdi); - //Keep this at the end as we don't want to be RX_ACTIVE unless everything is ok - devc->rxstate=RX_ACTIVE; - - return SR_OK; + + } + if (ch->name[0] == 'D') { + devc->d_chan_mask &= ~(1 << ch->index); + if (ch->enabled) { + devc->d_chan_mask |= + (ch->enabled << ch->index); + d_enabled++; + // sr_dbg("D%d en %d mask 0x%X",ch->index,ch->enabled,devc->d_chan_mask); + } + } + sr_info("Channel enable masks D 0x%X A 0x%X", + devc->d_chan_mask, devc->a_chan_mask); + sprintf(tmpstr, "%c%d%d\n", ch->name[0], ch->enabled, + ch->index); + if (send_serial_w_ack(serial, tmpstr) != SR_OK) { + sr_err("ERROR:Channel enable fail"); + return SR_ERR; + } else { + + } + } //for all channels + //ensure data channels are continuous + int invalid = 0; + for (i = 0; i < 32; i++) { + if ((devc->d_chan_mask >> i) & 1) { + if (invalid) { + sr_err + ("Digital channel mask 0x%X not continous\n\r", + devc->d_chan_mask); + return SR_ERR; + } + } else { + invalid = 1; + } + } + //recalculate bytes_per_slice. + devc->bytes_per_slice = (a_enabled * devc->a_size); + + for (i = 0; i < devc->num_d_channels; i += 7) { + if (((devc->d_chan_mask) >> i) & (0x7F)) { + (devc->bytes_per_slice)++; + } + } + if ((a_enabled == 0) && (d_enabled == 0)) { + sr_err("ERROR:No channels enabled"); + return SR_ERR; + } + sr_dbg("bps %d\n", devc->bytes_per_slice); + + //Apply sample rate limits + //Save off the lower rate values which are hacked way of getting configs to the device + uint8_t cfg_bits; + cfg_bits = (devc->sample_rate % 10 & 0x6); //Only bits 2&1 are used as cfg_bits + devc->sample_rate -= cfg_bits; + sr_warn("Capture device cfg_bits of 0x%X from sample rate %lld", + cfg_bits, devc->sample_rate); + if ((a_enabled == 3) && (devc->sample_rate > 166660)) { + sr_err + ("ERROR:3 channel ADC sample rate dropped to 166.660khz"); + devc->sample_rate = 166660; + } + if ((a_enabled == 2) && (devc->sample_rate > 250000)) { + sr_err + ("ERROR:2 channel ADC sample rate dropped to 250khz"); + devc->sample_rate = 250000; + } + if ((a_enabled == 1) && (devc->sample_rate > 500000)) { + sr_err + ("ERROR:1 channel ADC sample rate dropped to 500khz"); + devc->sample_rate = 500000; + } + //Depending on channel configs, rates below 5ksps are possible + //but such a low rate can easily stream and this eliminates a lot + //of special cases. + if (devc->sample_rate < 5000) { + sr_err("Sample rate override to min of 5ksps"); + devc->sample_rate = 5000; + } + if (devc->sample_rate > 120000000) { + sr_err("Sample rate override to max of 120Msps"); + devc->sample_rate = 12000000; + } + //It may take a very large number of samples to notice, but if digital and analog are enabled + //and either PIO or ADC are fractional the samples will skew over time. + //24Mhz is the max common divisor to the 120Mhz and 48Mhz ADC clock + //so force an integer divisor to it. + if ((a_enabled > 0) && (d_enabled > 0)) { + if (24000000ULL % (devc->sample_rate)) { + uint32_t commondivint = + 24000000ULL / (devc->sample_rate); + //Always increment the divisor so that we go down in frequency to avoid max sample rate issues + commondivint++; + devc->sample_rate = 24000000ULL / commondivint; + //While the common divisor is an integer, that does not mean the resulting sample rate is, and + //we want to keep the sample_rate divisible by 10 to support the cfg_bits + while ((devc->sample_rate % 10) + && (commondivint < 4800)) { + commondivint++; + devc->sample_rate = + 24000000ULL / commondivint; + //sr_err(" sample rate of %llu div %u\n\r",devc->sample_rate,commondivint); + } + //Make sure the divisor increement didn't make use go too low. + if (devc->sample_rate < 5000) { + devc->sample_rate = 50000; + } + sr_err + ("WARN: Forcing common integer divisor sample rate of %llu div %u\n\r", + devc->sample_rate, commondivint); + } + + } + //If we are only digital only or only analog print a warning that the + //fractional divisors aren't a true PLL fractional feedback loop and thus + //could have sample to sample variation. + if (a_enabled > 0) { + if (48000000ULL % (devc->sample_rate * a_enabled)) { + sr_warn + ("WARN: Non integer ADC divisor of 48Mhz clock for sample rate %llu may cause sample to sample variability.", + devc->sample_rate); + } + } + if (d_enabled > 0) { + if (120000000ULL % (devc->sample_rate)) { + sr_warn + ("WARN: Non integer PIO divisor of 120Mhz for sample rate %llu may cause sample to sample variability.", + devc->sample_rate); + } + } + + //modulo 10 to add cfg_bits back in + //All code above should create overrides that are multiples of 10, but add a check just in case. + if (devc->sample_rate % 10) { + sr_err("Output sample rate %llu not mod 10", + devc->sample_rate); + devc->sample_rate = (devc->sample_rate / 10) * 10; + } + + devc->sample_rate += cfg_bits; + if (cfg_bits) { + sr_warn + ("Embedding cfg_bits of 0x%X in sample_rate %lld\n\r", + cfg_bits, devc->sample_rate); + } + sprintf(&tmpstr[0], "R%llu\n", devc->sample_rate); + if (send_serial_w_ack(serial, tmpstr) != SR_OK) { + sr_err("Sample rate to device failed"); + return SR_ERR; + } + sprintf(tmpstr, "L%lld\n", devc->limit_samples); + if (send_serial_w_ack(serial, tmpstr) != SR_OK) { + sr_err("Sample limit to device failed"); + return SR_ERR; + } + + + devc->sent_samples = 0; + devc->byte_cnt = 0; + devc->bytes_avail = 0; + devc->wrptr = 0; + devc->cbuf_wrptr = 0; + len = + serial_read_blocking(serial, devc->buffer, + devc->serial_buffer_size, + serial_timeout(serial, 4)); + if (len > 0) { + sr_info("Pre-ARM drain had %d characters:", len); + devc->buffer[len] = 0; + sr_info("%s", devc->buffer); + } + + for (i = 0; i < devc->num_a_channels; i++) { + devc->a_data_bufs[i] = + g_malloc(devc->sample_buf_size * sizeof(float)); + if (!(devc->a_data_bufs[i])) { + sr_err("ERROR:analog buffer malloc fail"); + return SR_ERR_MALLOC; + } + } + if (devc->num_d_channels > 0) { + devc->d_data_buf = + g_malloc(devc->sample_buf_size * + devc->dig_sample_bytes); + if (!(devc->d_data_buf)) { + sr_err("ERROR:logic buffer malloc fail"); + return SR_ERR_MALLOC; + } + } + + if ((trigger = sr_session_trigger_get(sdi->session))) { + devc->pretrig_entries = + (devc->capture_ratio * devc->limit_samples) / 100; + devc->stl = + soft_trigger_logic_new(sdi, trigger, + devc->pretrig_entries); + if (!devc->stl) + return SR_ERR_MALLOC; + devc->trigger_fired = FALSE; + if (devc->pretrig_entries > 0) { + sr_dbg("Allocating pretrig buffers size %d", + devc->pretrig_entries); + for (i = 0; i < devc->num_a_channels; i++) { + if ((devc->a_chan_mask >> i) & 1) { + devc->a_pretrig_bufs[i] = + g_malloc0(sizeof(float) * + devc-> + pretrig_entries); + if (!devc->a_pretrig_bufs[i]) { + sr_err + ("ERROR:Analog pretrigger buffer malloc failure, disabling"); + devc->trigger_fired = TRUE; + } + } //if chan_mask + } //for num_a_channels + } //if pre_trigger + sr_info("Entering sw triggered mode"); + //post the receive before starting the device to ensure we are ready to receive data ASAP + serial_source_add(sdi->session, serial, G_IO_IN, 200, + raspberrypi_pico_receive, (void *) sdi); + sprintf(tmpstr, "C\n"); + if (send_serial_str(serial, tmpstr) != SR_OK) + return SR_ERR; + + } else { + devc->trigger_fired = TRUE; + devc->pretrig_entries = 0; + sr_info("Entering fixed sample mode"); + serial_source_add(sdi->session, serial, G_IO_IN, 200, + raspberrypi_pico_receive, (void *) sdi); + sprintf(tmpstr, "F\n"); + if (send_serial_str(serial, tmpstr) != SR_OK) + return SR_ERR; + } + std_session_send_df_header(sdi); + + sr_dbg("dsbstartend %d", devc->dig_sample_bytes); + + if (devc->trigger_fired) + std_session_send_df_trigger(sdi); + //Keep this at the end as we don't want to be RX_ACTIVE unless everything is ok + devc->rxstate = RX_ACTIVE; + + return SR_OK; } + //This function is called either by the protocol code if we reached all of the samples //or an error condition, and also by the user clicking stop in pulseview. //It must always be called for any acquistion that was started to free memory. static int dev_acquisition_stop(struct sr_dev_inst *sdi) { - struct dev_context *devc; - struct sr_serial_dev_inst *serial; - sr_dbg("****at dev_acquisition_stop"); - int len; - devc = sdi->priv; - serial = sdi->conn; - - std_session_send_df_end(sdi); - //If we reached this while still active it is likely because the stop button was pushed - //in pulseview. - //That is generally some kind of error condition, so we don't try to check the bytenct - if(devc->rxstate==RX_ACTIVE){ - sr_err("Reached dev_acquisition_stop in RX_ACTIVE"); - } - if(devc->rxstate!=RX_IDLE){ - sr_err("Sending plus to stop device stream\n\r"); - send_serial_char(serial,'+'); - } - //In case we get calls to receive force it to exit - devc->rxstate=RX_IDLE; - //drain data from device so that it doesn't confuse subsequent commands - do{ - len=serial_read_blocking(serial, devc->buffer, devc->serial_buffer_size,100); - if(len) sr_err("Dropping %d device bytes\n\r",len); - }while(len>0); - - - - if(devc->buffer){g_free(devc->buffer);devc->buffer=NULL;} - - for(int i=0;inum_a_channels;i++){ - if(devc->a_data_bufs[i]){ - g_free(devc->a_data_bufs[i]); - devc->a_data_bufs[i]=NULL; - } - } - - if(devc->d_data_buf){g_free(devc->d_data_buf);devc->d_data_buf=NULL;} - for(int i=0;inum_a_channels;i++){ - if(devc->a_pretrig_bufs[i]) g_free(devc->a_pretrig_bufs[i]); - devc->a_pretrig_bufs[i]=NULL; - } - - serial= sdi->conn; - serial_source_remove(sdi->session, serial); - - return SR_OK; + struct dev_context *devc; + struct sr_serial_dev_inst *serial; + sr_dbg("****at dev_acquisition_stop"); + int len; + devc = sdi->priv; + serial = sdi->conn; + + std_session_send_df_end(sdi); + //If we reached this while still active it is likely because the stop button was pushed + //in pulseview. + //That is generally some kind of error condition, so we don't try to check the bytenct + if (devc->rxstate == RX_ACTIVE) { + sr_err("Reached dev_acquisition_stop in RX_ACTIVE"); + } + if (devc->rxstate != RX_IDLE) { + sr_err("Sending plus to stop device stream\n\r"); + send_serial_char(serial, '+'); + } + //In case we get calls to receive force it to exit + devc->rxstate = RX_IDLE; + //drain data from device so that it doesn't confuse subsequent commands + do { + len = + serial_read_blocking(serial, devc->buffer, + devc->serial_buffer_size, 100); + if (len) + sr_err("Dropping %d device bytes\n\r", len); + } while (len > 0); + + + + if (devc->buffer) { + g_free(devc->buffer); + devc->buffer = NULL; + } + + for (int i = 0; i < devc->num_a_channels; i++) { + if (devc->a_data_bufs[i]) { + g_free(devc->a_data_bufs[i]); + devc->a_data_bufs[i] = NULL; + } + } + + if (devc->d_data_buf) { + g_free(devc->d_data_buf); + devc->d_data_buf = NULL; + } + for (int i = 0; i < devc->num_a_channels; i++) { + if (devc->a_pretrig_bufs[i]) + g_free(devc->a_pretrig_bufs[i]); + devc->a_pretrig_bufs[i] = NULL; + } + + serial = sdi->conn; + serial_source_remove(sdi->session, serial); + + return SR_OK; } static struct sr_dev_driver raspberrypi_pico_driver_info = { - .name = "raspberrypi-pico", - .longname = "RaspberryPI PICO", - .api_version = 1, - .init = std_init, - .cleanup = std_cleanup, - .scan = scan, - .dev_list = std_dev_list, - .dev_clear = std_dev_clear, - .config_get = config_get, - .config_set = config_set, - .config_list = config_list, - .dev_open = std_serial_dev_open, - .dev_close = std_serial_dev_close, - .dev_acquisition_start = dev_acquisition_start, - .dev_acquisition_stop = dev_acquisition_stop, - .context = NULL, + .name = "raspberrypi-pico", + .longname = "RaspberryPI PICO", + .api_version = 1, + .init = std_init, + .cleanup = std_cleanup, + .scan = scan, + .dev_list = std_dev_list, + .dev_clear = std_dev_clear, + .config_get = config_get, + .config_set = config_set, + .config_list = config_list, + .dev_open = std_serial_dev_open, + .dev_close = std_serial_dev_close, + .dev_acquisition_start = dev_acquisition_start, + .dev_acquisition_stop = dev_acquisition_stop, + .context = NULL, }; + SR_REGISTER_DEV_DRIVER(raspberrypi_pico_driver_info); diff --git a/src/hardware/raspberrypi-pico/protocol.c b/src/hardware/raspberrypi-pico/protocol.c index 55094ee3..a9ca4723 100644 --- a/src/hardware/raspberrypi-pico/protocol.c +++ b/src/hardware/raspberrypi-pico/protocol.c @@ -32,75 +32,88 @@ #include "libsigrok-internal.h" #include "protocol.h" -SR_PRIV int send_serial_str(struct sr_serial_dev_inst *serial, char *str){ - int len=strlen(str); - if((len>15)||(len<1)){ //limit length to catch errant strings - sr_err("ERROR:Serial string len %d invalid ",len); - return SR_ERR; - } - //100ms timeout. With USB CDC serial we can't define the timeout - //based on link rate, so just pick something large as we shouldn't normally see them - if(serial_write_blocking(serial,str,len,100) != len){ - sr_err("ERROR:Serial str write failed"); - return SR_ERR; - } - - return SR_OK; +SR_PRIV int send_serial_str(struct sr_serial_dev_inst *serial, char *str) +{ + int len = strlen(str); + if ((len > 15) || (len < 1)) { //limit length to catch errant strings + sr_err("ERROR:Serial string len %d invalid ", len); + return SR_ERR; + } + //100ms timeout. With USB CDC serial we can't define the timeout + //based on link rate, so just pick something large as we shouldn't normally see them + if (serial_write_blocking(serial, str, len, 100) != len) { + sr_err("ERROR:Serial str write failed"); + return SR_ERR; + } + + return SR_OK; +} + +SR_PRIV int send_serial_char(struct sr_serial_dev_inst *serial, char ch) +{ + char buf[1]; + buf[0] = ch; + if (serial_write_blocking(serial, buf, 1, 100) != 1) { //100ms + sr_err("ERROR:Serial char write failed"); + return SR_ERR; + } + return SR_OK; } -SR_PRIV int send_serial_char(struct sr_serial_dev_inst *serial, char ch){ - char buf[1]; - buf[0]=ch; - if(serial_write_blocking(serial,buf,1,100) != 1){ //100ms - sr_err("ERROR:Serial char write failed"); - return SR_ERR; - } - return SR_OK; -} + //Issue a command that expects a string return, return length of string -int send_serial_w_resp(struct sr_serial_dev_inst *serial, char *str,char *resp,size_t cnt){ - int num_read,i; - send_serial_str(serial,str); - //Using the serial_read_blocking function when reading a response of unknown length requires - //a long worst case timeout to always be taken. So, instead loop waiting for a first byte, and - //then a final small delay for the rest. - for(i=0;i<1000;i++){ //wait up to 1 second in ms increments - num_read = serial_read_blocking(serial, resp, cnt, 1); - if(num_read>0) break; - } - //sr_spew("rwprsp1 i %d nr %d",i,num_read); - //Since the serial port is usb CDC we can't calculate timeouts based on baud rate but - //even if the response is split between two USB transfers 10ms should be plenty. - num_read+= serial_read_blocking(serial, &(resp[num_read]), cnt-num_read, 10); - //sr_spew("rwrsp2 nr %d",num_read); - - if ((num_read < 1)||(num_read>30)) { - sr_err("ERROR:Serial_w_resp failed (%d).", num_read); - return -1; - }else{ - return num_read; - } -} +int send_serial_w_resp(struct sr_serial_dev_inst *serial, char *str, + char *resp, size_t cnt) +{ + int num_read, i; + send_serial_str(serial, str); + //Using the serial_read_blocking function when reading a response of unknown length requires + //a long worst case timeout to always be taken. So, instead loop waiting for a first byte, and + //then a final small delay for the rest. + for (i = 0; i < 1000; i++) { //wait up to 1 second in ms increments + num_read = serial_read_blocking(serial, resp, cnt, 1); + if (num_read > 0) + break; + } + //sr_spew("rwprsp1 i %d nr %d",i,num_read); + //Since the serial port is usb CDC we can't calculate timeouts based on baud rate but + //even if the response is split between two USB transfers 10ms should be plenty. + num_read += + serial_read_blocking(serial, &(resp[num_read]), cnt - num_read, + 10); + //sr_spew("rwrsp2 nr %d",num_read); + + if ((num_read < 1) || (num_read > 30)) { + sr_err("ERROR:Serial_w_resp failed (%d).", num_read); + return -1; + } else { + return num_read; + } +} + //Issue a command that expects a single char ack -SR_PRIV int send_serial_w_ack(struct sr_serial_dev_inst *serial, char *str){ - char buf[2]; - int num_read; - //In case we have left over transfer from the device, drain them - while((num_read=serial_read_blocking(serial, buf, 2, 10))){ - //sr_dbg("swack drops 2 previous bytes %d %d",buf[0],buf[1]); - } - send_serial_str(serial,str); - //1000ms timeout - num_read =serial_read_blocking(serial, buf, 1, 1000); - if ((num_read == 1)&&(buf[0]=='*')) { - return SR_OK; - }else{ - sr_err("ERROR:Serial_w_ack %s failed (%d).", str,num_read); - if(num_read){ - sr_err("ack resp char %c d %d\n\r",buf[0],buf[0]); - } - return SR_ERR; - } -} +SR_PRIV int send_serial_w_ack(struct sr_serial_dev_inst *serial, char *str) +{ + char buf[2]; + int num_read; + //In case we have left over transfer from the device, drain them + while ((num_read = serial_read_blocking(serial, buf, 2, 10))) { + //sr_dbg("swack drops 2 previous bytes %d %d",buf[0],buf[1]); + } + send_serial_str(serial, str); + //1000ms timeout + num_read = serial_read_blocking(serial, buf, 1, 1000); + if ((num_read == 1) && (buf[0] == '*')) { + return SR_OK; + } else { + sr_err("ERROR:Serial_w_ack %s failed (%d).", str, + num_read); + if (num_read) { + sr_err("ack resp char %c d %d\n\r", buf[0], + buf[0]); + } + return SR_ERR; + } +} //Process incoming data stream assuming it is optimized packing of 4 channels or less //Each byte is 4 channels of data and a 3 bit rle value, or a larger rle value, or a control signal. @@ -111,414 +124,545 @@ SR_PRIV int send_serial_w_ack(struct sr_serial_dev_inst *serial, char *str){ //Since we can get huge rle values we chop them up for processing into smaller groups //In this mode we can always consume all bytes because there are no cases where the processing of one //byte requires the one after it. -void process_D4(struct sr_dev_inst *sdi,struct dev_context *d){ - int32_t j; - uint8_t cbyte; - uint8_t cval; - uint32_t rlecnt=0; - uint32_t sampcnt=0; //number of samples received with no rles - while(d->ser_rdptr < d->bytes_avail){ - cbyte=d->buffer[(d->ser_rdptr)]; - //RLE only byte - if(cbyte>=48 && cbyte<=127){ - rlecnt+=(cbyte-47)*8; - d->byte_cnt++; - }else if(cbyte>=0x80){ //sample with possible rle - rlecnt+=(cbyte&0x70)>>4; - if(rlecnt){ - //On a value change, duplicate the previous values first. - //The maximum value of one rle is 640. - //To ensure we don't overflow the sample buffer but still send it large chunks of data - //(to make the packet sends to the session efficient) only call process group after - //a large number of samples have been seen. - //Likely we could use the max rle value of 640 but 2048 gives some extra room. - if((rlecnt+d->cbuf_wrptr)>(d->sample_buf_size-2048)){ - //process_group is sent the number of slices which is just the cbufwrptr divided by the slice size - //This modulo check should never happen as long the calculations for dig_sample_bytes etc are - //correct, but it's a good cross check for code development. - if((d->cbuf_wrptr)%(d->dig_sample_bytes)){ - sr_err("Modulo fail %d %d ",d->cbuf_wrptr,d->dig_sample_bytes); - } - process_group(sdi,d,(d->cbuf_wrptr/d->dig_sample_bytes)); - } - rle_memset(d,rlecnt); - rlecnt=0; - sampcnt=0; - } - //Finally add in the new values - cval=cbyte&0xF; - d->d_data_buf[d->cbuf_wrptr++]=cval; - //pad in all other bytes since the sessions even wants disabled channels reported - for(j=1;jdig_sample_bytes;j++){ - d->d_data_buf[d->cbuf_wrptr++]=0; - } - sampcnt++; - d->byte_cnt++; - sr_spew("Dchan4 rdptr %d wrptr %d bytein 0x%X rle %d cval 0x%X\n", - (d->ser_rdptr)-1,d->cbuf_wrptr,cbyte,rlecnt,cval); - rlecnt=0; - - d->d_last[0]=cval; - } - //Any other character ends parsing - it could be a frame error or a start of the final byte cnt - else { - if(cbyte=='$'){ - sr_info("D4 Data stream stops with cbyte %d char %c rdidx %d cnt %llu",cbyte,cbyte,d->ser_rdptr,d->byte_cnt); - d->rxstate=RX_STOPPED; - }else{ - sr_err("D4 Data stream aborts with cbyte %d char %c rdidx %d cnt %llu",cbyte,cbyte,d->ser_rdptr,d->byte_cnt); - d->rxstate=RX_ABORT; - } - break; //break from while loop - } - (d->ser_rdptr)++; - }//while rdptr < wrptr - sr_spew("D4 while done rdptr %d",d->ser_rdptr); - //If we reach the end of the serial input stream send any remaining values or rles to the session - /*this can also be skipped now the rle_memset handles cbufwrptr - if(sampcnt){ - process_group(sdi,d,sampcnt); - sampcnt=0; - } - */ - if(rlecnt){ - sr_spew("Residual D4 slice rlecnt %d",rlecnt); - rle_memset(d,rlecnt); - } - if(d->cbuf_wrptr){ - sr_spew("Residual D4 data wrptr %d",d->cbuf_wrptr); - process_group(sdi,d,d->cbuf_wrptr/d->dig_sample_bytes); - - } - -}//Process_D4 +void process_D4(struct sr_dev_inst *sdi, struct dev_context *d) +{ + uint32_t j; + uint8_t cbyte; + uint8_t cval; + uint32_t rlecnt = 0; + uint32_t sampcnt = 0; //number of samples received with no rles + while (d->ser_rdptr < d->bytes_avail) { + cbyte = d->buffer[(d->ser_rdptr)]; + //RLE only byte + if (cbyte >= 48 && cbyte <= 127) { + rlecnt += (cbyte - 47) * 8; + d->byte_cnt++; + } else if (cbyte >= 0x80) { //sample with possible rle + rlecnt += (cbyte & 0x70) >> 4; + if (rlecnt) { + //On a value change, duplicate the previous values first. + //The maximum value of one rle is 640. + //To ensure we don't overflow the sample buffer but still send it large chunks of data + //(to make the packet sends to the session efficient) only call process group after + //a large number of samples have been seen. + //Likely we could use the max rle value of 640 but 2048 gives some extra room. + if ((rlecnt + d->cbuf_wrptr) > + (d->sample_buf_size - 2048)) { + //process_group is sent the number of slices which is just the cbufwrptr divided by the slice size + //This modulo check should never happen as long the calculations for dig_sample_bytes etc are + //correct, but it's a good cross check for code development. + if ((d->cbuf_wrptr) % + (d->dig_sample_bytes)) { + sr_err + ("Modulo fail %d %d ", + d->cbuf_wrptr, + d->dig_sample_bytes); + } + process_group(sdi, d, + (d->cbuf_wrptr / + d->dig_sample_bytes)); + } + rle_memset(d, rlecnt); + rlecnt = 0; + sampcnt = 0; + } + //Finally add in the new values + cval = cbyte & 0xF; + d->d_data_buf[d->cbuf_wrptr++] = cval; + //pad in all other bytes since the sessions even wants disabled channels reported + for (j = 1; j < d->dig_sample_bytes; j++) { + d->d_data_buf[d->cbuf_wrptr++] = 0; + } + sampcnt++; + d->byte_cnt++; + sr_spew + ("Dchan4 rdptr %d wrptr %d bytein 0x%X rle %d cval 0x%X\n", + (d->ser_rdptr) - 1, d->cbuf_wrptr, cbyte, + rlecnt, cval); + rlecnt = 0; + + d->d_last[0] = cval; + } + //Any other character ends parsing - it could be a frame error or a start of the final byte cnt + else { + if (cbyte == '$') { + sr_info + ("D4 Data stream stops with cbyte %d char %c rdidx %d cnt %llu", + cbyte, cbyte, d->ser_rdptr, + d->byte_cnt); + d->rxstate = RX_STOPPED; + } else { + sr_err + ("D4 Data stream aborts with cbyte %d char %c rdidx %d cnt %llu", + cbyte, cbyte, d->ser_rdptr, + d->byte_cnt); + d->rxstate = RX_ABORT; + } + break; //break from while loop + } + (d->ser_rdptr)++; + } //while rdptr < wrptr + sr_spew("D4 while done rdptr %d", d->ser_rdptr); + //If we reach the end of the serial input stream send any remaining values or rles to the session + /*this can also be skipped now the rle_memset handles cbufwrptr + if(sampcnt){ + process_group(sdi,d,sampcnt); + sampcnt=0; + } + */ + if (rlecnt) { + sr_spew("Residual D4 slice rlecnt %d", rlecnt); + rle_memset(d, rlecnt); + } + if (d->cbuf_wrptr) { + sr_spew("Residual D4 data wrptr %d", d->cbuf_wrptr); + process_group(sdi, d, d->cbuf_wrptr / d->dig_sample_bytes); + + } + +} //Process_D4 //Process incoming data stream and forward to trigger processing with process_group //The final value of ser_rdptr indicates how many bytes were processed. //This version handles all other enabled channel configurations that Process_D4 doesn't -void process_slice(struct sr_dev_inst *sdi,struct dev_context *devc){ - int32_t i; - uint32_t tmp32; - uint8_t cbyte; - uint32_t slices_avail=0; - uint32_t cword; - uint32_t slice_bytes; //number of bytes that have legal slice values - //Only process legal data values for this mode which are >=0x80 - for(slice_bytes=1;(slice_bytesbytes_avail)&&(devc->buffer[slice_bytes-1]>=0x80);slice_bytes++); - if(slice_bytes!=devc->bytes_avail){ - cbyte=devc->buffer[slice_bytes-1]; - slice_bytes--; //Don't process the ending character - if(cbyte=='$'){ - sr_info("Data stream stops with cbyte %d char %c rdidx %d sbytes %d cnt %llu",cbyte,cbyte,devc->ser_rdptr,slice_bytes,devc->byte_cnt); - devc->rxstate=RX_STOPPED; - }else{ - sr_err("Data stream aborts with cbyte %d char %c rdidx %d sbytes %d cnt %llu",cbyte,cbyte,devc->ser_rdptr,slice_bytes,devc->byte_cnt); - devc->rxstate=RX_ABORT; - } - } - //If the wrptr is non-zero due to a residual from the previous serial transfer don't double count it towards byte_cnt - devc->byte_cnt+=slice_bytes-(devc->wrptr); - sr_spew("process slice avail %d rdptr %d sb %d byte_cnt %d",devc->bytes_avail,devc->ser_rdptr,slice_bytes,devc->byte_cnt); - //Must have a full slice - while((devc->ser_rdptr+devc->bytes_per_slice)<=slice_bytes){ - //The use of devc->cbuf_wrptr is different between analog and digital. - //For analog it targets a float sized offset for that channel's buffer - //For digital it targets a bit, so the 3 lsbs are bit offsets within a byte - slices_avail++; - cword=0; - //build up a word 7 bits at a time, using only enabled channels - for(i=0;inum_d_channels;i+=7){ - if(((devc->d_chan_mask)>>i)&0x7F){ - cword|=((devc->buffer[devc->ser_rdptr])&0x7F)<ser_rdptr)++; - } - } - //and then distribute 8 bits at a time to all possible channels - for(i=0;inum_d_channels;i+=8){ - uint32_t idx=((devc->cbuf_wrptr)*devc->dig_sample_bytes)+(i>>3); - devc->d_data_buf[idx]=cword&0xFF; - sr_spew("Dchan i %d wrptr %d idx %d char 0x%X cword 0x%X",i,devc->cbuf_wrptr,idx,devc->d_data_buf[idx],cword); - cword>>=8; - } - //Each analog value is a 7 bit value - for(i=0;inum_a_channels;i++){ - if((devc->a_chan_mask>>i)&1){ - //a_size is depracted and must always be 1B - tmp32=devc->buffer[devc->ser_rdptr]-0x80; - devc->a_data_bufs[i][devc->cbuf_wrptr]=((float)tmp32 * devc->a_scale[i])+devc->a_offset[i]; - devc->a_last[i]=devc->a_data_bufs[i][devc->cbuf_wrptr]; - sr_spew("AChan %d t32 %d value %f wrptr %d rdptr %d sc %d off %d",i,tmp32,devc->a_data_bufs[i][devc->cbuf_wrptr],devc->cbuf_wrptr,devc->ser_rdptr,devc->a_scale[i],devc->a_offset[i]); - devc->ser_rdptr++; - }//if channel enabled - }//for num_a_channels - devc->cbuf_wrptr++; - }//While another slice available - if(slices_avail){ - process_group(sdi,devc,slices_avail); - } +void process_slice(struct sr_dev_inst *sdi, struct dev_context *devc) +{ + int32_t i; + uint32_t tmp32; + uint8_t cbyte; + uint32_t slices_avail = 0; + uint32_t cword; + uint32_t slice_bytes; //number of bytes that have legal slice values + //Only process legal data values for this mode which are >=0x80 + for (slice_bytes = 1; (slice_bytes < devc->bytes_avail) + && (devc->buffer[slice_bytes - 1] >= 0x80); slice_bytes++); + if (slice_bytes != devc->bytes_avail) { + cbyte = devc->buffer[slice_bytes - 1]; + slice_bytes--; //Don't process the ending character + if (cbyte == '$') { + sr_info + ("Data stream stops with cbyte %d char %c rdidx %d sbytes %d cnt %llu", + cbyte, cbyte, devc->ser_rdptr, slice_bytes, + devc->byte_cnt); + devc->rxstate = RX_STOPPED; + } else { + sr_err + ("Data stream aborts with cbyte %d char %c rdidx %d sbytes %d cnt %llu", + cbyte, cbyte, devc->ser_rdptr, slice_bytes, + devc->byte_cnt); + devc->rxstate = RX_ABORT; + } + } + //If the wrptr is non-zero due to a residual from the previous serial transfer don't double count it towards byte_cnt + devc->byte_cnt += slice_bytes - (devc->wrptr); + sr_spew("process slice avail %d rdptr %d sb %d byte_cnt %lld", + devc->bytes_avail, devc->ser_rdptr, slice_bytes, + devc->byte_cnt); + //Must have a full slice + while ((devc->ser_rdptr + devc->bytes_per_slice) <= slice_bytes) { + //The use of devc->cbuf_wrptr is different between analog and digital. + //For analog it targets a float sized offset for that channel's buffer + //For digital it targets a bit, so the 3 lsbs are bit offsets within a byte + slices_avail++; + cword = 0; + //build up a word 7 bits at a time, using only enabled channels + for (i = 0; i < devc->num_d_channels; i += 7) { + if (((devc->d_chan_mask) >> i) & 0x7F) { + cword |= + ((devc->buffer[devc->ser_rdptr]) & + 0x7F) << i; + (devc->ser_rdptr)++; + } + } + //and then distribute 8 bits at a time to all possible channels + for (i = 0; i < devc->num_d_channels; i += 8) { + uint32_t idx = + ((devc->cbuf_wrptr) * devc->dig_sample_bytes) + + (i >> 3); + devc->d_data_buf[idx] = cword & 0xFF; + sr_spew + ("Dchan i %d wrptr %d idx %d char 0x%X cword 0x%X", + i, devc->cbuf_wrptr, idx, + devc->d_data_buf[idx], cword); + cword >>= 8; + } + //Each analog value is a 7 bit value + for (i = 0; i < devc->num_a_channels; i++) { + if ((devc->a_chan_mask >> i) & 1) { + //a_size is depracted and must always be 1B + tmp32 = + devc->buffer[devc->ser_rdptr] - 0x80; + devc->a_data_bufs[i][devc->cbuf_wrptr] = + ((float) tmp32 * devc->a_scale[i]) + + devc->a_offset[i]; + devc->a_last[i] = + devc->a_data_bufs[i][devc->cbuf_wrptr]; + sr_spew + ("AChan %d t32 %d value %f wrptr %d rdptr %d sc %f off %f", + i, tmp32, + devc-> + a_data_bufs[i][devc->cbuf_wrptr], + devc->cbuf_wrptr, devc->ser_rdptr, + devc->a_scale[i], devc->a_offset[i]); + devc->ser_rdptr++; + } //if channel enabled + } //for num_a_channels + devc->cbuf_wrptr++; + } //While another slice available + if (slices_avail) { + process_group(sdi, devc, slices_avail); + } } + //Send the processed analog values to the session -int send_analog(struct sr_dev_inst *sdi,struct dev_context *devc,uint32_t num_samples, uint32_t offset){ - struct sr_datafeed_packet packet; - struct sr_datafeed_analog analog; - struct sr_analog_encoding encoding; - struct sr_analog_meaning meaning; - struct sr_analog_spec spec; - struct sr_channel *ch; - uint32_t i; - float *fptr; - - sr_analog_init(&analog, &encoding, &meaning, &spec, ANALOG_DIGITS); - for(i=0;inum_a_channels;i++){ - if((devc->a_chan_mask>>i)&1){ - ch=devc->analog_groups[i]->channels->data; - analog.meaning->channels = g_slist_append(NULL, ch); - analog.num_samples = num_samples; - analog.data = (devc->a_data_bufs[i]) + offset; - fptr=analog.data; - sr_spew("send analog num %d offset %d first %f 2 %f",num_samples,offset,*(devc->a_data_bufs[i]),*fptr); - analog.meaning->mq = SR_MQ_VOLTAGE; - analog.meaning->unit = SR_UNIT_VOLT; - analog.meaning->mqflags = 0; - packet.type = SR_DF_ANALOG; - packet.payload = &analog; - sr_session_send(sdi, &packet); - g_slist_free(analog.meaning->channels); - } //if enabled - }//for channels - return 0; +int send_analog(struct sr_dev_inst *sdi, struct dev_context *devc, + uint32_t num_samples, uint32_t offset) +{ + struct sr_datafeed_packet packet; + struct sr_datafeed_analog analog; + struct sr_analog_encoding encoding; + struct sr_analog_meaning meaning; + struct sr_analog_spec spec; + struct sr_channel *ch; + uint32_t i; + float *fptr; + + sr_analog_init(&analog, &encoding, &meaning, &spec, ANALOG_DIGITS); + for (i = 0; i < devc->num_a_channels; i++) { + if ((devc->a_chan_mask >> i) & 1) { + ch = devc->analog_groups[i]->channels->data; + analog.meaning->channels = + g_slist_append(NULL, ch); + analog.num_samples = num_samples; + analog.data = (devc->a_data_bufs[i]) + offset; + fptr = analog.data; + sr_spew + ("send analog num %d offset %d first %f 2 %f", + num_samples, offset, *(devc->a_data_bufs[i]), + *fptr); + analog.meaning->mq = SR_MQ_VOLTAGE; + analog.meaning->unit = SR_UNIT_VOLT; + analog.meaning->mqflags = 0; + packet.type = SR_DF_ANALOG; + packet.payload = &analog; + sr_session_send(sdi, &packet); + g_slist_free(analog.meaning->channels); + } //if enabled + } //for channels + return 0; } + //Send the ring buffer of pre-trigger analog samples. // The entire buffer is sent (as long as it filled once), but need send two payloads split at the // the writeptr -int send_analog_ring(struct sr_dev_inst *sdi,struct dev_context *devc,uint32_t num_samples){ - struct sr_datafeed_packet packet; - struct sr_datafeed_analog analog; - struct sr_analog_encoding encoding; - struct sr_analog_meaning meaning; - struct sr_analog_spec spec; - struct sr_channel *ch; - int i; - uint32_t num_pre,start_pre; - uint32_t num_post,start_post; - num_pre=(num_samples>=devc->pretrig_wr_ptr) ? devc->pretrig_wr_ptr : num_samples; - start_pre=devc->pretrig_wr_ptr-num_pre; - num_post=num_samples-num_pre; - start_post=devc->pretrig_entries-num_post; - sr_spew("send_analog ring wrptr %u ns %d npre %u spre %u npost %u spost %u",devc->pretrig_wr_ptr,num_samples,num_pre,start_pre,num_post,start_post); - float *fptr; - sr_analog_init(&analog, &encoding, &meaning, &spec, ANALOG_DIGITS); - for(i=0;inum_a_channels;i++){ - if((devc->a_chan_mask>>i)&1){ - ch=devc->analog_groups[i]->channels->data; - analog.meaning->channels = g_slist_append(NULL, ch); - analog.meaning->mq = SR_MQ_VOLTAGE; - analog.meaning->unit = SR_UNIT_VOLT; - analog.meaning->mqflags = 0; - packet.type = SR_DF_ANALOG; - packet.payload = &analog; - //First send what is after the write pointer because it is oldest - if(num_post){ - analog.num_samples = num_post; - analog.data = (devc->a_pretrig_bufs[i]) + start_post; - //sr_spew("ring buf %d starts at %p",i,(void *) devc->a_pretrig_bufs[i]); - //sr_spew("analog data %d starts at %p",i,(void *) analog.data); - //sr_spew("Sending A%d ring buffer oldest ",i); - for(uint32_t j=0;ja_pretrig_bufs[i])+start_pre; - sr_dbg("Sending A%d ring buffer newest ",i); - for(uint32_t j=0;jchannels); - sr_dbg("Sending A%d ring buffer done ",i); - } //if enabled - }//for channels - return 0; +int send_analog_ring(struct sr_dev_inst *sdi, struct dev_context *devc, + uint32_t num_samples) +{ + struct sr_datafeed_packet packet; + struct sr_datafeed_analog analog; + struct sr_analog_encoding encoding; + struct sr_analog_meaning meaning; + struct sr_analog_spec spec; + struct sr_channel *ch; + int i; + uint32_t num_pre, start_pre; + uint32_t num_post, start_post; + num_pre = + (num_samples >= + devc->pretrig_wr_ptr) ? devc->pretrig_wr_ptr : num_samples; + start_pre = devc->pretrig_wr_ptr - num_pre; + num_post = num_samples - num_pre; + start_post = devc->pretrig_entries - num_post; + sr_spew + ("send_analog ring wrptr %u ns %d npre %u spre %u npost %u spost %u", + devc->pretrig_wr_ptr, num_samples, num_pre, start_pre, + num_post, start_post); + float *fptr; + sr_analog_init(&analog, &encoding, &meaning, &spec, ANALOG_DIGITS); + for (i = 0; i < devc->num_a_channels; i++) { + if ((devc->a_chan_mask >> i) & 1) { + ch = devc->analog_groups[i]->channels->data; + analog.meaning->channels = + g_slist_append(NULL, ch); + analog.meaning->mq = SR_MQ_VOLTAGE; + analog.meaning->unit = SR_UNIT_VOLT; + analog.meaning->mqflags = 0; + packet.type = SR_DF_ANALOG; + packet.payload = &analog; + //First send what is after the write pointer because it is oldest + if (num_post) { + analog.num_samples = num_post; + analog.data = + (devc->a_pretrig_bufs[i]) + start_post; + //sr_spew("ring buf %d starts at %p",i,(void *) devc->a_pretrig_bufs[i]); + //sr_spew("analog data %d starts at %p",i,(void *) analog.data); + //sr_spew("Sending A%d ring buffer oldest ",i); + for (uint32_t j = 0; + j < analog.num_samples; j++) { + fptr = + analog.data + + (j * sizeof(float)); + //sr_spew("RNGDCT%d j %d %f %p",i,j,*fptr,(void *)fptr); + } + sr_session_send(sdi, &packet); + } + if (num_pre) { + analog.num_samples = num_pre; + analog.data = + (devc->a_pretrig_bufs[i]) + start_pre; + sr_dbg("Sending A%d ring buffer newest ", + i); + for (uint32_t j = 0; + j < analog.num_samples; j++) { + fptr = + analog.data + + (j * sizeof(float)); + sr_spew("RNGDCW%d j %d %f %p", i, + j, *fptr, (void *) fptr); + } + sr_session_send(sdi, &packet); + } + g_slist_free(analog.meaning->channels); + sr_dbg("Sending A%d ring buffer done ", i); + } //if enabled + } //for channels + return 0; } //Given a chunk of slices forward to trigger check or session as appropriate and update state //these could be real slices or those generated by rles -int process_group(struct sr_dev_inst *sdi,struct dev_context *devc,uint32_t num_slices){ - int trigger_offset; - int pre_trigger_samples; - //These are samples sent to session and are less than num_slices if we reach limit_samples - size_t num_samples; - struct sr_datafeed_logic logic; - struct sr_datafeed_packet packet; - int i; - size_t cbuf_wrptr_cpy; - cbuf_wrptr_cpy=devc->cbuf_wrptr; - //regardless of whether we forward samples on or not (because we aren't triggered), always reset the - //pointer into the device data buffers - devc->cbuf_wrptr=0; - if(devc->trigger_fired){ //send directly to session - if (devc->limit_samples && - num_slices > devc->limit_samples - devc->sent_samples){ - num_samples = devc->limit_samples - devc->sent_samples; - }else{ - num_samples=num_slices; - } - if(num_samples>0) { - sr_spew("Process_group sending %d post trig samples dsb %d",num_samples,devc->dig_sample_bytes); - //for(int z=0;(zd_data_buf[z]); - //} - if(devc->num_d_channels){ - packet.type = SR_DF_LOGIC; - packet.payload = &logic; - //Size the number of bytes required to fit all of the channels - logic.unitsize = devc->dig_sample_bytes; - //The total length of the array sent - logic.length=num_samples*logic.unitsize; - logic.data = devc->d_data_buf; - sr_session_send(sdi, &packet); - } - send_analog(sdi,devc,num_samples,0); - }//num_sample>0 - devc->sent_samples+=num_samples; - return 0; - } //trigger_fired - else{ - size_t num_ring_samples; - size_t sptr; - size_t eptr; - size_t numtail; - size_t numwrap; - size_t srcptr; - //sr_spew("Process_group check %d pre trig samples",num_slices); - //The trigger_offset is -1 if no trigger is found, but if a trigger is found - //then trigger_offset is the offset into the data buffer sent to it. - //The pre_trigger_samples is the total number of samples before the trigger, but limited to - //the size of the ring buffer set by the capture_ratio. So the pre_trigger_samples can include both the new samples - //and the ring buffer, but trigger_offset is only in relation to the new samples - trigger_offset = soft_trigger_logic_check(devc->stl, - devc->d_data_buf, num_slices * devc->dig_sample_bytes, &pre_trigger_samples); - //A trigger offset >=0 indicate a trigger was seen. The stl will isue the trigger to the session - //and will forward all pre trigger logic samples, but we must send any post trigger logic - //and all pre and post trigger analog signals - // sr_dbg("trggr_off %d",trigger_offset); - // sr_dbg("pre_samp %d",pre_trigger_samples); - if (trigger_offset > -1) { - devc->trigger_fired = TRUE; - devc->sent_samples += pre_trigger_samples; - packet.type = SR_DF_LOGIC; - packet.payload = &logic; - num_samples = num_slices - trigger_offset; +int process_group(struct sr_dev_inst *sdi, struct dev_context *devc, + uint32_t num_slices) +{ + int trigger_offset; + int pre_trigger_samples; + //These are samples sent to session and are less than num_slices if we reach limit_samples + size_t num_samples; + struct sr_datafeed_logic logic; + struct sr_datafeed_packet packet; + int i; + size_t cbuf_wrptr_cpy; + cbuf_wrptr_cpy = devc->cbuf_wrptr; + //regardless of whether we forward samples on or not (because we aren't triggered), always reset the + //pointer into the device data buffers + devc->cbuf_wrptr = 0; + if (devc->trigger_fired) { //send directly to session + if (devc->limit_samples && + num_slices > + devc->limit_samples - devc->sent_samples) { + num_samples = + devc->limit_samples - devc->sent_samples; + } else { + num_samples = num_slices; + } + if (num_samples > 0) { + sr_spew + ("Process_group sending %d post trig samples dsb %d", + num_samples, devc->dig_sample_bytes); + //for(int z=0;(zd_data_buf[z]); + //} + if (devc->num_d_channels) { + packet.type = SR_DF_LOGIC; + packet.payload = &logic; + //Size the number of bytes required to fit all of the channels + logic.unitsize = devc->dig_sample_bytes; + //The total length of the array sent + logic.length = + num_samples * logic.unitsize; + logic.data = devc->d_data_buf; + sr_session_send(sdi, &packet); + } + send_analog(sdi, devc, num_samples, 0); + } //num_sample>0 + devc->sent_samples += num_samples; + return 0; + } //trigger_fired + else { + size_t num_ring_samples; + size_t sptr; + size_t eptr; + size_t numtail; + size_t numwrap; + size_t srcptr; + //sr_spew("Process_group check %d pre trig samples",num_slices); + //The trigger_offset is -1 if no trigger is found, but if a trigger is found + //then trigger_offset is the offset into the data buffer sent to it. + //The pre_trigger_samples is the total number of samples before the trigger, but limited to + //the size of the ring buffer set by the capture_ratio. So the pre_trigger_samples can include both the new samples + //and the ring buffer, but trigger_offset is only in relation to the new samples + trigger_offset = soft_trigger_logic_check(devc->stl, + devc->d_data_buf, + num_slices * + devc->dig_sample_bytes, + &pre_trigger_samples); + //A trigger offset >=0 indicate a trigger was seen. The stl will isue the trigger to the session + //and will forward all pre trigger logic samples, but we must send any post trigger logic + //and all pre and post trigger analog signals + // sr_dbg("trggr_off %d",trigger_offset); + // sr_dbg("pre_samp %d",pre_trigger_samples); + if (trigger_offset > -1) { + devc->trigger_fired = TRUE; + devc->sent_samples += pre_trigger_samples; + packet.type = SR_DF_LOGIC; + packet.payload = &logic; + num_samples = num_slices - trigger_offset; //Since we are in continuous mode for SW triggers it is possible to get more samples than limit_samples, so //once the trigger fires make sure we don't get beyond limit samples. At this point sent_samples should //be equal to pre_trigger_samples (just added above) because without being triggered we'd never increment //sent_samples. //This number is the number of post trigger logic samples to send to the session, the number of floats //is larger because of the analog ring buffer we track. - if (devc->limit_samples && - num_samples > devc->limit_samples - devc->sent_samples) - num_samples = devc->limit_samples - devc->sent_samples; - //The soft trigger logic issues the trigger and sends packest for all logic data that was pretrigger - //so only send what is left - if(num_samples>0){ - sr_dbg("Sending post trigger logical remainder of %d",num_samples); - logic.length = num_samples * devc->dig_sample_bytes; - logic.unitsize = devc->dig_sample_bytes; - logic.data = devc->d_data_buf + (trigger_offset * devc->dig_sample_bytes); - devc->sent_samples += num_samples; - sr_session_send(sdi, &packet); - } - size_t new_start,new_end,new_samples,ring_samples; - //Figure out the analog data to send. - //We might need to send: - //-some or all of incoming data - //-all of incoming data and some of ring buffer - //-all of incoming data and all of ring buffer (and still might be short) - //We don't need to compare to limit_samples because pretrig_entries can never be more than limit_samples - //trigger offset indicatese where in the new samples the trigger was, but we need to go back pretrig_entries before it - new_start=(trigger_offset>(int)devc->pretrig_entries) ? trigger_offset-devc->pretrig_entries : 0; - //Note that we might not have gotten all the pre triggerstore data we were looking for. In such a case the sw trigger - //logic seems to fill up to the limit_samples and thus the ratio is off, but we get the full number of samples - //The number of entries in the ring buffer is pre_trigger_samples-trigger_offset so subtract that from limit samples - //as a threshold - new_end=MIN(num_slices-1,devc->limit_samples-(pre_trigger_samples-trigger_offset)-1); - //This includes pre and post trigger storage. - new_samples=new_end-new_start+1; - //pre_trigger_samples can never be greater than trigger_offset by more than the ring buffer depth (pretrig entries) - ring_samples=(pre_trigger_samples>trigger_offset) ? pre_trigger_samples-trigger_offset : 0; - sr_spew("SW trigger float info newstart %zu new_end %zu new_samp %zu ring_samp %zu",new_start,new_end,new_samples,ring_samples); - if(ring_samples>0){ - send_analog_ring(sdi,devc,ring_samples); - } - if(new_samples){ - send_analog(sdi,devc,new_samples,new_start); - } - - }//if trigger_offset - else { //We didn't trigger but need to copy to ring buffer - if((devc->a_chan_mask)&&(devc->pretrig_entries)){ - //The incoming data buffer could be much larger than the ring buffer, so never copy more than - //the size of the ring buffer - num_ring_samples=num_slices > devc->pretrig_entries ? devc->pretrig_entries : num_slices; - sptr=devc->pretrig_wr_ptr; //starting pointer to copy to - //endptr can't go past the end - eptr=(sptr+num_ring_samples)>=devc->pretrig_entries ? devc->pretrig_entries-1 : sptr+num_ring_samples-1; - numtail=(eptr-sptr)+1; //number of samples to copy to the tail of ring buffer without wrapping - numwrap=(num_ring_samples>numtail) ? num_ring_samples-numtail:0; - //cbuf_wrptr points to where the next write should go, not theactual write data - srcptr=cbuf_wrptr_cpy-num_ring_samples; - sr_spew("RNG num %zu sptr %zu eptr %zu ",num_ring_samples,sptr,eptr); - //sr_spew("RNG srcptr %zu nt %zu nw %zu",srcptr,numtail,numwrap); - for(i=0;inum_a_channels;i++){ - if((devc->a_chan_mask>>i)&1){ - //copy tail - for(uint32_t j=0;ja_pretrig_bufs[i][sptr+j]=devc->a_data_bufs[i][srcptr+j]; - //sr_spew("RNGCpyT C%d src %zu dest %zu",i,srcptr+j,sptr+j); - }//for j - } //if chan_mask - }//for channels - //Copy wrap - srcptr+=numtail; - for(i=0;inum_a_channels;i++){ - if((devc->a_chan_mask>>i)&1){ - for(uint32_t j=0;ja_pretrig_bufs[i][j]=devc->a_data_bufs[i][srcptr+j]; - //sr_spew("RNGCpyW C%d src %zu dest %zu",i,srcptr+j,j); - }//for j - }//if chan_mask - }//for channels - devc->pretrig_wr_ptr=(numwrap) ? numwrap : (eptr+1)%devc->pretrig_entries; - //sr_dbg("RNG pwrptr new %u",devc->pretrig_wr_ptr); - }//if any analog channel enabled and pretrig_entries - }//else (trigger not detected) - }//trigger not set on function entry - return 0; -}//process_group + if (devc->limit_samples && + num_samples > + devc->limit_samples - devc->sent_samples) + num_samples = + devc->limit_samples - + devc->sent_samples; + //The soft trigger logic issues the trigger and sends packest for all logic data that was pretrigger + //so only send what is left + if (num_samples > 0) { + sr_dbg + ("Sending post trigger logical remainder of %d", + num_samples); + logic.length = + num_samples * devc->dig_sample_bytes; + logic.unitsize = devc->dig_sample_bytes; + logic.data = + devc->d_data_buf + + (trigger_offset * + devc->dig_sample_bytes); + devc->sent_samples += num_samples; + sr_session_send(sdi, &packet); + } + size_t new_start, new_end, new_samples, + ring_samples; + //Figure out the analog data to send. + //We might need to send: + //-some or all of incoming data + //-all of incoming data and some of ring buffer + //-all of incoming data and all of ring buffer (and still might be short) + //We don't need to compare to limit_samples because pretrig_entries can never be more than limit_samples + //trigger offset indicatese where in the new samples the trigger was, but we need to go back pretrig_entries before it + new_start = + (trigger_offset > + (int) devc->pretrig_entries) ? trigger_offset + - devc->pretrig_entries : 0; + //Note that we might not have gotten all the pre triggerstore data we were looking for. In such a case the sw trigger + //logic seems to fill up to the limit_samples and thus the ratio is off, but we get the full number of samples + //The number of entries in the ring buffer is pre_trigger_samples-trigger_offset so subtract that from limit samples + //as a threshold + new_end = + MIN(num_slices - 1, + devc->limit_samples - + (pre_trigger_samples - trigger_offset) - + 1); + //This includes pre and post trigger storage. + new_samples = new_end - new_start + 1; + //pre_trigger_samples can never be greater than trigger_offset by more than the ring buffer depth (pretrig entries) + ring_samples = + (pre_trigger_samples > + trigger_offset) ? pre_trigger_samples - + trigger_offset : 0; + sr_spew + ("SW trigger float info newstart %zu new_end %zu new_samp %zu ring_samp %zu", + new_start, new_end, new_samples, + ring_samples); + if (ring_samples > 0) { + send_analog_ring(sdi, devc, ring_samples); + } + if (new_samples) { + send_analog(sdi, devc, new_samples, + new_start); + } + + } //if trigger_offset + else { //We didn't trigger but need to copy to ring buffer + if ((devc->a_chan_mask) && (devc->pretrig_entries)) { + //The incoming data buffer could be much larger than the ring buffer, so never copy more than + //the size of the ring buffer + num_ring_samples = + num_slices > + devc-> + pretrig_entries ? devc->pretrig_entries + : num_slices; + sptr = devc->pretrig_wr_ptr; //starting pointer to copy to + //endptr can't go past the end + eptr = + (sptr + num_ring_samples) >= + devc-> + pretrig_entries ? devc->pretrig_entries + - 1 : sptr + num_ring_samples - 1; + numtail = (eptr - sptr) + 1; //number of samples to copy to the tail of ring buffer without wrapping + numwrap = + (num_ring_samples > + numtail) ? num_ring_samples - + numtail : 0; + //cbuf_wrptr points to where the next write should go, not theactual write data + srcptr = cbuf_wrptr_cpy - num_ring_samples; + sr_spew("RNG num %zu sptr %zu eptr %zu ", + num_ring_samples, sptr, eptr); + //sr_spew("RNG srcptr %zu nt %zu nw %zu",srcptr,numtail,numwrap); + for (i = 0; i < devc->num_a_channels; i++) { + if ((devc->a_chan_mask >> i) & 1) { + //copy tail + for (uint32_t j = 0; + j < numtail; j++) { + devc->a_pretrig_bufs + [i][sptr + j] = + devc->a_data_bufs + [i] + [srcptr + j]; + //sr_spew("RNGCpyT C%d src %zu dest %zu",i,srcptr+j,sptr+j); + } //for j + } //if chan_mask + } //for channels + //Copy wrap + srcptr += numtail; + for (i = 0; i < devc->num_a_channels; i++) { + if ((devc->a_chan_mask >> i) & 1) { + for (uint32_t j = 0; + j < numwrap; j++) { + devc->a_pretrig_bufs + [i][j] = + devc->a_data_bufs + [i] + [srcptr + j]; + //sr_spew("RNGCpyW C%d src %zu dest %zu",i,srcptr+j,j); + } //for j + } //if chan_mask + } //for channels + devc->pretrig_wr_ptr = + (numwrap) ? numwrap : (eptr + + 1) % + devc->pretrig_entries; + //sr_dbg("RNG pwrptr new %u",devc->pretrig_wr_ptr); + } //if any analog channel enabled and pretrig_entries + } //else (trigger not detected) + } //trigger not set on function entry + return 0; +} //process_group //Duplicate previous sample values //This function relies on the caller to ensure d_data_buf has samples to handle the full value of the rle -void rle_memset(struct dev_context *devc,uint32_t num_slices){ - uint32_t j,k; - sr_spew("rle_memset val 0x%X,slices %d dsb %ld\n",devc->d_last[0],num_slices,devc->dig_sample_bytes); - //Even if a channel is disabled, PV expects the same location and size for the enabled - // channels as if the channel were enabled. - for(j=0;jdig_sample_bytes;k++){ - devc->d_data_buf[devc->cbuf_wrptr++]=devc->d_last[k]; - //sr_spew("k %d j %d v 0x%X",k,j,devc->d_data_buf[(devc->cbuf_wrptr)-1]); - } - } +void rle_memset(struct dev_context *devc, uint32_t num_slices) +{ + uint32_t j, k; + sr_spew("rle_memset val 0x%X,slices %d dsb %d\n", devc->d_last[0], + num_slices, devc->dig_sample_bytes); + //Even if a channel is disabled, PV expects the same location and size for the enabled + // channels as if the channel were enabled. + for (j = 0; j < num_slices; j++) { + for (k = 0; k < devc->dig_sample_bytes; k++) { + devc->d_data_buf[devc->cbuf_wrptr++] = + devc->d_last[k]; + //sr_spew("k %d j %d v 0x%X",k,j,devc->d_data_buf[(devc->cbuf_wrptr)-1]); + } + } } //This callback function is mapped from api.c with serial_source_add and is created after a capture @@ -526,187 +670,213 @@ void rle_memset(struct dev_context *devc,uint32_t num_slices){ //and forwarding packets SR_PRIV int raspberrypi_pico_receive(int fd, int revents, void *cb_data) { - struct sr_dev_inst *sdi; - struct dev_context *devc; - struct sr_serial_dev_inst *serial; - uint32_t i; - int len; - uint32_t bytes_rem; - uint32_t residual_bytes; - (void)fd; - - if (!(sdi = cb_data)) - return TRUE; - - if (!(devc = sdi->priv)) - return TRUE; - if(devc->rxstate!=RX_ACTIVE){ - //This condition is normal operation and expected to happen - //but printed as information - sr_dbg("Reached non active state in receive %d",devc->rxstate); - //don't return - we may be waiting for a final bytecnt - //return TRUE; - } - if(devc->rxstate==RX_IDLE){ - //This is the normal end condition where we do one more receive - //to make sure we get the full byte_cnt - sr_dbg("Reached idle state in receive %d",devc->rxstate); - return FALSE; - } - - serial = sdi->conn; - //return true if it is some kind of event we don't handle - if (!(revents == G_IO_IN || revents == 0)) - return TRUE; - //Fill the buffer, note the end may have partial slices - bytes_rem=devc->serial_buffer_size - devc->wrptr; - //Read one byte less so that we can null it and print as a string - //Do a small 10ms timeout, if we get nothing, we'll always come back again - len=serial_read_blocking(serial, &(devc->buffer[devc->wrptr]), bytes_rem-1,10); - sr_spew("Entry wrptr %u bytes_rem %u len %d",devc->wrptr,bytes_rem,len); - - if(len>0){ - devc->buffer[devc->wrptr+len]=0; - //Add the "#" so that spaces are clearly seen - sr_dbg("rx string %s#",devc->buffer); - //This is not guaranteed to be a dataloss condition, but definitely indicates we are - //processing data right at the incoming rate. - //With the addition of the byte_cnt sent at the end we will detect any dataloss conditions - //and thus this is disabled - //if(len>=(int)bytes_rem-8){ - // sr_err("ERROR: Serial buffer near or at max depth, data from device may have been lost"); - //} - devc->bytes_avail=(devc->wrptr+len); - sr_spew("rx len %d bytes_avail %ul sent_samples %ul wrptr %u",len,devc->bytes_avail,devc->sent_samples,devc->wrptr); - //sr_err("rx len %d ",len); - }else if (len==0){ - return TRUE; - }else { - sr_err("ERROR:Negative serial read code %d",len); - sdi->driver->dev_acquisition_stop(sdi); - return FALSE; - }//len>0 - //This can be used as a bit bucket to drop all samples to see how host processing time effects - //the devices ability to send data. Obviously no data will be forwarded to the session so it will hang - // return TRUE; - - //Process the serial read data - devc->ser_rdptr=0; - if(devc->rxstate==RX_ACTIVE){ - if((devc->a_chan_mask==0)&&((devc->d_chan_mask&0xFFFFFFF0)==0)){ - process_D4(sdi,devc); - }else{ - process_slice(sdi,devc); - } - } - //process_slice/process_D4 increment ser_rdptr as bytes of the serial buffer are used - //But they may not use all of it, and thus the residual unused bytes are shifted to the start of the buffer - //for the next call. - residual_bytes=devc->bytes_avail - devc->ser_rdptr; - //sr_spew("Residuals resid %d avail %d rdptr %d wrptr %d\n",residual_bytes,devc->bytes_avail,devc->ser_rdptr,devc->wrptr); - if(residual_bytes){ - for(i=0;ibuffer[i]=devc->buffer[i+devc->ser_rdptr]; - } - devc->ser_rdptr=0; - devc->wrptr=residual_bytes; - sr_spew("Residual shift rdptr %u wrptr %u",devc->ser_rdptr,devc->wrptr); - }else{ - //If there are no residuals shifted then zero the wrptr since all data is used - devc->wrptr=0; - } - //ABORT ends immediately - if(devc->rxstate==RX_ABORT){ - sr_err("Ending receive on abort"); - sdi->driver->dev_acquisition_stop(sdi); - return FALSE;// - } - //if stopped look for final '+' indicating the full byte_cnt is received - if(devc->rxstate==RX_STOPPED){ - sr_dbg("Stopped, checking byte_cnt"); - if(devc->buffer[0]!='$'){ - //If this happens it means that we got a set of data that was not processed as - //whole groups of slice bytes. So either we lost data or are not parsing it correctly. - sr_err("ERROR: Stop marker should be byte zero"); - devc->rxstate=RX_ABORT; - sdi->driver->dev_acquisition_stop(sdi); - return FALSE; - } - for(i=1;iwrptr;i++){ - if(devc->buffer[i]=='+'){ - devc->buffer[i]=0; - uint64_t rxbytecnt; - rxbytecnt=atol(&(devc->buffer[1])); - sr_dbg("Byte_cnt check device cnt %llu host cnt %llu",rxbytecnt,devc->byte_cnt); - if(rxbytecnt!=devc->byte_cnt){ - sr_err("ERROR: received %llu and counted %llu bytecnts don't match, data may be lost",rxbytecnt,devc->byte_cnt); - } - //Since we got the bytecnt we know the device is done sending data - devc->rxstate=RX_IDLE; - //We must always call acquisition_stop on all completed runs - sdi->driver->dev_acquisition_stop(sdi); - return TRUE; - } - } - //It's possible we need one more serial transfer to get the byte_cnt, so print that here - sr_dbg("Haven't seen byte_cnt + yet"); - }//RX_STOPPED - //If at the sample limit, send a "+" in case we are in continuous mode and need - //to stop the device. Not that even in non continous mode there might be cases where get an extra - //sample or two... - - if((devc->sent_samples>=devc->limit_samples)&&(devc->rxstate==RX_ACTIVE)){ - sr_dbg("Ending: sent %u of limit %llu samples byte_cnt %llu", - devc->sent_samples,devc->limit_samples,devc->byte_cnt); - send_serial_char(serial,'+'); - - } - sr_spew("Receive function done: sent %u limit %llu wrptr %u len %d",devc->sent_samples,devc->limit_samples,devc->wrptr,len); - return TRUE; -}//raspberrypi_pico_receive + struct sr_dev_inst *sdi; + struct dev_context *devc; + struct sr_serial_dev_inst *serial; + uint32_t i; + int len; + uint32_t bytes_rem; + uint32_t residual_bytes; + (void) fd; + + if (!(sdi = cb_data)) + return TRUE; + + if (!(devc = sdi->priv)) + return TRUE; + if (devc->rxstate != RX_ACTIVE) { + //This condition is normal operation and expected to happen + //but printed as information + sr_dbg("Reached non active state in receive %d", + devc->rxstate); + //don't return - we may be waiting for a final bytecnt + //return TRUE; + } + if (devc->rxstate == RX_IDLE) { + //This is the normal end condition where we do one more receive + //to make sure we get the full byte_cnt + sr_dbg("Reached idle state in receive %d", devc->rxstate); + return FALSE; + } + + serial = sdi->conn; + //return true if it is some kind of event we don't handle + if (!(revents == G_IO_IN || revents == 0)) + return TRUE; + //Fill the buffer, note the end may have partial slices + bytes_rem = devc->serial_buffer_size - devc->wrptr; + //Read one byte less so that we can null it and print as a string + //Do a small 10ms timeout, if we get nothing, we'll always come back again + len = + serial_read_blocking(serial, &(devc->buffer[devc->wrptr]), + bytes_rem - 1, 10); + sr_spew("Entry wrptr %u bytes_rem %u len %d", devc->wrptr, + bytes_rem, len); + + if (len > 0) { + devc->buffer[devc->wrptr + len] = 0; + //Add the "#" so that spaces are clearly seen + sr_dbg("rx string %s#", devc->buffer); + //This is not guaranteed to be a dataloss condition, but definitely indicates we are + //processing data right at the incoming rate. + //With the addition of the byte_cnt sent at the end we will detect any dataloss conditions + //and thus this is disabled + //if(len>=(int)bytes_rem-8){ + // sr_err("ERROR: Serial buffer near or at max depth, data from device may have been lost"); + //} + devc->bytes_avail = (devc->wrptr + len); + sr_spew + ("rx len %d bytes_avail %ul sent_samples %ul wrptr %u", + len, devc->bytes_avail, devc->sent_samples, + devc->wrptr); + //sr_err("rx len %d ",len); + } else if (len == 0) { + return TRUE; + } else { + sr_err("ERROR:Negative serial read code %d", len); + sdi->driver->dev_acquisition_stop(sdi); + return FALSE; + } //len>0 + //This can be used as a bit bucket to drop all samples to see how host processing time effects + //the devices ability to send data. Obviously no data will be forwarded to the session so it will hang + // return TRUE; + + //Process the serial read data + devc->ser_rdptr = 0; + if (devc->rxstate == RX_ACTIVE) { + if ((devc->a_chan_mask == 0) + && ((devc->d_chan_mask & 0xFFFFFFF0) == 0)) { + process_D4(sdi, devc); + } else { + process_slice(sdi, devc); + } + } + //process_slice/process_D4 increment ser_rdptr as bytes of the serial buffer are used + //But they may not use all of it, and thus the residual unused bytes are shifted to the start of the buffer + //for the next call. + residual_bytes = devc->bytes_avail - devc->ser_rdptr; + //sr_spew("Residuals resid %d avail %d rdptr %d wrptr %d\n",residual_bytes,devc->bytes_avail,devc->ser_rdptr,devc->wrptr); + if (residual_bytes) { + for (i = 0; i < residual_bytes; i++) { + devc->buffer[i] = + devc->buffer[i + devc->ser_rdptr]; + } + devc->ser_rdptr = 0; + devc->wrptr = residual_bytes; + sr_spew("Residual shift rdptr %u wrptr %u", + devc->ser_rdptr, devc->wrptr); + } else { + //If there are no residuals shifted then zero the wrptr since all data is used + devc->wrptr = 0; + } + //ABORT ends immediately + if (devc->rxstate == RX_ABORT) { + sr_err("Ending receive on abort"); + sdi->driver->dev_acquisition_stop(sdi); + return FALSE; // + } + //if stopped look for final '+' indicating the full byte_cnt is received + if (devc->rxstate == RX_STOPPED) { + sr_dbg("Stopped, checking byte_cnt"); + if (devc->buffer[0] != '$') { + //If this happens it means that we got a set of data that was not processed as + //whole groups of slice bytes. So either we lost data or are not parsing it correctly. + sr_err("ERROR: Stop marker should be byte zero"); + devc->rxstate = RX_ABORT; + sdi->driver->dev_acquisition_stop(sdi); + return FALSE; + } + for (i = 1; i < devc->wrptr; i++) { + if (devc->buffer[i] == '+') { + devc->buffer[i] = 0; + uint64_t rxbytecnt; + rxbytecnt = atol((char *)&(devc->buffer[1])); + sr_dbg + ("Byte_cnt check device cnt %llu host cnt %llu", + rxbytecnt, devc->byte_cnt); + if (rxbytecnt != devc->byte_cnt) { + sr_err + ("ERROR: received %llu and counted %llu bytecnts don't match, data may be lost", + rxbytecnt, devc->byte_cnt); + } + //Since we got the bytecnt we know the device is done sending data + devc->rxstate = RX_IDLE; + //We must always call acquisition_stop on all completed runs + sdi->driver->dev_acquisition_stop(sdi); + return TRUE; + } + } + //It's possible we need one more serial transfer to get the byte_cnt, so print that here + sr_dbg("Haven't seen byte_cnt + yet"); + } //RX_STOPPED + //If at the sample limit, send a "+" in case we are in continuous mode and need + //to stop the device. Not that even in non continous mode there might be cases where get an extra + //sample or two... + + if ((devc->sent_samples >= devc->limit_samples) + && (devc->rxstate == RX_ACTIVE)) { + sr_dbg + ("Ending: sent %u of limit %llu samples byte_cnt %llu", + devc->sent_samples, devc->limit_samples, + devc->byte_cnt); + send_serial_char(serial, '+'); + + } + sr_spew + ("Receive function done: sent %u limit %llu wrptr %u len %d", + devc->sent_samples, devc->limit_samples, devc->wrptr, len); + return TRUE; +} //raspberrypi_pico_receive //Read device specific information from the device SR_PRIV int raspberrypi_pico_get_dev_cfg(const struct sr_dev_inst *sdi) { - struct dev_context *devc; - struct sr_serial_dev_inst *serial; - char *cmd, response[20]; - gchar **tokens; - unsigned int i; - int ret,num_tokens; - - devc = sdi->priv; - sr_dbg("At get_dev_cfg"); - serial = sdi->conn; - for(i=0;inum_a_channels;i++){ - cmd = g_strdup_printf("a%d\n",i); - ret = send_serial_w_resp(serial,cmd,response,20); - if(ret<=0){ - sr_err("ERROR:No response from device for analog channel query"); - return SR_ERR; - } - //null end of string for strsplit - response[ret]=0; - tokens=NULL; - tokens = g_strsplit(response, "x", 0); - num_tokens = g_strv_length(tokens); - if (num_tokens == 2) { - devc->a_scale[i]=((float)atoi(tokens[0]))/1000000.0; - devc->a_offset[i]=((float)atoi(tokens[1]))/1000000.0; - sr_dbg("A%d scale %f offset %f response #%s# tokens #%s# #%s#\n",i,devc->a_scale[i],devc->a_offset[i],response,tokens[0],tokens[1]); - }else{ - sr_err("ERROR:Ascale read c%d got unparseable response %s tokens %d",i,response,num_tokens); - //force a legal fixed value assuming a 3.3V scale - //a failue in parsing the scale - devc->a_scale[i]=0.0257; - devc->a_offset[i]=0.0; - } - g_strfreev(tokens); - g_free(cmd); - } - - - return SR_OK; + struct dev_context *devc; + struct sr_serial_dev_inst *serial; + char *cmd, response[20]; + gchar **tokens; + unsigned int i; + int ret, num_tokens; + + devc = sdi->priv; + sr_dbg("At get_dev_cfg"); + serial = sdi->conn; + for (i = 0; i < devc->num_a_channels; i++) { + cmd = g_strdup_printf("a%d\n", i); + ret = send_serial_w_resp(serial, cmd, response, 20); + if (ret <= 0) { + sr_err + ("ERROR:No response from device for analog channel query"); + return SR_ERR; + } + //null end of string for strsplit + response[ret] = 0; + tokens = NULL; + tokens = g_strsplit(response, "x", 0); + num_tokens = g_strv_length(tokens); + if (num_tokens == 2) { + devc->a_scale[i] = + ((float) atoi(tokens[0])) / 1000000.0; + devc->a_offset[i] = + ((float) atoi(tokens[1])) / 1000000.0; + sr_dbg + ("A%d scale %f offset %f response #%s# tokens #%s# #%s#\n", + i, devc->a_scale[i], devc->a_offset[i], + response, tokens[0], tokens[1]); + } else { + sr_err + ("ERROR:Ascale read c%d got unparseable response %s tokens %d", + i, response, num_tokens); + //force a legal fixed value assuming a 3.3V scale + //a failue in parsing the scale + devc->a_scale[i] = 0.0257; + devc->a_offset[i] = 0.0; + } + g_strfreev(tokens); + g_free(cmd); + } -} + return SR_OK; + +} diff --git a/src/hardware/raspberrypi-pico/protocol.h b/src/hardware/raspberrypi-pico/protocol.h index 7c48fa04..8443003c 100644 --- a/src/hardware/raspberrypi-pico/protocol.h +++ b/src/hardware/raspberrypi-pico/protocol.h @@ -39,113 +39,118 @@ SR_PRIV int send_serial_str(struct sr_serial_dev_inst *serial, char *str); SR_PRIV int send_serial_char(struct sr_serial_dev_inst *serial, char ch); -int send_serial_w_resp(struct sr_serial_dev_inst *serial, char *str,char *resp,size_t cnt); -SR_PRIV int send_serial_w_ack(struct sr_serial_dev_inst *serial, char *str); +int send_serial_w_resp(struct sr_serial_dev_inst *serial, char *str, + char *resp, size_t cnt); +SR_PRIV int send_serial_w_ack(struct sr_serial_dev_inst *serial, + char *str); typedef enum rxstate { - RX_IDLE=0,//not receiving - RX_ACTIVE=1, //receiving data - RX_STOPPED=2, //received stop marker, waiting for byte cnt - RX_ABORT=3, //received aborted marker or other error -}rxstate_t; + RX_IDLE = 0, //not receiving + RX_ACTIVE = 1, //receiving data + RX_STOPPED = 2, //received stop marker, waiting for byte cnt + RX_ABORT = 3, //received aborted marker or other error +} rxstate_t; //TODO todo - stopped review here - renam wrptr, and review all variables struct dev_context { /*Configuration Parameters */ - //It is up to the user to understand sample rates and serial download speed etc and - // do the right thing. i.e. don't expect continuous streaming bandwidth greater - //than serial link speed etc... - //The number of samples the user expects to see. - uint64_t limit_samples; - uint64_t sample_rate; - //Number of samples that have been received and processed - uint32_t num_samples; - //Initial Number of analog and digital channels. - //This is set by initial device config. Channels can be disabled/enabled, - //but can not be added/removed once driver is loaded. - uint16_t num_a_channels; - uint16_t num_d_channels; - //Masks of enabled channels based on user input - uint32_t a_chan_mask; - uint32_t d_chan_mask; - // Channel groups -each analog channel is it's own group - struct sr_channel_group **analog_groups; - struct sr_channel_group *digital_group; - //Data size in bytes for each analog channel in bytes - //must be 1 as only single byte samples are supported in this version - uint8_t a_size; - //Offset and scale for each analog channel to covert bytes to float - float a_offset[MAX_ANALOG_CHANNELS]; - float a_scale[MAX_ANALOG_CHANNELS]; - // % ratio of pre-trigger to post trigger samples - uint64_t capture_ratio; - // total number of bytes of data sent for one sample across all channels - uint16_t bytes_per_slice; - //The number of bytes needed to store all channels for one sample in the device data buff - uint32_t dig_sample_bytes; + //It is up to the user to understand sample rates and serial download speed etc and + // do the right thing. i.e. don't expect continuous streaming bandwidth greater + //than serial link speed etc... + //The number of samples the user expects to see. + uint64_t limit_samples; + uint64_t sample_rate; + //Number of samples that have been received and processed + uint32_t num_samples; + //Initial Number of analog and digital channels. + //This is set by initial device config. Channels can be disabled/enabled, + //but can not be added/removed once driver is loaded. + uint16_t num_a_channels; + uint16_t num_d_channels; + //Masks of enabled channels based on user input + uint32_t a_chan_mask; + uint32_t d_chan_mask; + // Channel groups -each analog channel is it's own group + struct sr_channel_group **analog_groups; + struct sr_channel_group *digital_group; + //Data size in bytes for each analog channel in bytes + //must be 1 as only single byte samples are supported in this version + uint8_t a_size; + //Offset and scale for each analog channel to covert bytes to float + float a_offset[MAX_ANALOG_CHANNELS]; + float a_scale[MAX_ANALOG_CHANNELS]; + // % ratio of pre-trigger to post trigger samples + uint64_t capture_ratio; + // total number of bytes of data sent for one sample across all channels + uint16_t bytes_per_slice; + //The number of bytes needed to store all channels for one sample in the device data buff + uint32_t dig_sample_bytes; /* Tracking/status once started */ - //number of bytes in the current serial input stream - uint32_t bytes_avail; - //Samples sent to the session */ - uint32_t sent_samples; - //count total received bytes to detect lost info*/ - uint64_t byte_cnt; - //For SW based triggering we put the device into continuous transmit and stop when - // we detect a sample and capture all the samples we need. trigger_fired is thus set when - // the sw trigger logic detects a trigger. - //For non triggered modes we send a start and a number of samples and the device - //transmits that much. trigger_fired is set immediately at the start. - gboolean trigger_fired; - //Has the device, via an "!" indicated it has stopped sending data, or has a marker - //error been detected - // gboolean device_stopped; - rxstate_t rxstate; + //number of bytes in the current serial input stream + uint32_t bytes_avail; + //Samples sent to the session */ + uint32_t sent_samples; + //count total received bytes to detect lost info*/ + uint64_t byte_cnt; + //For SW based triggering we put the device into continuous transmit and stop when + // we detect a sample and capture all the samples we need. trigger_fired is thus set when + // the sw trigger logic detects a trigger. + //For non triggered modes we send a start and a number of samples and the device + //transmits that much. trigger_fired is set immediately at the start. + gboolean trigger_fired; + //Has the device, via an "!" indicated it has stopped sending data, or has a marker + //error been detected + // gboolean device_stopped; + rxstate_t rxstate; /* Serial Related */ - // Serial data buffer - unsigned char *buffer; - //Size of incoming serial buffer - uint32_t serial_buffer_size; - //Current byte in serial read stream that is being processed - uint32_t ser_rdptr; - //write pointer into the serial input buffer - uint32_t wrptr; + // Serial data buffer + unsigned char *buffer; + //Size of incoming serial buffer + uint32_t serial_buffer_size; + //Current byte in serial read stream that is being processed + uint32_t ser_rdptr; + //write pointer into the serial input buffer + uint32_t wrptr; /* Buffering Related */ - /* parsed serial read data is split into each channels dedicated buffer for analog*/ - float *a_data_bufs[MAX_ANALOG_CHANNELS]; - /*digital samples are stored packed together since cli/pulseview want it that way*/ - uint8_t *d_data_buf; - /*write point for the the per channel data buffers*/ - uint32_t cbuf_wrptr; - /*size of packet data buffers for each channel*/ - uint32_t sample_buf_size; + /* parsed serial read data is split into each channels dedicated buffer for analog */ + float *a_data_bufs[MAX_ANALOG_CHANNELS]; + /*digital samples are stored packed together since cli/pulseview want it that way */ + uint8_t *d_data_buf; + /*write point for the the per channel data buffers */ + uint32_t cbuf_wrptr; + /*size of packet data buffers for each channel */ + uint32_t sample_buf_size; /* RLE related*/ - /*Previous sample values to duplicate for rle */ - float a_last[MAX_ANALOG_CHANNELS]; - uint8_t d_last[MAX_DIGITAL_CHANNELS/8]; + /*Previous sample values to duplicate for rle */ + float a_last[MAX_ANALOG_CHANNELS]; + uint8_t d_last[MAX_DIGITAL_CHANNELS / 8]; /* SW Trigger Related */ - struct soft_trigger_logic *stl; - //Maximum number of entries to store pre-trigger - uint32_t pretrig_entries; - /* Analog pre-trigger storage for software based triggering - because sw based only has internal storage for logic*/ - float *a_pretrig_bufs[MAX_ANALOG_CHANNELS]; - uint32_t pretrig_wr_ptr; + struct soft_trigger_logic *stl; + //Maximum number of entries to store pre-trigger + uint32_t pretrig_entries; + /* Analog pre-trigger storage for software based triggering + because sw based only has internal storage for logic */ + float *a_pretrig_bufs[MAX_ANALOG_CHANNELS]; + uint32_t pretrig_wr_ptr; }; SR_PRIV int raspberrypi_pico_receive(int fd, int revents, void *cb_data); SR_PRIV int raspberrypi_pico_get_dev_cfg(const struct sr_dev_inst *sdi); -void process_D4(struct sr_dev_inst *sdi,struct dev_context *d); -void process_slice(struct sr_dev_inst *sdi,struct dev_context *devc); +void process_D4(struct sr_dev_inst *sdi, struct dev_context *d); +void process_slice(struct sr_dev_inst *sdi, struct dev_context *devc); -int send_analog(struct sr_dev_inst *sdi,struct dev_context *devc,uint32_t num_samples, uint32_t offset); -int send_analog_ring(struct sr_dev_inst *sdi,struct dev_context *devc,uint32_t num_samples); +int send_analog(struct sr_dev_inst *sdi, struct dev_context *devc, + uint32_t num_samples, uint32_t offset); +int send_analog_ring(struct sr_dev_inst *sdi, struct dev_context *devc, + uint32_t num_samples); -int process_group(struct sr_dev_inst *sdi,struct dev_context *devc,uint32_t num_slices); -void rle_memset(struct dev_context *devc,uint32_t num_slices); -SR_PRIV int check_marker(struct dev_context *d,int *len); +int process_group(struct sr_dev_inst *sdi, struct dev_context *devc, + uint32_t num_slices); +void rle_memset(struct dev_context *devc, uint32_t num_slices); +SR_PRIV int check_marker(struct dev_context *d, int *len);