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
+//The host can either provide a std_gvar_samplerates_steps or a std_gvar_samplerates.
+//The latter is just a long list of every supported rate.
+//For the steps, pulseview/pv/toolbars/mainbar.cpp will do a min,max,step. If step is
+//1 then it provides a 1,2,5,10 select otherwise it allows a spin box.
+//Going with the full list because while the spin box is more flexible, it is harder to read
+/*
static const uint64_t samplerates[] = {
SR_HZ(10),
SR_MHZ(120),
SR_HZ(2),
};
+*/
+static const uint64_t samplerates[] = {
+ SR_KHZ(5),
+ SR_KHZ(6),
+ SR_KHZ(8),
+ SR_KHZ(10),
+ SR_KHZ(20),
+ SR_KHZ(30),
+ SR_KHZ(40),
+ SR_KHZ(50),
+ SR_KHZ(60),
+ SR_KHZ(80),
+ SR_KHZ(100),
+ SR_KHZ(125),
+ SR_KHZ(150),
+ SR_KHZ(160),//max rate of 3 ADC channels that has integer divisor/dividend
+ SR_KHZ(200),
+ SR_KHZ(250), //max rate of 2 ADC channels
+ SR_KHZ(300),
+ SR_KHZ(400),
+ SR_KHZ(500),
+ SR_KHZ(600),
+ SR_KHZ(800),
+ //Give finer granularity near the thresholds of RLE effectiveness
+ SR_MHZ(1),
+ SR_MHZ(1.25),
+ SR_MHZ(1.5),
+ SR_MHZ(2),
+ SR_MHZ(2.5),
+ SR_MHZ(3),
+ SR_MHZ(4),
+ SR_MHZ(5),
+ SR_MHZ(6),
+ SR_MHZ(8),
+ SR_MHZ(10),
+ SR_MHZ(15),
+ SR_MHZ(20),
+ SR_MHZ(30),
+ SR_MHZ(40),
+ SR_MHZ(60),
+ SR_MHZ(120)
+};
static const uint32_t drvopts[] = {
SR_CONF_OSCILLOSCOPE,
}
//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
+ //and zz is number of digital channels, and VV is two digit version# which must be 02
if ((num_read < 16)
|| (strncmp(buf, "SRPICO,A", 8))
|| (buf[11] != 'D')
|| (buf[15] != '0')
- || (buf[16] != '0')) {
+ || (buf[16] != '2')) {
sr_err("ERROR:Bad response string %s %d", buf, num_read);
return NULL;
}
//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;
+ //And thus no serial buffer is large enough. But, it's only 32K....
+ devc->serial_buffer_size = 32000;
devc->buffer = NULL;
sr_dbg("Setting serial buffer size: %i.",
devc->serial_buffer_size);
//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;
+ //An RLE byte in normal mode can represent up to 1640 samples.
+ //In D4 an RLE byte can represents up to 640 samples.
+ //Rather than making the sample_buf_size 1640x the size of serial buff, we require that the process loops
+ //push samples to the session as we get anywhere close to full.
+
+ devc->sample_buf_size = devc->serial_buffer_size;
for (i = 0; i < devc->num_a_channels; i++) {
devc->a_data_bufs[i] = NULL;
devc->a_pretrig_bufs[i] = NULL;
}
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
+// std_gvar_samplerates_steps(ARRAY_AND_SIZE
+// (samplerates));
+ std_gvar_samplerates(ARRAY_AND_SIZE
(samplerates));
break;
//This must be set to get SW trigger support
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)) {
+ if ((a_enabled == 3) && (devc->sample_rate > 160000)) {
sr_err
- ("ERROR:3 channel ADC sample rate dropped to 166.660khz");
- devc->sample_rate = 166660;
+ ("ERROR:3 channel ADC sample rate dropped to 160khz");
+ devc->sample_rate = 160000;
}
if ((a_enabled == 2) && (devc->sample_rate > 250000)) {
sr_err
//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;
}
}
- //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_MALLOC;
}
}
-
+ devc->pretrig_entries =
+ (devc->capture_ratio * devc->limit_samples) / 100;
+ //While the driver supports the passing of trigger info to the device
+ //it has been found that the sw overhead of supporting triggering and
+ //pretrigger buffer entries etc.. ends up slowing the cores down enough
+ //that the effect continous sample rate isn't much higher than that of sending
+ //untriggered samples across USB. Thus this code will remain but likely may
+ //not be used by the device.
if ((trigger = sr_session_trigger_get(sdi->session))) {
- devc->pretrig_entries =
- (devc->capture_ratio * devc->limit_samples) / 100;
+ if (g_slist_length(trigger->stages) > 1)
+ return SR_ERR_NA;
+
+ struct sr_trigger_stage *stage;
+ struct sr_trigger_match *match;
+ GSList *l;
+ stage = g_slist_nth_data(trigger->stages, 0);
+ if (!stage)
+ return SR_ERR_ARG;
+ for (l = stage->matches; l; l = l->next) {
+ match = l->data;
+ if (!match->match)
+ continue;
+ if (!match->channel->enabled)
+ continue;
+ int idx = match->channel->index;
+ int8_t val;
+ switch(match->match){
+ case SR_TRIGGER_ZERO:
+ val=0; break;
+ case SR_TRIGGER_ONE:
+ val=1; break;
+ case SR_TRIGGER_RISING:
+ val=2; break;
+ case SR_TRIGGER_FALLING:
+ val=3; break;
+ case SR_TRIGGER_EDGE:
+ val=4; break;
+ default:
+ val=-1;
+ }
+ sr_info("Trigger value idx %d match %d",idx,match->match);
+ //Only set trigger on enabled channels
+ if((val>=0) && ((devc->d_chan_mask>>idx)&1)){
+ sprintf(&tmpstr[0], "t%d%02d\n", val,idx+2);
+ if (send_serial_w_ack(serial, tmpstr) != SR_OK) {
+ sr_err("Trigger cfg to device failed");
+ return SR_ERR;
+ }
+
+ }
+ }
+ sprintf(&tmpstr[0], "p%d\n", devc->pretrig_entries);
+ if (send_serial_w_ack(serial, tmpstr) != SR_OK) {
+ sr_err("Pretrig to device failed");
+ return SR_ERR;
+ }
devc->stl =
soft_trigger_logic_new(sdi, trigger,
devc->pretrig_entries);
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
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;
+ uint32_t didx=(d->cbuf_wrptr) * (d->dig_sample_bytes);
+ d->d_data_buf[didx] = 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;
+ d->d_data_buf[didx+j] = 0;
}
- sampcnt++;
d->byte_cnt++;
sr_spew
- ("Dchan4 rdptr %d wrptr %d bytein 0x%X rle %d cval 0x%X\n",
+ ("Dchan4 rdptr %d wrptr %d bytein 0x%X rle %d cval 0x%X didx %d\n",
(d->ser_rdptr) - 1, d->cbuf_wrptr, cbyte,
- rlecnt, cval);
+ rlecnt, cval,didx);
+ d->cbuf_wrptr++;
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
break; //break from while loop
}
(d->ser_rdptr)++;
- } //while rdptr < wrptr
+ //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.
+ //cbuf_wrptr counts slices, so shift right by 2 to create a worst case x4 multiple ratio of
+ //cbuf_wrptr value to the depth of the sample buffer.
+ //Likely we could use the max rle value of 640 but 1024 gives some extra room.
+ //Also do a simple check of rlecnt>2000 since that is a reasonable minimal value to send to the session
+ if ((rlecnt>=2000)
+ ||((rlecnt + ((d->cbuf_wrptr)<<2))) > (d->sample_buf_size - 1024)) {
+ sr_spew("D4 preoverflow wrptr %d bufsize %d rlecnt %d\n\r",d->cbuf_wrptr,d->sample_buf_size,rlecnt);
+ rle_memset(d, rlecnt);
+ process_group(sdi, d, d->cbuf_wrptr);
+ rlecnt=0;
+ }
+
+ }//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_group(sdi, d, d->cbuf_wrptr);
}
-} //Process_D4
+} //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.
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
+ uint32_t slice_bytes; //number of bytes that have legal slice values including RLE
+ //Only process legal data values for this mode which are 0x32-0x7F for RLE and 0x80 to 0xFF for data
for (slice_bytes = 1; (slice_bytes < devc->bytes_avail)
- && (devc->buffer[slice_bytes - 1] >= 0x80); slice_bytes++);
+ && (devc->buffer[slice_bytes - 1] >= 0x30); slice_bytes++);
if (slice_bytes != devc->bytes_avail) {
cbyte = devc->buffer[slice_bytes - 1];
slice_bytes--; //Don't process the ending character
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++;
+ //Must have a full slice or one rle byte
+ while (((devc->ser_rdptr + devc->bytes_per_slice) <= slice_bytes)
+ ||((devc->ser_rdptr < slice_bytes)&&(devc->buffer[devc->ser_rdptr] < 0x80))) {
+
+ if(devc->buffer[devc->ser_rdptr] < 0x80){
+ int16_t rlecnt;
+ if(devc->buffer[devc->ser_rdptr]<=79){
+ rlecnt=devc->buffer[devc->ser_rdptr]-47;
+ }else{
+ rlecnt=(devc->buffer[devc->ser_rdptr]-78)*32;
+ }
+ sr_info("RLEcnt of %d in %d",rlecnt,devc->buffer[devc->ser_rdptr]);
+ if((rlecnt < 1)||(rlecnt>1568)){
+ sr_err("Bad rlecnt val %d in %d",rlecnt,devc->buffer[devc->ser_rdptr]);
+ }else{
+ rle_memset(devc,rlecnt);
+ }
+ devc->ser_rdptr++;
+
+ }else{
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) {
}
}
//and then distribute 8 bits at a time to all possible channels
+ //but first save of cword for rle
+ devc->d_last[0]=cword&0xFF;
+ devc->d_last[1]=(cword>>8)&0xFF;
+ devc->d_last[2]=(cword>>16)&0xFF;
+ devc->d_last[3]=(cword>>24)&0xFF;
for (i = 0; i < devc->num_d_channels; i += 8) {
uint32_t idx =
((devc->cbuf_wrptr) * devc->dig_sample_bytes) +
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) {
} //if channel enabled
} //for num_a_channels
devc->cbuf_wrptr++;
- } //While another slice available
- if (slices_avail) {
- process_group(sdi, devc, slices_avail);
+ }//Not an RLE
+ //RLEs can create a large number of samples relative to the incoming serial buffer
+ //To prevent overflow of the sample data buffer we call process_group.
+ //cbuf_wrptr and sample_buf_size are both in terms of slices
+ //2048 is more than needed for a max rle of 1640 on the next incoming character
+ if((devc->cbuf_wrptr +2048) > devc->sample_buf_size){
+ sr_spew("Drain large buff %d %d\n\r",devc->cbuf_wrptr,devc->sample_buf_size);
+ process_group(sdi, devc, devc->cbuf_wrptr);
+
+ }
+ }//While another slice or RLE available
+ if (devc->cbuf_wrptr){
+ process_group(sdi, devc, devc->cbuf_wrptr);
}
}
sr_spew
("Process_group sending %d post trig samples dsb %d",
num_samples, devc->dig_sample_bytes);
- //for(int z=0;(z<num_samples);z+=2){
- // sr_spew("0x%X ",devc->d_data_buf[z]);
+ //for(int z=0;(z<num_samples);z++){
+ // sr_spew("0x%X ",devc->d_data_buf[z]);
//}
if (devc->num_d_channels) {
packet.type = SR_DF_LOGIC;
//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 %d\n", devc->d_last[0],
+ uint32_t j, k,didx;
+ sr_spew("rle_memset vals 0x%X, 0x%X, 0x%X slices %d dsb %d\n", devc->d_last[0],devc->d_last[1],devc->d_last[2],
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++) {
+ didx=devc->cbuf_wrptr*devc->dig_sample_bytes;
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]);
+ devc->d_data_buf[didx + k] = devc->d_last[k];
+ // sr_spew("k %d j %d v 0x%X p %d didx %d",k,j,devc->d_data_buf[(devc->cbuf_wrptr)+k],(devc->cbuf_wrptr)+k,didx);
}
+ // cbuf_wrptr always counts slices/samples (and not the bytes in the buffer)
+ // regardless of mode
+ devc->cbuf_wrptr++;
}
+
}
//This callback function is mapped from api.c with serial_source_add and is created after a capture