diff options
-rw-r--r-- | fw/Makefile | 4 | ||||
-rw-r--r-- | fw/adc.c | 8 | ||||
-rw-r--r-- | fw/datagen.py | 39 | ||||
-rw-r--r-- | fw/main.c | 2 | ||||
-rw-r--r-- | fw/protocol.c | 43 | ||||
-rw-r--r-- | fw/protocol.h | 3 | ||||
-rw-r--r-- | fw/protocol_test.c | 159 |
7 files changed, 241 insertions, 17 deletions
diff --git a/fw/Makefile b/fw/Makefile index 3050fd1..16cf5c7 100644 --- a/fw/Makefile +++ b/fw/Makefile @@ -92,6 +92,9 @@ program: main.elf openocd.cfg 8b10b_test_decode: 8b10b_test_decode.c 8b10b.c gcc -o $@ $^ +protocol_test: protocol.c protocol_test.c + gcc -o $@ -O0 -Wall -Wextra -g -I../common $^ + clean: rm -f **.o rm -f main.elf main.hex main.bin main.map main.lst @@ -101,4 +104,5 @@ clean: rm -f sources.tar.xz.zip rm -f sources.c rm -f *.dot + rm -f protocol_test @@ -96,12 +96,10 @@ void adc_configure_monitor_mode(struct command_if_def *cmd_if, int ivl_us) { st.det_st.base_interval_cycles = 10; st.det_st.sync = 0; - st.det_st.rx_st.rxpos = -1; - st.det_st.rx_st.address = 5; /* FIXME debug code */ st.det_st.last_bit = 0; st.det_st.committed_len_ctr = st.det_st.len_ctr = 0; - st.det_st.rx_st.cmd_if = cmd_if; xfr_8b10b_reset((struct state_8b10b_dec *)&st.det_st.rx8b10b); + reset_receiver((struct proto_rx_st *)&st.det_st.rx_st, cmd_if); adc_dma_init(NCH, true); @@ -219,7 +217,7 @@ void bit_detector(struct bit_detector_st *st, int a) { } else if (st->len_ctr >= st->committed_len_ctr) { st->committed_len_ctr += st->base_interval_cycles; - receive_bit(&st->rx_st, st->last_bit); + receive_bit(st, st->last_bit); } } @@ -251,7 +249,7 @@ void DMA1_Channel1_IRQHandler(void) { const long vmeas_r_total = VMEAS_R_HIGH + VMEAS_R_LOW; //int a = adc_data.adc_vmeas_a_mv = (st.adc_aggregate[VMEAS_A]*(vmeas_r_total * vcc / VMEAS_R_LOW)) >> 12; int a = adc_data.adc_vmeas_a_mv = (adc_buf[VMEAS_A]*13300) >> 12; - bit_detector(&st.det_st, a); + bit_detector((struct bit_detector_st *)&st.det_st, a); /* ISR timing measurement for debugging */ int end = SysTick->VAL; diff --git a/fw/datagen.py b/fw/datagen.py new file mode 100644 index 0000000..63402dc --- /dev/null +++ b/fw/datagen.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python3 + +import statistics + +if __name__ == '__main__': + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('infile') + + parser.add_argument('-b', '--bitlen', type=float, default=250, help='Average length of a bit in fractional samples') + parser.add_argument('-j', '--jitter', type=float, default=0, help='Bit length jitter standard deviation in fractional samples') + + parser.add_argument('-v', '--high', type=float, default=12.0, help='High level in V') + parser.add_argument('-l', '--low', type=float, default=0.2, help='Low level in V') + parser.add_argument('-n', '--noise', type=float, default=0, help='Gaussian white voltage noise amplitude on top of signal') + + parser.add_argument('-r', '--risetime', type=int, default=1, help='Rise time in sp/V') + parser.add_argument('-f', '--falltime', type=int, default=1, help='Fall time in sp/V') + #parser.add_argument('-g', '--glitchfreq', type=float, default=0, help='Add glitches every {g} samples on average (set to 0 to turn off)') + #parser.add_argument('--glitchlen', type=float, default=0, help='Length of glitches to add in samples') + #parser.add_argument('-t', '--glitch-constant', type=float, default=0, help='When the signal stays constant between bits add a glitch with probability {t}') + args = paresr.parse_args() + + with open(args.infile, 'r') as f: + bits = f.read().replace(' ', '').splitlines() + + + def join_transitions(chunks): + for l, r in zip(chunks, chunks[1:]): + t = args.risetime if l[-1] < r[0] else args.falltime + yield from (l[-1] + (r[0] - l[-1] * i/t) for i in range(t)) + yield from c[args.risetime:-args.falltime] + + def add_noise(vals): + yield from (val + random.gauss(0, args.noise) for val in vals) + + def encode_bits(bitstring): + return add_noise(join_transitions([ args.high if bit == '1' else args.low for _ in range(random.gauss(args.bitlen, args.jitter)) ])) + @@ -37,7 +37,7 @@ enum packet_type { struct { struct command_if_def cmd_if; int payload_len[PKT_TYPE_MAX]; -} cmd_if = {{PKT_TYPE_MAX}, { +} cmd_if = {{.packet_type_max=PKT_TYPE_MAX}, { [PKT_TYPE_RESERVED] = 0, [PKT_TYPE_SET_OUTPUTS_BINARY] = 1, [PKT_TYPE_SET_GLOBAL_BRIGHTNESS] = 1, diff --git a/fw/protocol.c b/fw/protocol.c index 2940aca..87d46e4 100644 --- a/fw/protocol.c +++ b/fw/protocol.c @@ -1,43 +1,66 @@ +#include <unistd.h> #include "protocol.h" #include "8b10b.h" +void reset_receiver(struct proto_rx_st *st, struct command_if_def *cmd_if) { + st->rxpos = -1; + st->address = 5; /* FIXME debug code */ + st->cmd_if = cmd_if; +} + void receive_symbol(struct proto_rx_st *st, int symbol) { if (symbol == -K28_1) { /* Comma/frame delimiter */ st->rxpos = 0; /* Fall through and return and just ignore incomplete packets */ } else if (symbol == -DECODING_ERROR) { - st->rxpos = -1; + goto reset; } else if (symbol < 0) { /* Unknown comma symbol or error */ - st->rxpos = -1; + goto reset; } else if (st->rxpos == -1) { return; } else if (st->rxpos == 0) { /* First data symbol, and not an error or comma symbol */ st->packet_type = symbol & ~PKT_TYPE_BULK_FLAG; - if (st->packet_type >= st->cmd_if->packet_type_max) { - st->rxpos = -1; - return; - } + if (st->packet_type >= st->cmd_if->packet_type_max) + goto reset; + int payload_len = st->cmd_if->payload_len[st->packet_type]; st->is_bulk = symbol & PKT_TYPE_BULK_FLAG; - st->offset = (st->is_bulk) ? st->address*st->cmd_if->payload_len[st->packet_type]+1 : 2; + st->offset = (st->is_bulk) ? (st->address*payload_len + 1) : 2; st->rxpos++; + if (payload_len == 0 && st->is_bulk) { + handle_command(st->packet_type, NULL); + goto reset; + } + } else if (!st->is_bulk && st->rxpos == 1) { - st->rxpos = (symbol == st->address) ? 2 : -1; + if (symbol != st->address) + goto reset; + + if (st->cmd_if->payload_len[st->packet_type] == 0) { + handle_command(st->packet_type, NULL); + goto reset; + } + st->rxpos = 2; } else { - st->argbuf[st->rxpos - st->offset] = symbol; + if (st->rxpos - st->offset >= 0) + st->argbuf[st->rxpos - st->offset] = symbol; st->rxpos++; if (st->rxpos - st->offset == st->cmd_if->payload_len[st->packet_type]) { handle_command(st->packet_type, (uint8_t *)st->argbuf); - st->rxpos = -1; + goto reset; } } + + return; +reset: + st->rxpos = -1; } diff --git a/fw/protocol.h b/fw/protocol.h index 508cfdd..9178c42 100644 --- a/fw/protocol.h +++ b/fw/protocol.h @@ -1,7 +1,7 @@ #ifndef __PROTOCOL_H__ #define __PROTOCOL_H__ -#include "global.h" +#include <stdint.h> #define PKT_TYPE_BULK_FLAG 0x80 @@ -24,5 +24,6 @@ struct command_if_def { void handle_command(int command, uint8_t *args); void receive_symbol(struct proto_rx_st *st, int symbol); +void reset_receiver(struct proto_rx_st *st, struct command_if_def *cmd_if); #endif diff --git a/fw/protocol_test.c b/fw/protocol_test.c new file mode 100644 index 0000000..5f02ef1 --- /dev/null +++ b/fw/protocol_test.c @@ -0,0 +1,159 @@ + +#include <string.h> +#include <assert.h> +#include <stdio.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "protocol.h" +#include "8b10b.h" + +int urandom_fd = -1; + +struct test_cmd_if { + struct command_if_def cmd_if; + int payload_len[256]; +}; + +struct { + int ncalls; + int last_cmd; + uint8_t last_args[sizeof(((struct proto_rx_st *)0)->argbuf)]; +} handler_state; + + +void handle_command(int command, uint8_t *args) { + handler_state.ncalls++; + handler_state.last_cmd = command; + if (args) + memcpy(handler_state.last_args, args, 8); +} + +void send_test_command_single(struct test_cmd_if *cmd_if, struct proto_rx_st *st, int cmd, int address, unsigned char pattern[256]) { + receive_symbol(st, -K28_1); + receive_symbol(st, cmd); + receive_symbol(st, address); + for (int i=0; i<cmd_if->payload_len[i]; i++) + receive_symbol(st, pattern[i]); +} + +void send_test_command_bulk(struct test_cmd_if *cmd_if, struct proto_rx_st *st, int cmd, int index, int len, unsigned char pattern[256]) { + receive_symbol(st, -K28_1); + receive_symbol(st, cmd | PKT_TYPE_BULK_FLAG); + for (int j=0; j<len; j++) { + for (int i=0; i<cmd_if->payload_len[cmd]; i++) { + if (j == index) + receive_symbol(st, pattern[i]); + else + receive_symbol(st, 0xaa); + } + } +} + +void test_commands_with_pattern(struct test_cmd_if *cmd_if, unsigned char pattern[256]) { + struct proto_rx_st st; + + for (int cmd=0; cmd<cmd_if->cmd_if.packet_type_max; cmd++) { + /* Addresssed tests */ + /* + reset_receiver(&st, &cmd_if->cmd_if); + st.address = 23; + handler_state.ncalls = 0; + send_test_command_single(cmd_if, &st, cmd, 23, pattern); + assert(handler_state.ncalls == 1); + assert(handler_state.last_cmd == cmd); + assert(!memcmp(handler_state.last_args, pattern, cmd_if->payload_len[cmd])); + + reset_receiver(&st, &cmd_if->cmd_if); + st.address = 23; + handler_state.ncalls = 0; + send_test_command_single(cmd_if, &st, cmd, 5, pattern); + assert(handler_state.ncalls == 0); + + reset_receiver(&st, &cmd_if->cmd_if); + st.address = 5; + handler_state.ncalls = 0; + send_test_command_single(cmd_if, &st, cmd, 5, pattern); + assert(handler_state.ncalls == 1); + assert(handler_state.last_cmd == cmd); + assert(!memcmp(handler_state.last_args, pattern, cmd_if->payload_len[cmd])); + */ + + /* Bulk test */ + reset_receiver(&st, &cmd_if->cmd_if); + st.address = 5; + handler_state.ncalls = 0; + send_test_command_bulk(cmd_if, &st, cmd, 5, 8, pattern); + assert(handler_state.ncalls == 1); + assert(handler_state.last_cmd == cmd); + assert(!memcmp(handler_state.last_args, pattern, cmd_if->payload_len[cmd])); + } +} + +void test_commands(struct test_cmd_if *cmd_if) { + unsigned char data[256]; + + memset(data, 0, sizeof(data)); + test_commands_with_pattern(cmd_if, data); + + memset(data, 1, sizeof(data)); + test_commands_with_pattern(cmd_if, data); + + memset(data, 255, sizeof(data)); + test_commands_with_pattern(cmd_if, data); + + for (int i=0; i<5; i++) { + assert(read(urandom_fd, (char *)data, sizeof(data)) == sizeof(data)); + test_commands_with_pattern(cmd_if, data); + } +} + +int main(void) { + struct test_cmd_if cmd_if; + + urandom_fd = open("/dev/urandom", O_RDONLY); + assert(urandom_fd > 0); + + for (int ncmds=1; ncmds<128; ncmds++) { + cmd_if.cmd_if.packet_type_max = ncmds; + + /* Case 1 */ + for (int i=0; i<ncmds; i++) + cmd_if.payload_len[i] = 0; + test_commands(&cmd_if); + + /* Case 2 */ + for (int i=0; i<ncmds; i++) + cmd_if.payload_len[i] = 1; + test_commands(&cmd_if); + + /* Case 3 */ + for (int i=0; i<ncmds; i++) + cmd_if.payload_len[i] = i&1 ? 1 : 0; + test_commands(&cmd_if); + + /* Case 4 */ + for (int i=0; i<ncmds; i++) + cmd_if.payload_len[i] = i&1 ? 0 : 1; + test_commands(&cmd_if); + + /* Case 5 */ + for (int i=0; i<ncmds; i++) + cmd_if.payload_len[i] = i&1 ? 1 : 2; + test_commands(&cmd_if); + + /* Case 6 */ + for (int i=0; i<ncmds; i++) + cmd_if.payload_len[i] = i%8; + test_commands(&cmd_if); + + /* Case 7 */ + for (int i=0; i<ncmds; i++) + cmd_if.payload_len[i] = 4; + test_commands(&cmd_if); + } + + assert(!close(urandom_fd)); +} |