DragonProbe/src/m_sump/cdc_sump.c

828 lines
24 KiB
C

/*
* The MIT License (MIT)
*
* Copyright (c) 2021 Jaroslav Kysela <perex@perex.cz>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*
* Protocol link: https://www.sump.org/projects/analyzer/protocol
*
*/
#include <assert.h>
#include <tusb.h>
#include "alloc.h"
#include "info.h"
#include "m_sump/bsp-feature.h"
#include "m_sump/sump.h"
#include "m_sump/sump_hw.h"
#define picoprobe_debug(format, ...) ((void)0)
#define picoprobe_info(format, ...) ((void)0)
#define CDC_INTF CDC_N_SUMP
#if SAMPLING_BITS != 8 && SAMPLING_BITS != 16
#error "Correct sampling width (8 or 16 bits)"
#endif
// TODO: runtime errors?
/*#if (SUMP_MEMORY_SIZE % SUMP_MAX_CHUNK_SIZE) != 0
#error "Invalid maximal chunk size!"
#endif
#if (SUMP_MEMORY_SIZE / SUMP_MAX_CHUNK_SIZE) < SUMP_DMA_CHANNELS
#error "DMA buffer and DMA channels out of sync!"
#endif*/
#define SUMP_STATE_CONFIG 0
#define SUMP_STATE_INIT 1
#define SUMP_STATE_TRIGGER 2
#define SUMP_STATE_SAMPLING 3
#define SUMP_STATE_DUMP 4
#define SUMP_STATE_ERROR 5
#define AS_16P(a) (*(uint16_t*)(a))
struct _trigger {
uint32_t mask;
uint32_t value;
uint16_t delay;
uint8_t channel;
uint8_t level;
bool serial;
bool start;
};
static struct _sump {
/* internal states */
bool cdc_connected;
uint8_t cmd[5]; // command
uint8_t cmd_pos; // command buffer position
uint8_t state; // SUMP_STATE_*
uint8_t width; // in bytes, 1 = 8 bits, 2 = 16 bits
uint8_t trigger_index;
// uint32_t pio_prog_offset;
uint32_t read_start;
// uint64_t timestamp_start;
/* protocol config */
uint32_t divider; // clock divider
uint32_t read_count;
uint32_t delay_count;
uint32_t flags;
struct _trigger trigger[4];
/* DMA buffer */
uint32_t chunk_size; // in bytes
uint32_t dma_start;
uint32_t dma_count;
// uint32_t dma_curr_idx; // current DMA channel (index)
uint32_t dma_pos;
uint32_t next_count;
//uint8_t buffer[SUMP_MEMORY_SIZE];
} sump;
// not in the main sump struct, as the latter gets cleared every so often
size_t sump_memory_size;
uint8_t* sump_buffer;
/* utility functions ======================================================= */
/*static void picoprobe_debug_hexa(uint8_t *buf, uint32_t len) {
uint32_t l;
for (l = 0; len > 0; len--, l++) {
if (l != 0)
putchar(':');
printf("%02x", *buf++);
}
}*/
static uint8_t* sump_add_metas(uint8_t* buf, uint8_t tag, const char* str) {
*buf++ = tag;
while (*str) *buf++ = (uint8_t)(*str++);
*buf++ = '\0';
return buf;
}
static uint8_t* sump_add_meta1(uint8_t* buf, uint8_t tag, uint8_t val) {
buf[0] = tag;
buf[1] = val;
return buf + 2;
}
static uint8_t* sump_add_meta4(uint8_t* buf, uint8_t tag, uint32_t val) {
buf[0] = tag;
// this is a bit weird, but libsigrok decodes Big-Endian words here
// the commands use Little-Endian
#if 0
buf[1] = val;
buf[2] = val >> 8;
buf[3] = val >> 16;
buf[4] = val >> 24;
#else
buf[1] = val >> 24;
buf[2] = val >> 16;
buf[3] = val >> 8;
buf[4] = val;
#endif
return buf + 5;
}
static void* sump_analyze_trigger8(void* ptr, uint32_t size) {
(void)size;
uint8_t* src = ptr;
uint8_t tmask = sump.trigger[sump.trigger_index].mask;
uint8_t tvalue = sump.trigger[sump.trigger_index].value;
uint32_t count = sump.chunk_size;
for (count = sump.chunk_size; count > 0; count--) {
uint32_t v = *src++;
if ((v & tmask) != tvalue) continue;
while (1) {
if (sump.trigger[sump.trigger_index].start) return src;
sump.trigger_index++;
tmask = sump.trigger[sump.trigger_index].mask;
tvalue = sump.trigger[sump.trigger_index].value;
if (tmask != 0 || tvalue != 0) break;
}
}
return NULL;
}
static void* sump_analyze_trigger16(void* ptr, uint32_t size) {
(void)size;
uint16_t* src = ptr;
uint16_t tmask = sump.trigger[0].mask;
uint16_t tvalue = sump.trigger[0].value;
uint32_t count = sump.chunk_size;
for (count = sump.chunk_size / 2; count > 0; count--) {
uint32_t v = *src++;
if ((v & tmask) != tvalue) continue;
while (1) {
if (sump.trigger[sump.trigger_index].start) return src;
sump.trigger_index++;
tmask = sump.trigger[sump.trigger_index].mask;
tvalue = sump.trigger[sump.trigger_index].value;
if (tmask != 0 || tvalue != 0) break;
}
}
return NULL;
}
static void* sump_analyze_trigger(void* ptr, uint32_t size) {
if (sump.width == 1)
return sump_analyze_trigger8(ptr, size);
else
return sump_analyze_trigger16(ptr, size);
}
uint32_t sump_calc_sysclk_divider() {
const uint32_t common_divisor = 4;
uint32_t divider = sump.divider;
if (divider > 65535) divider = 65535;
// return the fractional part in lowest byte (8 bits)
if (sump.flags & SUMP_FLAG1_DDR) {
// 125Mhz support
divider *= 128 / common_divisor;
} else {
divider *= 256 / common_divisor;
}
uint32_t v = sump_hw_get_sysclk();
assert((v % ONE_MHZ) == 0);
// conversion from 100Mhz to sysclk
v = ((v / ONE_MHZ) * divider) / ((100 / common_divisor) * SAMPLING_DIVIDER);
v *= sump.width;
if (v > 65535 * 256)
v = 65535 * 256;
else if (v <= 255)
v = 256;
picoprobe_debug("%s(): %u %u -> %u (%.4f)\n", __func__, sump_hw_get_sysclk(), sump.divider, v,
(float)v / 256.0);
return v;
}
static void sump_set_chunk_size(void) {
uint32_t clk_hz = sump_hw_get_sysclk() / (sump_calc_sysclk_divider() / 256);
// the goal is to transfer around 125 DMA chunks per second
// for slow sampling rates
sump.chunk_size = 1;
while (clk_hz > 125 && sump.chunk_size < SUMP_MAX_CHUNK_SIZE) {
sump.chunk_size *= 2;
clk_hz /= 2;
}
picoprobe_debug("%s(): 0x%04x\n", __func__, sump.chunk_size);
}
/* data capture ============================================================ */
static void sump_capture_done(void) {
sump_hw_capture_stop();
/*uint64_t us = time_us_64() - sump.timestamp_start;
picoprobe_debug("%s(): sampling time = %llu.%llu\n", __func__, us / 1000000ull, us %
1000000ull);*/
sump.state = SUMP_STATE_DUMP;
}
static int sump_capture_next(uint32_t pos) {
if (sump.state != SUMP_STATE_TRIGGER) {
sump_capture_done();
return 0;
}
// waiting for the trigger samples
uint8_t* ptr = sump_analyze_trigger(sump_buffer + pos, sump.chunk_size);
if (ptr == NULL) {
// call this routine again right after next chunk
return sump.chunk_size;
}
sump.state = SUMP_STATE_SAMPLING;
// calculate read start
uint32_t tmp = (sump.read_count - sump.delay_count) * sump.width;
pos = ptr - sump_buffer;
sump.read_start = (pos - tmp) % sump_memory_size;//SUMP_MEMORY_SIZE;
// calculate the samples after trigger
uint32_t delay_bytes = sump.delay_count * sump.width;
tmp = sump.chunk_size - (pos % sump.chunk_size);
if (tmp >= delay_bytes) {
sump_capture_done();
return 0;
}
return delay_bytes - tmp;
}
uint8_t* sump_capture_get_next_dest(uint32_t numch) {
return sump_buffer + (sump.dma_pos + numch * sump.chunk_size) % sump_memory_size;//SUMP_MEMORY_SIZE;
}
void sump_capture_callback_cancel(void) {
sump_capture_done();
sump.state = SUMP_STATE_ERROR;
}
void sump_capture_callback(uint32_t ch, uint32_t numch) {
// reprogram the current DMA channel to the tail
if (sump.next_count <= sump.chunk_size) {
sump.next_count = sump_capture_next(sump.dma_pos);
if (sump.state == SUMP_STATE_DUMP) return;
} else {
sump.next_count -= sump.chunk_size;
}
// sump_irq_debug("%s(): next=0x%x\n", __func__, sump.next_count);
sump.dma_pos += sump.chunk_size;
sump.dma_pos %= sump_memory_size;//SUMP_MEMORY_SIZE;
if (sump.state == SUMP_STATE_SAMPLING && sump.next_count >= sump.chunk_size &&
sump.next_count < numch * sump.chunk_size) {
// set the last DMA segment to correct size to avoid overwrites
uint32_t mask = sump.next_count / sump.chunk_size;
sump_hw_capture_setup_next(ch, mask, sump.chunk_size, sump.next_count, sump.width);
}
}
/* --- */
static void sump_xfer_start(uint8_t state) {
sump.dma_start = 0;
sump.dma_pos = 0;
picoprobe_debug("%s(): read=0x%08x delay=0x%08x divider=%u\n", __func__, sump.read_count,
sump.delay_count, sump.divider);
uint32_t count = sump.read_count;
if (count > sump_memory_size) count = sump_memory_size;
sump.dma_count = count;
if (sump.read_count <= sump.delay_count)
sump.next_count = sump.read_count;
else
sump.next_count = sump.read_count - sump.delay_count;
sump.next_count *= sump.width;
sump.read_start = 0;
picoprobe_debug("%s(): buffer = 0x%08x, dma_count=0x%08x next_count=0x%08x\n", __func__,
sump_buffer, sump.dma_count, sump.next_count);
// limit chunk size for slow sampling
sump_set_chunk_size();
/*sump.timestamp_start =*/sump_hw_capture_start(
sump.width, sump.flags, sump.chunk_size, sump_buffer);
sump.state = state;
}
/* SUMP proto command handling ============================================= */
static void sump_do_meta(void) {
char cpu[32];
uint8_t buf[128], *ptr = buf, *wptr = buf;
ptr = sump_add_metas(ptr, SUMP_META_NAME, INFO_PRODUCT_BARE " Logic Analyzer v1");
sump_hw_get_hw_name(cpu);
ptr = sump_add_metas(ptr, SUMP_META_FPGA_VERSION, cpu);
sump_hw_get_cpu_name(cpu);
ptr = sump_add_metas(ptr, SUMP_META_CPU_VERSION, cpu);
ptr = sump_add_meta4(ptr, SUMP_META_SAMPLE_RATE, sump_hw_get_sysclk() / SAMPLING_DIVIDER);
ptr = sump_add_meta4(ptr, SUMP_META_SAMPLE_RAM, sump_memory_size);
ptr = sump_add_meta1(ptr, SUMP_META_PROBES_B, SAMPLING_BITS);
ptr = sump_add_meta1(ptr, SUMP_META_PROTOCOL_B, 2);
*ptr++ = SUMP_META_END;
assert(ptr < &buf[128] && "Stack overflow! aaaa!");
while (wptr != ptr) wptr += tud_cdc_n_write(CDC_INTF, wptr, ptr - wptr);
tud_cdc_n_write_flush(CDC_INTF);
}
static void sump_do_id(void) {
tud_cdc_n_write_str(CDC_INTF, "1ALS");
tud_cdc_n_write_flush(CDC_INTF);
}
static void sump_do_run(void) {
uint8_t state;
uint32_t tmask = 0;
bool tstart = false;
if (sump.width == 0) {
// invalid config, dump something nice
sump.state = SUMP_STATE_DUMP;
return;
}
for (uint32_t i = 0; i < count_of(sump.trigger); i++) {
tstart |= sump.trigger[i].start;
tmask |= sump.trigger[i].mask;
}
if (tstart && tmask) {
state = SUMP_STATE_TRIGGER;
sump.trigger_index = 0;
} else {
state = SUMP_STATE_SAMPLING;
}
sump_xfer_start(state);
}
static void sump_do_finish(void) {
if (sump.state == SUMP_STATE_TRIGGER || sump.state == SUMP_STATE_SAMPLING) {
sump.state = SUMP_STATE_DUMP;
sump_capture_done();
return;
}
}
static void sump_do_stop(void) {
if (sump.state == SUMP_STATE_INIT) return;
sump_hw_stop();
// protocol state
sump.state = SUMP_STATE_INIT;
}
static void sump_do_reset(void) {
sump_do_stop();
memset(&sump.trigger, 0, sizeof(sump.trigger));
}
static void sump_set_flags(uint32_t flags) {
uint32_t width = 2;
sump.flags = flags;
if (flags & SUMP_FLAG1_GR0_DISABLE) width--;
if (flags & SUMP_FLAG1_GR1_DISABLE) width--;
// we don't support 24-bit or 32-bit capture - sorry
if ((flags & SUMP_FLAG1_GR2_DISABLE) == 0) width = 0;
if ((flags & SUMP_FLAG1_GR3_DISABLE) == 0) width = 0;
picoprobe_debug("%s(): sample %u bytes\n", __func__, width);
sump.width = width;
}
static void sump_update_counts(uint32_t val) {
/*
* This just sets up how many samples there should be before
* and after the trigger fires. The read_count is total samples
* to return and delay_count number of samples after
* the trigger.
*
* This sets the buffer splits like 0/100, 25/75, 50/50
* for example if read_count == delay_count then we should
* return all samples starting from the trigger point.
* If delay_count < read_count we return
* (read_count - delay_count) of samples from before
* the trigger fired.
*/
uint32_t read_count = ((val & 0xffff) + 1) * 4;
uint32_t delay_count = ((val >> 16) + 1) * 4;
if (delay_count > read_count) read_count = delay_count;
sump.read_count = read_count;
sump.delay_count = delay_count;
}
static void sump_set_trigger_mask(uint32_t trig, uint32_t val) {
struct _trigger* t = &sump.trigger[trig];
t->mask = val;
picoprobe_debug("%s(): idx=%u val=0x%08x\n", __func__, trig, val);
}
static void sump_set_trigger_value(uint32_t trig, uint32_t val) {
struct _trigger* t = &sump.trigger[trig];
t->value = val;
picoprobe_debug("%s(): idx=%u val=0x%08x\n", __func__, trig, val);
}
static void sump_set_trigger_config(uint32_t trig, uint32_t val) {
struct _trigger* t = &sump.trigger[trig];
t->start = (val & 0x08000000) != 0;
t->serial = (val & 0x02000000) != 0;
t->channel = ((val >> 20) & 0x0f) | ((val >> (24 - 4)) & 0x10);
t->level = (val >> 16) & 3;
t->delay = val & 0xffff;
picoprobe_debug("%s(): idx=%u val=0x%08x (start=%u serial=%u channel=%u level=%u delay=%u)\n",
__func__, trig, val, t->start, t->serial, t->channel, t->level, t->delay);
}
/* UART protocol handling ================================================== */
static void sump_rx_short(uint8_t cmd) {
picoprobe_debug("%s(): 0x%02x\n", __func__, cmd);
switch (cmd) {
case SUMP_CMD_RESET: sump_do_reset(); break;
case SUMP_CMD_ARM: sump_do_run(); break;
case SUMP_CMD_ID: sump_do_id(); break;
case SUMP_CMD_META: sump_do_meta(); break;
case SUMP_CMD_FINISH: sump_do_finish(); break;
case SUMP_CMD_QUERY_INPUT: break;
case SUMP_CMD_ADVANCED_ARM: sump_do_run(); break;
default: break;
}
}
static void sump_rx_long(uint8_t* cmd) {
uint32_t val = cmd[1] | (cmd[2] << 8) | (cmd[3] << 16) | (cmd[4] << 24);
picoprobe_debug("%s(): [0x%02x] 0x%08x\n", __func__, cmd[0], val);
switch (cmd[0]) {
case SUMP_CMD_SET_SAMPLE_RATE:
sump_do_stop();
sump.divider = val + 1;
break;
case SUMP_CMD_SET_COUNTS:
sump_do_stop();
sump_update_counts(val);
break;
case SUMP_CMD_SET_FLAGS:
sump_do_stop();
sump_set_flags(val);
break;
case SUMP_CMD_SET_ADV_TRG_SELECT:
case SUMP_CMD_SET_ADV_TRG_DATA: break; /* not implemented */
case SUMP_CMD_SET_BTRG0_MASK:
case SUMP_CMD_SET_BTRG1_MASK:
case SUMP_CMD_SET_BTRG2_MASK:
case SUMP_CMD_SET_BTRG3_MASK:
sump_set_trigger_mask((cmd[0] - SUMP_CMD_SET_BTRG0_MASK) / 3, val);
break;
case SUMP_CMD_SET_BTRG0_VALUE:
case SUMP_CMD_SET_BTRG1_VALUE:
case SUMP_CMD_SET_BTRG2_VALUE:
case SUMP_CMD_SET_BTRG3_VALUE:
sump_set_trigger_value((cmd[0] - SUMP_CMD_SET_BTRG0_VALUE) / 3, val);
break;
case SUMP_CMD_SET_BTRG0_CONFIG:
case SUMP_CMD_SET_BTRG1_CONFIG:
case SUMP_CMD_SET_BTRG2_CONFIG:
case SUMP_CMD_SET_BTRG3_CONFIG:
sump_set_trigger_config((cmd[0] - SUMP_CMD_SET_BTRG0_CONFIG) / 3, val);
break;
default: return;
}
}
static void sump_rx(uint8_t* buf, uint32_t count) {
if (count == 0) return;
#if 0
picoprobe_debug("%s(): ", __func__);
picoprobe_debug_hexa(buf, count);
picoprobe_debug("\n");
#endif
while (count-- > 0) {
sump.cmd[sump.cmd_pos++] = *buf++;
if (SUMP_CMD_IS_SHORT(sump.cmd[0])) {
sump_rx_short(sump.cmd[0]);
sump.cmd_pos = 0;
} else if (sump.cmd_pos >= 5) {
sump_rx_long(sump.cmd);
sump.cmd_pos = 0;
}
}
}
static uint32_t sump_tx_empty(uint8_t* buf, uint32_t len) {
uint32_t i;
uint32_t count = sump.read_count;
// picoprobe_debug("%s: count=%u\n", __func__, count);
uint8_t a = 0x55;
if (sump.flags & SUMP_FLAG1_ENABLE_RLE) {
count += count & 1; // align up
if (sump.width == 1) {
for (i = 0; i < len && count > 0; count -= 2, i += 2) {
*buf++ = 0x81; // RLE mark + two samples
*buf++ = a;
a ^= 0xff;
}
if (i > sump.read_count)
sump.read_count = 0;
else
sump.read_count -= i;
} else if (sump.width == 2) {
for (i = 0; i < len && count > 0; count -= 2, i += 4) {
*buf++ = 0x01; // two samples
*buf++ = 0x80; // RLE mark + two samples
*buf++ = a;
*buf++ = a;
a ^= 0xff;
}
if (i / 2 > sump.read_count)
sump.read_count = 0;
else
sump.read_count -= i / 2;
} else {
return 0;
}
} else {
if (sump.width == 1) {
for (i = 0; i < len && count > 0; count--, i++) {
*buf++ = a;
a ^= 0xff;
}
sump.read_count -= i;
} else if (sump.width == 2) {
for (i = 0; i < len && count > 0; count--, i += 2) {
*buf++ = a;
*buf++ = a;
a ^= 0xff;
}
sump.read_count -= i / 2;
} else {
return 0;
}
}
// picoprobe_debug("%s: ret=%u\n", __func__, i);
return i;
}
static uint32_t sump_tx8(uint8_t* buf, uint32_t len) {
uint32_t i;
uint32_t count = sump.read_count;
// picoprobe_debug("%s: count=%u, start=%u\n", __func__, count);
uint8_t* ptr = sump_buffer + (sump.read_start + count) % sump_memory_size;//SUMP_MEMORY_SIZE;
if (sump.flags & SUMP_FLAG1_ENABLE_RLE) {
uint8_t b, rle_last = 0x80, rle_count = 0;
for (i = 0; i + 1 < len && count > 0; count--) {
if (ptr == sump_buffer) ptr = sump_buffer + sump_memory_size;//SUMP_MEMORY_SIZE;
b = *(--ptr) & 0x7f;
if (b != rle_last) {
if (rle_count > 0) {
*((uint16_t*)buf) = (rle_count - 1) | 0x80 | ((uint16_t)rle_last << 8);
buf += 2;
i += 2;
sump.read_count -= rle_count;
}
rle_last = b;
rle_count = 1;
continue;
}
if (++rle_count == 0x80) {
*((uint16_t*)buf) = (rle_count - 1) | 0x80 | ((uint16_t)rle_last << 8);
buf += 2;
i += 2;
sump.read_count -= rle_count;
rle_count = 0;
}
}
} else {
for (i = 0; i < len && count > 0; i++, count--) {
if (ptr == sump_buffer) ptr = sump_buffer + sump_memory_size;//SUMP_MEMORY_SIZE;
*buf++ = *(--ptr);
}
sump.read_count -= i;
}
// picoprobe_debug("%s: ret=%u\n", __func__, i);
return i;
}
static uint32_t sump_tx16(uint8_t* buf, uint32_t len) {
uint32_t i;
uint32_t count = sump.read_count;
// picoprobe_debug("%s: count=%u, start=%u\n", __func__, count, sump.read_count);
volatile uint8_t* ptr = sump_buffer + (sump.read_start + count * 2) % sump_memory_size;//SUMP_MEMORY_SIZE;
if (sump.flags & SUMP_FLAG1_ENABLE_RLE) {
uint16_t rle_last = 0x8000, rle_count = 0;
for (i = 0; i + 3 < len && count > 0; count--) {
if (ptr == sump_buffer) ptr = sump_buffer + sump_memory_size;//SUMP_MEMORY_SIZE;
ptr -= 2;
uint32_t b = *((uint16_t*)ptr) & 0x7fff;
if (b != rle_last) {
if (rle_count > 0) {
*((uint32_t*)buf) = (rle_count - 1) | 0x8000 | ((uint32_t)rle_last << 16);
buf += 4;
i += 4;
sump.read_count -= rle_count;
}
rle_last = b;
rle_count = 1;
continue;
}
if (++rle_count == 0x8000) {
*((uint32_t*)buf) = (rle_count - 1) | 0x8000 | ((uint32_t)rle_last << 16);
buf += 4;
i += 4;
sump.read_count -= rle_count;
rle_count = 0;
}
}
} else {
for (i = 0; i + 1 < len && count > 0; i += 2, count--) {
if (ptr == sump_buffer) ptr = sump_buffer + sump_memory_size;//SUMP_MEMORY_SIZE;
ptr -= 2;
*((uint16_t*)buf) = *((uint16_t*)ptr);
buf += 2;
}
sump.read_count -= i / 2;
}
// picoprobe_debug("%s: ret=%u\n", __func__, i);
return i;
}
static uint32_t sump_fill_tx(uint8_t* buf, uint32_t len) {
uint32_t ret;
assert((len & 3) == 0);
if (sump.read_count == 0) {
sump.state = SUMP_STATE_CONFIG;
return 0;
}
if (sump.state == SUMP_STATE_DUMP) {
if (sump.width == 1) {
ret = sump_tx8(buf, len);
} else if (sump.width == 2) {
ret = sump_tx16(buf, len);
} else {
// invalid
ret = sump_tx_empty(buf, len);
}
} else {
// invalid or error
ret = sump_tx_empty(buf, len);
}
if (ret == 0) sump.state = SUMP_STATE_CONFIG;
return ret;
}
static void sump_init_connect(void) {
memset(&sump, 0, sizeof(sump));
memset(sump_buffer, 0, sump_memory_size);
sump.width = 1;
sump.divider = 1000; // a safe value
sump.read_count = 256;
sump.delay_count = 256;
}
void cdc_sump_init(void) {
sump_buffer = m_alloc_all_remaining(SUMP_MAX_CHUNK_SIZE, 4, &sump_memory_size);
sump_hw_init();
sump_init_connect();
picoprobe_debug("%s(): memory buffer %u bytes\n", __func__, sump_memory_size);
}
void cdc_sump_deinit(void) {
sump_hw_deinit();
memset(&sump, 0, sizeof(sump));
memset(sump_buffer, 0, sump_memory_size);
}
#define MAX_UART_PKT 64
void cdc_sump_task(void) {
uint8_t buf[MAX_UART_PKT];
if (tud_cdc_n_connected(CDC_INTF)) {
if (!sump.cdc_connected) {
sump_init_connect();
sump.cdc_connected = true;
}
if (sump.state == SUMP_STATE_DUMP || sump.state == SUMP_STATE_ERROR) {
if (tud_cdc_n_write_available(CDC_INTF) >= sizeof(buf)) {
uint32_t tx_len = sump_fill_tx(buf, sizeof(buf));
tud_cdc_n_write(CDC_INTF, buf, tx_len);
tud_cdc_n_write_flush(CDC_INTF);
}
}
if (tud_cdc_n_available(CDC_INTF)) {
uint32_t cmd_len = tud_cdc_n_read(CDC_INTF, buf, sizeof(buf));
sump_rx(buf, cmd_len);
}
/*if (sump.state == SUMP_STATE_TRIGGER || sump.state == SUMP_STATE_SAMPLING)
led_signal_activity(1);*/
} else if (!sump.cdc_connected) {
sump.cdc_connected = false;
sump_do_reset();
}
}
// we could hook the callback, but it's not really used, so, eh.
/*void cdc_sump_line_coding(cdc_line_coding_t const *line_coding);
void cdc_sump_line_coding(cdc_line_coding_t const *line_coding) {
picoprobe_info("Sump new baud rate %d\n", line_coding->bit_rate);
}*/