From 896df82e279b2a4c0852fb03044f26b37da6a931 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Hru=C5=A1ka?= Date: Sun, 1 Apr 2018 00:45:47 +0200 Subject: [PATCH] wip rx handler --- .gitignore | 2 + CMakeLists.txt | 44 +++++++++++++ Inc/debug.h | 10 +++ Inc/gex_gateway.h | 11 ++++ Inc/main.h | 3 + Inc/minmax.h | 16 +++++ Inc/msg_queue.h | 37 +++++++++++ Inc/payload_builder.h | 110 ++++++++++++++++++++++++++++++++ Inc/payload_parser.h | 143 ++++++++++++++++++++++++++++++++++++++++++ Inc/type_coerce.h | 32 ++++++++++ Inc/usart.h | 3 + Inc/usbd_conf.h | 6 +- Makefile | 28 ++++++--- Src/debug.c | 35 +++++++++++ Src/freertos.c | 0 Src/gex_gateway.c | 111 ++++++++++++++++++++++++++++++++ Src/main.c | 27 +++++--- Src/msg_queue.c | 67 ++++++++++++++++++++ Src/payload_builder.c | 100 +++++++++++++++++++++++++++++ Src/payload_parser.c | 121 +++++++++++++++++++++++++++++++++++ Src/usart.c | 40 ++++++++++-- Src/usbd_cdc_if.c | 4 ++ Src/usbd_desc.c | 23 +++---- 23 files changed, 937 insertions(+), 36 deletions(-) create mode 100644 CMakeLists.txt create mode 100644 Inc/debug.h create mode 100644 Inc/gex_gateway.h create mode 100644 Inc/minmax.h create mode 100644 Inc/msg_queue.h create mode 100644 Inc/payload_builder.h create mode 100644 Inc/payload_parser.h create mode 100644 Inc/type_coerce.h create mode 100644 Src/debug.c delete mode 100644 Src/freertos.c create mode 100644 Src/gex_gateway.c create mode 100644 Src/msg_queue.c create mode 100644 Src/payload_builder.c create mode 100644 Src/payload_parser.c diff --git a/.gitignore b/.gitignore index 6138ab5..7cf53f1 100644 --- a/.gitignore +++ b/.gitignore @@ -85,3 +85,5 @@ cmake-build-* /disassembly.lst /main.ram.map build/* +.dep/ + diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..aef293a --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,44 @@ +cmake_minimum_required(VERSION 3.9) +project(GEX_NRF) + +set(CMAKE_CXX_STANDARD 11) + +add_definitions( + -DUSE_HAL_DRIVER=1 + -DSTM32F103xB + -D__weak=__attribute__\(\(weak\)\) + -D__packed=__attribute__\(\(__packed__\)\) + -D__COUNTER__=__LINE__ + -DUSBD_SUPPORT_USER_STRING=1 + -DUSE_FULL_ASSERT=1 + -DUSE_FULL_LL_DRIVER=1 +) + +FILE(GLOB_RECURSE SOURCE_FILES + Inc/*.h + Drivers/*.c + Drivers/*.h + Middlewares/*.c + Middlewares/*.h + Src/*.c + Src/*.h + ) + +include_directories( + # System includes folder + /usr/arm-none-eabi/include/ + + # CMSIS + HAL + Drivers/CMSIS/Include + Drivers/CMSIS/Device/ST/STM32F1xx/Include + Drivers/STM32F1xx_HAL_Driver/Inc + Drivers/STM32F1xx_HAL_Driver/Inc/Legacy + + # USB Library + Middlewares/ST/STM32_USB_Device_Library/Class/CDC/Inc + Middlewares/ST/STM32_USB_Device_Library/Core/Inc + + Inc +) + +add_executable(main ${SOURCE_FILES}) diff --git a/Inc/debug.h b/Inc/debug.h new file mode 100644 index 0000000..ab89928 --- /dev/null +++ b/Inc/debug.h @@ -0,0 +1,10 @@ +// +// Created by MightyPork on 2018/03/31. +// + +#ifndef GEX_NRF_DEBUG_H +#define GEX_NRF_DEBUG_H + +void dbg(const char *format, ...); + +#endif //GEX_NRF_DEBUG_H diff --git a/Inc/gex_gateway.h b/Inc/gex_gateway.h new file mode 100644 index 0000000..b6c96dd --- /dev/null +++ b/Inc/gex_gateway.h @@ -0,0 +1,11 @@ +// +// Created by MightyPork on 2018/03/31. +// + +#ifndef GEX_NRF_GEX_GATEWAY_H +#define GEX_NRF_GEX_GATEWAY_H + +#include "main.h" +void gw_process(void); + +#endif //GEX_NRF_GEX_GATEWAY_H diff --git a/Inc/main.h b/Inc/main.h index 2561f16..71c5ea8 100644 --- a/Inc/main.h +++ b/Inc/main.h @@ -64,6 +64,9 @@ #include "stm32f1xx_ll_usart.h" #include "stm32f1xx.h" #include "stm32f1xx_ll_gpio.h" +#include +#include +#include /* USER CODE BEGIN Includes */ diff --git a/Inc/minmax.h b/Inc/minmax.h new file mode 100644 index 0000000..44b9842 --- /dev/null +++ b/Inc/minmax.h @@ -0,0 +1,16 @@ +// +// Created by MightyPork on 2018/04/01. +// + +#ifndef GEX_NRF_MINMAX_H +#define GEX_NRF_MINMAX_H + +#ifndef MAX +#define MAX(a,b) ((a) > (b) ? (a) : (b)) +#endif + +#ifndef MIN +#define MIN(a,b) ((a) > (b) ? (b) : (a)) +#endif + +#endif //GEX_NRF_MINMAX_H diff --git a/Inc/msg_queue.h b/Inc/msg_queue.h new file mode 100644 index 0000000..df64232 --- /dev/null +++ b/Inc/msg_queue.h @@ -0,0 +1,37 @@ +// +// Created by MightyPork on 2018/03/31. +// + +#ifndef GEX_NRF_MSG_QUEUE_H +#define GEX_NRF_MSG_QUEUE_H + +#include +#include + +#define MQ_LEN 16 +#define MQ_SLOT_LEN 64 + +typedef struct { + uint8_t packet[MQ_SLOT_LEN]; +} MQSlot; + +typedef struct { + MQSlot slots[MQ_LEN]; + volatile uint32_t lr; + volatile uint32_t nw; +} MQueue; + +extern MQueue usb_rxq; +extern MQueue usb_txq; + +void mq_init(MQueue *mq); + +bool mq_can_post(MQueue *mq); + +bool mq_post(MQueue *mq, const uint8_t *buffer, uint32_t len); + +bool mq_can_read(MQueue *mq); + +bool mq_read(MQueue *mq, uint8_t *buffer); + +#endif //GEX_NRF_MSG_QUEUE_H diff --git a/Inc/payload_builder.h b/Inc/payload_builder.h new file mode 100644 index 0000000..e4d6568 --- /dev/null +++ b/Inc/payload_builder.h @@ -0,0 +1,110 @@ +#ifndef PAYLOAD_BUILDER_H +#define PAYLOAD_BUILDER_H + +/** + * PayloadBuilder, part of the TinyFrame utilities collection + * + * (c) Ondřej Hruška, 2014-2017. MIT license. + * + * The builder supports big and little endian which is selected when + * initializing it or by accessing the bigendian struct field. + * + * This module helps you with building payloads (not only for TinyFrame) + * + * The builder performs bounds checking and calls the provided handler when + * the requested write wouldn't fit. Use the handler to realloc / flush the buffer + * or report an error. + */ + +#include +#include +#include +#include "type_coerce.h" + +typedef struct PayloadBuilder_ PayloadBuilder; + +/** + * Full buffer handler. + * + * 'needed' more bytes should be written but the end of the buffer was reached. + * + * Return true if the problem was solved (e.g. buffer was flushed and the + * 'current' pointer moved to the beginning). + * + * If false is returned, the 'ok' flag on the struct is set to false + * and all following writes are discarded. + */ +typedef bool (*pb_full_handler)(PayloadBuilder *pb, uint32_t needed); + +struct PayloadBuilder_ { + uint8_t *start; //!< Pointer to the beginning of the buffer + uint8_t *current; //!< Pointer to the next byte to be read + uint8_t *end; //!< Pointer to the end of the buffer (start + length) + pb_full_handler full_handler; //!< Callback for buffer overrun + bool bigendian; //!< Flag to use big-endian parsing + bool ok; //!< Indicates that all reads were successful +}; + +// --- initializer helper macros --- + +/** Start the builder. */ +#define pb_start_e(buf, capacity, bigendian, full_handler) ((PayloadBuilder){buf, buf, (buf)+(capacity), full_handler, bigendian, 1}) + +/** Start the builder in big-endian mode */ +#define pb_start_be(buf, capacity, full_handler) pb_start_e(buf, capacity, 1, full_handler) + +/** Start the builder in little-endian mode */ +#define pb_start_le(buf, capacity, full_handler) pb_start_e(buf, capacity, 0, full_handler) + +/** Start the parser in little-endian mode (default) */ +#define pb_start(buf, capacity, full_handler) pb_start_le(buf, capacity, full_handler) + +// --- utilities --- + +/** Get already used bytes count */ +#define pb_length(pb) ((pb)->current - (pb)->start) + +/** Reset the current pointer to start */ +#define pb_rewind(pb) do { pb->current = pb->start; } while (0) + + +/** Write from a buffer */ +bool pb_buf(PayloadBuilder *pb, const uint8_t *buf, uint32_t len); + +/** Write a zero terminated string */ +bool pb_string(PayloadBuilder *pb, const char *str); + +/** Write uint8_t to the buffer */ +bool pb_u8(PayloadBuilder *pb, uint8_t byte); + +/** Write boolean to the buffer. */ +static inline bool pb_bool(PayloadBuilder *pb, bool b) +{ + return pb_u8(pb, (uint8_t) b); +} + +/** Write uint16_t to the buffer. */ +bool pb_u16(PayloadBuilder *pb, uint16_t word); + +/** Write uint32_t to the buffer. */ +bool pb_u32(PayloadBuilder *pb, uint32_t word); + +/** Write int8_t to the buffer. */ +bool pb_i8(PayloadBuilder *pb, int8_t byte); + +/** Write char (int8_t) to the buffer. */ +static inline bool pb_char(PayloadBuilder *pb, char c) +{ + return pb_i8(pb, c); +} + +/** Write int16_t to the buffer. */ +bool pb_i16(PayloadBuilder *pb, int16_t word); + +/** Write int32_t to the buffer. */ +bool pb_i32(PayloadBuilder *pb, int32_t word); + +/** Write 4-byte float to the buffer. */ +bool pb_float(PayloadBuilder *pb, float f); + +#endif // PAYLOAD_BUILDER_H diff --git a/Inc/payload_parser.h b/Inc/payload_parser.h new file mode 100644 index 0000000..cddab1b --- /dev/null +++ b/Inc/payload_parser.h @@ -0,0 +1,143 @@ +#ifndef PAYLOAD_PARSER_H +#define PAYLOAD_PARSER_H + +/** + * PayloadParser, part of the TinyFrame utilities collection + * + * (c) Ondřej Hruška, 2016-2017. MIT license. + * + * This module helps you with parsing payloads (not only from TinyFrame). + * + * The parser supports big and little-endian which is selected when + * initializing it or by accessing the bigendian struct field. + * + * The parser performs bounds checking and calls the provided handler when + * the requested read doesn't have enough data. Use the callback to take + * appropriate action, e.g. report an error. + * + * If the handler function is not defined, the pb->ok flag is set to false + * (use this to check for success), and further reads won't have any effect + * and always result in 0 or empty array. + */ + +#include +#include +#include +#include "type_coerce.h" + +typedef struct PayloadParser_ PayloadParser; + +/** + * Empty buffer handler. + * + * 'needed' more bytes should be read but the end was reached. + * + * Return true if the problem was solved (e.g. new data loaded into + * the buffer and the 'current' pointer moved to the beginning). + * + * If false is returned, the 'ok' flag on the struct is set to false + * and all following reads will fail / return 0. + */ +typedef bool (*pp_empty_handler)(PayloadParser *pp, uint32_t needed); + +struct PayloadParser_ { + uint8_t *start; //!< Pointer to the beginning of the buffer + uint8_t *current; //!< Pointer to the next byte to be read + uint8_t *end; //!< Pointer to the end of the buffer (start + length) + pp_empty_handler empty_handler; //!< Callback for buffer underrun + bool bigendian; //!< Flag to use big-endian parsing + bool ok; //!< Indicates that all reads were successful +}; + +// --- initializer helper macros --- + +/** Start the parser. */ +#define pp_start_e(buf, length, bigendian, empty_handler) ((PayloadParser){buf, buf, (buf)+(length), empty_handler, bigendian, 1}) + +/** Start the parser in big-endian mode */ +#define pp_start_be(buf, length, empty_handler) pp_start_e(buf, length, 1, empty_handler) + +/** Start the parser in little-endian mode */ +#define pp_start_le(buf, length, empty_handler) pp_start_e(buf, length, 0, empty_handler) + +/** Start the parser in little-endian mode (default) */ +#define pp_start(buf, length, empty_handler) pp_start_le(buf, length, empty_handler) + +// --- utilities --- + +/** Get remaining length */ +#define pp_length(pp) ((pp)->end - (pp)->current) + +/** Reset the current pointer to start */ +#define pp_rewind(pp) do { pp->current = pp->start; } while (0) + + +/** + * @brief Get the remainder of the buffer. + * + * Returns NULL and sets 'length' to 0 if there are no bytes left. + * + * @param pp + * @param length : here the buffer length will be stored. NULL to do not store. + * @return the remaining portion of the input buffer + */ +const uint8_t *pp_tail(PayloadParser *pp, uint32_t *length); + +/** Read uint8_t from the payload. */ +uint8_t pp_u8(PayloadParser *pp); + +/** Read bool from the payload. */ +static inline int8_t pp_bool(PayloadParser *pp) +{ + return pp_u8(pp) != 0; +} + +/** Skip bytes */ +void pp_skip(PayloadParser *pp, uint32_t num); + +/** Read uint16_t from the payload. */ +uint16_t pp_u16(PayloadParser *pp); + +/** Read uint32_t from the payload. */ +uint32_t pp_u32(PayloadParser *pp); + +/** Read int8_t from the payload. */ +int8_t pp_i8(PayloadParser *pp); + +/** Read char (int8_t) from the payload. */ +static inline int8_t pp_char(PayloadParser *pp) +{ + return pp_i8(pp); +} + +/** Read int16_t from the payload. */ +int16_t pp_i16(PayloadParser *pp); + +/** Read int32_t from the payload. */ +int32_t pp_i32(PayloadParser *pp); + +/** Read 4-byte float from the payload. */ +float pp_float(PayloadParser *pp); + +/** + * Parse a zero-terminated string + * + * @param pp - parser + * @param buffer - target buffer + * @param maxlen - buffer size + * @return actual number of bytes, excluding terminator + */ +uint32_t pp_string(PayloadParser *pp, char *buffer, uint32_t maxlen); + +/** + * Parse a buffer + * + * @param pp - parser + * @param buffer - target buffer + * @param maxlen - buffer size + * @return actual number of bytes, excluding terminator + */ +uint32_t pp_buf(PayloadParser *pp, uint8_t *buffer, uint32_t maxlen); + + +#endif // PAYLOAD_PARSER_H diff --git a/Inc/type_coerce.h b/Inc/type_coerce.h new file mode 100644 index 0000000..2e4d0c6 --- /dev/null +++ b/Inc/type_coerce.h @@ -0,0 +1,32 @@ +#ifndef TYPE_COERCE_H +#define TYPE_COERCE_H + +/** + * Structs for conversion between types, + * part of the TinyFrame utilities collection + * + * (c) Ondřej Hruška, 2016-2017. MIT license. + * + * This is a support header file for PayloadParser and PayloadBuilder. + */ + +#include +#include + +union conv8 { + uint8_t u8; + int8_t i8; +}; + +union conv16 { + uint16_t u16; + int16_t i16; +}; + +union conv32 { + uint32_t u32; + int32_t i32; + float f32; +}; + +#endif // TYPE_COERCE_H diff --git a/Inc/usart.h b/Inc/usart.h index a27fd01..ff7ad86 100644 --- a/Inc/usart.h +++ b/Inc/usart.h @@ -81,6 +81,9 @@ void MX_USART1_UART_Init(void); /* USER CODE BEGIN Prototypes */ +void MX_USART_DmaWaitReady(void); +void MX_USART_DmaSend(uint8_t *buffer, uint32_t length); + /* USER CODE END Prototypes */ #ifdef __cplusplus diff --git a/Inc/usbd_conf.h b/Inc/usbd_conf.h index c26cee0..0348d00 100644 --- a/Inc/usbd_conf.h +++ b/Inc/usbd_conf.h @@ -95,13 +95,13 @@ /*---------- -----------*/ #define USBD_MAX_NUM_CONFIGURATION 1 /*---------- -----------*/ -#define USBD_MAX_STR_DESC_SIZ 64 +#define USBD_MAX_STR_DESC_SIZ 128 /*---------- -----------*/ -#define USBD_SUPPORT_USER_STRING 0 +#define USBD_SUPPORT_USER_STRING 1 /*---------- -----------*/ #define USBD_DEBUG_LEVEL 0 /*---------- -----------*/ -#define USBD_SELF_POWERED 1 +#define USBD_SELF_POWERED 0 /*---------- -----------*/ #define MAX_STATIC_ALLOC_SIZE 512 diff --git a/Makefile b/Makefile index 955cbcc..52f8b0c 100644 --- a/Makefile +++ b/Makefile @@ -62,6 +62,11 @@ BUILD_DIR = build # C sources C_SOURCES = \ Src/gpio.c \ +Src/debug.c \ +Src/msg_queue.c \ +Src/gex_gateway.c \ +Src/payload_builder.c \ +Src/payload_parser.c \ Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_tim.c \ Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_rcc.c \ Drivers/STM32F1xx_HAL_Driver/Src/stm32f1xx_hal_cortex.c \ @@ -203,24 +208,31 @@ vpath %.c $(sort $(dir $(C_SOURCES))) OBJECTS += $(addprefix $(BUILD_DIR)/,$(notdir $(ASM_SOURCES:.s=.o))) vpath %.s $(sort $(dir $(ASM_SOURCES))) -$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR) - $(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@ +$(BUILD_DIR)/%.o: %.c Makefile | $(BUILD_DIR) + @printf "CC $<\n" + @$(CC) -c $(CFLAGS) -Wa,-a,-ad,-alms=$(BUILD_DIR)/$(notdir $(<:.c=.lst)) $< -o $@ $(BUILD_DIR)/%.o: %.s Makefile | $(BUILD_DIR) - $(AS) -c $(CFLAGS) $< -o $@ + @printf "CC $<\n" + @$(AS) -c $(CFLAGS) $< -o $@ $(BUILD_DIR)/$(TARGET).elf: $(OBJECTS) Makefile - $(CC) $(OBJECTS) $(LDFLAGS) -o $@ - $(SZ) $@ + @printf "Linking...\n" + @$(CC) $(OBJECTS) $(LDFLAGS) -o $@ + @$(SZ) $@ $(BUILD_DIR)/%.hex: $(BUILD_DIR)/%.elf | $(BUILD_DIR) - $(HEX) $< $@ + @$(HEX) $< $@ $(BUILD_DIR)/%.bin: $(BUILD_DIR)/%.elf | $(BUILD_DIR) - $(BIN) $< $@ + @$(BIN) $< $@ $(BUILD_DIR): - mkdir -p $@ + @mkdir -p $@ + +flash: $(BUILD_DIR)/$(TARGET).bin + @printf " FLASH $<\n" + @st-flash write $< 0x8000000 ####################################### # clean up diff --git a/Src/debug.c b/Src/debug.c new file mode 100644 index 0000000..b9f9b1d --- /dev/null +++ b/Src/debug.c @@ -0,0 +1,35 @@ +// +// Created by MightyPork on 2018/03/31. +// + +#include "debug.h" +#include "main.h" +#include +#include "usart.h" + +#define BUFLEN 128 +static char buff[BUFLEN]; +void dbg(const char *format, ...) +{ + MX_USART_DmaWaitReady(); + + va_list args; + va_start (args, format); + uint32_t count = (uint32_t) vsprintf (buff, format, args); + if (count < BUFLEN - 2) { + buff[count++] = '\r'; + buff[count++] = '\n'; + buff[count] = 0; + } + va_end (args); + + MX_USART_DmaSend((uint8_t *) buff, count); + +// char c; +// char* ptr = buff; +// while ((c = *ptr++) != 0) { +// txchar(c); +// } +// txchar('\r'); +// txchar('\n'); +} diff --git a/Src/freertos.c b/Src/freertos.c deleted file mode 100644 index e69de29..0000000 diff --git a/Src/gex_gateway.c b/Src/gex_gateway.c new file mode 100644 index 0000000..c4cff3d --- /dev/null +++ b/Src/gex_gateway.c @@ -0,0 +1,111 @@ +// +// Created by MightyPork on 2018/03/31. +// + +#include +#include "debug.h" +#include "msg_queue.h" +#include "gex_gateway.h" +#include "main.h" +#include "minmax.h" +#include "payload_parser.h" + +// USB RX +enum URX_STATE { + URXS_IDLE = 0, + URXS_MSG4SLAVE = 1, +}; + +#define MAX_FRAME_LEN 512 + +static enum URX_STATE urx_state = URXS_IDLE; +static uint32_t msg4slave_len = 0; // total len to be collected +static uint32_t msg4slave_already = 0; // already collected len +static uint8_t msg4slave[MAX_FRAME_LEN]; // equal buffer size in GEX +static uint8_t msg4slave_addr = 0; +static uint8_t msg4slave_cksum = 0; + +#define MAGIC_GW_COMMAND 0x47U // 'G' + +enum GW_CMD { + CMD_GET_ID = 'i', // 105 + CMD_MSG4SLAVE = 'm', // 109 +}; + +void respond_gw_id(); // TODO impl + +void start_slave_cmd(uint8_t slave_addr, uint16_t frame_len, uint8_t cksum) +{ + msg4slave_len = frame_len; + msg4slave_already = 0; + msg4slave_addr = slave_addr; + msg4slave_cksum = cksum; +} + +/** called from the main loop, periodically */ +void gw_process(void) +{ + static uint8_t buffer[MQ_SLOT_LEN]; + while (mq_read(&usb_rxq, buffer)) { // greedy - handle as many as possible + if (urx_state == URXS_IDLE) { + PayloadParser pp = pp_start(buffer, MQ_SLOT_LEN, NULL); + + // handle binary commands for the gateway + + // magic twice, one inverted - denotes a gateway command + uint16_t magic1 = pp_u8(&pp); + uint16_t magic2 = pp_u8(&pp); + if (magic1 == MAGIC_GW_COMMAND && magic2 == ~MAGIC_GW_COMMAND) { + // third byte is the command code + switch (pp_u8(&pp)) { + case CMD_GET_ID: + respond_gw_id(); + break; + + case CMD_MSG4SLAVE:; + uint8_t slave_addr = pp_u8(&pp); + uint16_t frame_len = pp_u16(&pp); + uint8_t cksum = pp_u8(&pp); + + if (frame_len > MAX_FRAME_LEN) { + dbg("Frame too big!"); + break; + } + + start_slave_cmd(slave_addr, frame_len, cksum); + dbg("Collecting frame for slave %02x: %d bytes", (int)slave_addr, (int)frame_len); + urx_state = URXS_MSG4SLAVE; + break; + } + } else { + // Bad frame?? + dbg("Bad USB frame, starts %x", buffer[0]); + } + } + else if (urx_state == URXS_MSG4SLAVE) { + uint32_t wanted = MIN(msg4slave_len-msg4slave_already, MQ_SLOT_LEN); + memcpy(&msg4slave[msg4slave_already], buffer, wanted); + msg4slave_already += wanted; + + if (wanted < MQ_SLOT_LEN) { + // this was the end + uint8_t ck = 0; + for (int i = 0; i < msg4slave_len; i++) { + ck ^= msg4slave[i]; + } + ck = ~ck; + + if (ck != msg4slave_cksum) { + dbg("Checksum mismatch!"); + } + else { + dbg("Verified, sending a %d B frame to slave.", (int) msg4slave_len); + // TODO send to slave + } + + urx_state = URXS_IDLE; + } + } + } +} + diff --git a/Src/main.c b/Src/main.c index 190136a..da26f91 100644 --- a/Src/main.c +++ b/Src/main.c @@ -47,6 +47,7 @@ ****************************************************************************** */ /* Includes ------------------------------------------------------------------*/ +#include #include "main.h" #include "stm32f1xx_hal.h" #include "dma.h" @@ -54,6 +55,7 @@ #include "usart.h" #include "usb_device.h" #include "gpio.h" +#include "debug.h" /* USER CODE BEGIN Includes */ @@ -105,25 +107,32 @@ int main(void) /* USER CODE END SysInit */ + LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOC); + LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOD); + LL_APB2_GRP1_EnableClock(LL_APB2_GRP1_PERIPH_GPIOA); + /* Initialize all configured peripherals */ - MX_GPIO_Init(); - MX_DMA_Init(); - MX_USB_DEVICE_Init(); - MX_SPI1_Init(); - MX_USART1_UART_Init(); + MX_GPIO_Init(); + MX_DMA_Init(); + MX_USB_DEVICE_Init(); + MX_SPI1_Init(); + MX_USART1_UART_Init(); /* USER CODE BEGIN 2 */ /* USER CODE END 2 */ + dbg("Main loop starts."); /* Infinite loop */ /* USER CODE BEGIN WHILE */ + int cnt = 0; while (1) { + if (cnt++ > 10000) { + GPIOC->ODR ^= (1 << 13); + cnt = 0; + } - /* USER CODE END WHILE */ - - /* USER CODE BEGIN 3 */ - + gw_process(); } /* USER CODE END 3 */ diff --git a/Src/msg_queue.c b/Src/msg_queue.c new file mode 100644 index 0000000..f96d0a5 --- /dev/null +++ b/Src/msg_queue.c @@ -0,0 +1,67 @@ +// +// Created by MightyPork on 2018/03/31. +// + +#include "main.h" +#include +#include +#include "debug.h" +#include "msg_queue.h" + +// the two USB messaging queues +MQueue usb_rxq; +MQueue usb_txq; + +void mq_init(MQueue *mq) +{ + mq->lr = MQ_LEN-1; +} + +bool mq_can_post(MQueue *mq) +{ + return mq->nw != mq->lr; +} + +bool mq_post(MQueue *mq, const uint8_t *buffer, uint32_t len) +{ + if (!mq_can_post(mq)) { + dbg("FULL!"); + return false; + } + if (len >= MQ_SLOT_LEN) { + dbg("mq post too long!"); + return false; + } + + memcpy(mq->slots[mq->nw].packet, buffer, len); + // pad with zeros + if (len < MQ_SLOT_LEN) memset(mq->slots[mq->nw].packet+len, 0, MQ_SLOT_LEN - len); + + mq->nw++; + if (mq->nw == MQ_LEN) mq->nw = 0; + + return true; +} + +bool mq_can_read(MQueue *mq) +{ + // handle LR at the end, NW at 0 (initial state) + if (mq->lr == MQ_LEN-1) return mq->nw > 0; + // wrap-around - if LR not at the end, always have some to read + if (mq->nw <= mq->lr) return true; + // forward - one between + return mq->lr < mq->nw - 1; +} + +bool mq_read(MQueue *mq, uint8_t *buffer) +{ + if (!mq_can_read(mq)) { + return false; + } + + mq->lr++; + if (mq->lr == MQ_LEN) mq->lr = 0; + memcpy(buffer, mq->slots[mq->lr].packet, MQ_SLOT_LEN); + + return true; +} diff --git a/Src/payload_builder.c b/Src/payload_builder.c new file mode 100644 index 0000000..d228d80 --- /dev/null +++ b/Src/payload_builder.c @@ -0,0 +1,100 @@ +#include +#include "payload_builder.h" + +#define pb_check_capacity(pb, needed) \ + if ((pb)->current + (needed) > (pb)->end) { \ + if ((pb)->full_handler == NULL || !(pb)->full_handler(pb, needed)) (pb)->ok = 0; \ + } + +/** Write from a buffer */ +bool pb_buf(PayloadBuilder *pb, const uint8_t *buf, uint32_t len) +{ + pb_check_capacity(pb, len); + if (!pb->ok) return false; + + memcpy(pb->current, buf, len); + pb->current += len; + return true; +} + +/** Write s zero terminated string */ +bool pb_string(PayloadBuilder *pb, const char *str) +{ + uint32_t len = (uint32_t) strlen(str); + pb_check_capacity(pb, len+1); + if (!pb->ok) return false; + + memcpy(pb->current, str, len+1); + pb->current += len+1; + return true; +} + +/** Write uint8_t to the buffer */ +bool pb_u8(PayloadBuilder *pb, uint8_t byte) +{ + pb_check_capacity(pb, 1); + if (!pb->ok) return false; + + *pb->current++ = byte; + return true; +} + +/** Write uint16_t to the buffer. */ +bool pb_u16(PayloadBuilder *pb, uint16_t word) +{ + pb_check_capacity(pb, 2); + if (!pb->ok) return false; + + if (pb->bigendian) { + *pb->current++ = (uint8_t) ((word >> 8) & 0xFF); + *pb->current++ = (uint8_t) (word & 0xFF); + } else { + *pb->current++ = (uint8_t) (word & 0xFF); + *pb->current++ = (uint8_t) ((word >> 8) & 0xFF); + } + return true; +} + +/** Write uint32_t to the buffer. */ +bool pb_u32(PayloadBuilder *pb, uint32_t word) +{ + pb_check_capacity(pb, 4); + if (!pb->ok) return false; + + if (pb->bigendian) { + *pb->current++ = (uint8_t) ((word >> 24) & 0xFF); + *pb->current++ = (uint8_t) ((word >> 16) & 0xFF); + *pb->current++ = (uint8_t) ((word >> 8) & 0xFF); + *pb->current++ = (uint8_t) (word & 0xFF); + } else { + *pb->current++ = (uint8_t) (word & 0xFF); + *pb->current++ = (uint8_t) ((word >> 8) & 0xFF); + *pb->current++ = (uint8_t) ((word >> 16) & 0xFF); + *pb->current++ = (uint8_t) ((word >> 24) & 0xFF); + } + return true; +} + +/** Write int8_t to the buffer. */ +bool pb_i8(PayloadBuilder *pb, int8_t byte) +{ + return pb_u8(pb, ((union conv8){.i8 = byte}).u8); +} + +/** Write int16_t to the buffer. */ +bool pb_i16(PayloadBuilder *pb, int16_t word) +{ + return pb_u16(pb, ((union conv16){.i16 = word}).u16); +} + +/** Write int32_t to the buffer. */ +bool pb_i32(PayloadBuilder *pb, int32_t word) +{ + return pb_u32(pb, ((union conv32){.i32 = word}).u32); +} + +/** Write 4-byte float to the buffer. */ +bool pb_float(PayloadBuilder *pb, float f) +{ + return pb_u32(pb, ((union conv32){.f32 = f}).u32); +} diff --git a/Src/payload_parser.c b/Src/payload_parser.c new file mode 100644 index 0000000..ca80605 --- /dev/null +++ b/Src/payload_parser.c @@ -0,0 +1,121 @@ +#include "payload_parser.h" + +#define pp_check_capacity(pp, needed) \ + if ((pp)->current + (needed) > (pp)->end) { \ + if ((pp)->empty_handler == NULL || !(pp)->empty_handler(pp, needed)) {(pp)->ok = 0;} ; \ + } + +void pp_skip(PayloadParser *pp, uint32_t num) +{ + pp->current += num; +} + +uint8_t pp_u8(PayloadParser *pp) +{ + pp_check_capacity(pp, 1); + if (!pp->ok) return 0; + + return *pp->current++; +} + +uint16_t pp_u16(PayloadParser *pp) +{ + pp_check_capacity(pp, 2); + if (!pp->ok) return 0; + + uint16_t x = 0; + + if (pp->bigendian) { + x |= *pp->current++ << 8; + x |= *pp->current++; + } else { + x |= *pp->current++; + x |= *pp->current++ << 8; + } + return x; +} + +uint32_t pp_u32(PayloadParser *pp) +{ + pp_check_capacity(pp, 4); + if (!pp->ok) return 0; + + uint32_t x = 0; + + if (pp->bigendian) { + x |= (uint32_t) (*pp->current++ << 24); + x |= (uint32_t) (*pp->current++ << 16); + x |= (uint32_t) (*pp->current++ << 8); + x |= *pp->current++; + } else { + x |= *pp->current++; + x |= (uint32_t) (*pp->current++ << 8); + x |= (uint32_t) (*pp->current++ << 16); + x |= (uint32_t) (*pp->current++ << 24); + } + return x; +} + +const uint8_t *pp_tail(PayloadParser *pp, uint32_t *length) +{ + int32_t len = (int) (pp->end - pp->current); + if (!pp->ok || len <= 0) { + if (length != NULL) *length = 0; + return NULL; + } + + if (length != NULL) { + *length = (uint32_t) len; + } + + return pp->current; +} + +/** Read int8_t from the payload. */ +int8_t pp_i8(PayloadParser *pp) +{ + return ((union conv8) {.u8 = pp_u8(pp)}).i8; +} + +/** Read int16_t from the payload. */ +int16_t pp_i16(PayloadParser *pp) +{ + return ((union conv16) {.u16 = pp_u16(pp)}).i16; +} + +/** Read int32_t from the payload. */ +int32_t pp_i32(PayloadParser *pp) +{ + return ((union conv32) {.u32 = pp_u32(pp)}).i32; +} + +/** Read 4-byte float from the payload. */ +float pp_float(PayloadParser *pp) +{ + return ((union conv32) {.u32 = pp_u32(pp)}).f32; +} + +/** Read a zstring */ +uint32_t pp_string(PayloadParser *pp, char *buffer, uint32_t maxlen) +{ + pp_check_capacity(pp, 1); + uint32_t len = 0; + while (len < maxlen-1 && pp->current != pp->end) { + char c = *buffer++ = *pp->current++; + if (c == 0) break; + len++; + } + *buffer = 0; + return len; +} + +/** Read a buffer */ +uint32_t pp_buf(PayloadParser *pp, uint8_t *buffer, uint32_t maxlen) +{ + uint32_t len = 0; + while (len < maxlen && pp->current != pp->end) { + *buffer++ = *pp->current++; + len++; + } + return len; +} diff --git a/Src/usart.c b/Src/usart.c index f486c6e..187e06c 100644 --- a/Src/usart.c +++ b/Src/usart.c @@ -49,6 +49,7 @@ /* Includes ------------------------------------------------------------------*/ #include "usart.h" +#include #include "gpio.h" #include "dma.h" @@ -77,12 +78,13 @@ void MX_USART1_UART_Init(void) GPIO_InitStruct.OutputType = LL_GPIO_OUTPUT_PUSHPULL; LL_GPIO_Init(GPIOA, &GPIO_InitStruct); - GPIO_InitStruct.Pin = LL_GPIO_PIN_10; - GPIO_InitStruct.Mode = LL_GPIO_MODE_FLOATING; - LL_GPIO_Init(GPIOA, &GPIO_InitStruct); + // we don't use Rx +// GPIO_InitStruct.Pin = LL_GPIO_PIN_10; +// GPIO_InitStruct.Mode = LL_GPIO_MODE_FLOATING; +// LL_GPIO_Init(GPIOA, &GPIO_InitStruct); /* USART1 DMA Init */ - + /* USART1_TX Init */ LL_DMA_SetDataTransferDirection(DMA1, LL_DMA_CHANNEL_4, LL_DMA_DIRECTION_MEMORY_TO_PERIPH); @@ -98,6 +100,9 @@ void MX_USART1_UART_Init(void) LL_DMA_SetMemorySize(DMA1, LL_DMA_CHANNEL_4, LL_DMA_MDATAALIGN_BYTE); + // the USART address + LL_DMA_SetPeriphAddress(DMA1, LL_DMA_CHANNEL_4, LL_USART_DMA_GetRegAddr(USART1)); + USART_InitStruct.BaudRate = 115200; USART_InitStruct.DataWidth = LL_USART_DATAWIDTH_8B; USART_InitStruct.StopBits = LL_USART_STOPBITS_1; @@ -109,10 +114,35 @@ void MX_USART1_UART_Init(void) LL_USART_ConfigAsyncMode(USART1); LL_USART_Enable(USART1); - } + /* USER CODE BEGIN 1 */ +static volatile bool usart_dma_first = true; +/** Wait for the last DMA request to finish - so the buffer can be re-filled with new content */ +void MX_USART_DmaWaitReady(void) +{ + if (!usart_dma_first) { + // wait for the last transfer to finish + while (!LL_DMA_IsActiveFlag_TC4(DMA1)); + } + + LL_USART_DisableDMAReq_TX(USART1); +} + +/** Send new content using DMA */ +void MX_USART_DmaSend(uint8_t *buffer, uint32_t length) +{ + usart_dma_first = false; + + LL_USART_EnableDMAReq_TX(USART1); + + LL_DMA_DisableChannel(DMA1, LL_DMA_CHANNEL_4); + LL_DMA_ClearFlag_TC4(DMA1); + LL_DMA_SetMemoryAddress(DMA1, LL_DMA_CHANNEL_4, (uint32_t) buffer); + LL_DMA_SetDataLength(DMA1, LL_DMA_CHANNEL_4, length); + LL_DMA_EnableChannel(DMA1, LL_DMA_CHANNEL_4); +} /* USER CODE END 1 */ diff --git a/Src/usbd_cdc_if.c b/Src/usbd_cdc_if.c index daa2db6..5a1bebd 100644 --- a/Src/usbd_cdc_if.c +++ b/Src/usbd_cdc_if.c @@ -48,6 +48,7 @@ */ /* Includes ------------------------------------------------------------------*/ +#include #include "usbd_cdc_if.h" /* USER CODE BEGIN INCLUDE */ @@ -293,6 +294,9 @@ static int8_t CDC_Receive_FS(uint8_t* Buf, uint32_t *Len) /* USER CODE BEGIN 6 */ USBD_CDC_SetRxBuffer(&hUsbDeviceFS, &Buf[0]); USBD_CDC_ReceivePacket(&hUsbDeviceFS); + + // + return (USBD_OK); /* USER CODE END 6 */ } diff --git a/Src/usbd_desc.c b/Src/usbd_desc.c index 64b076a..8f2f6a7 100644 --- a/Src/usbd_desc.c +++ b/Src/usbd_desc.c @@ -48,6 +48,7 @@ */ /* Includes ------------------------------------------------------------------*/ +#include #include "usbd_core.h" #include "usbd_desc.h" #include "usbd_conf.h" @@ -91,10 +92,10 @@ * @{ */ -#define USBD_VID 4617 +#define USBD_VID 0x1209 #define USBD_LANGID_STRING 1033 -#define USBD_MANUFACTURER_STRING "STMicroelectronics" -#define USBD_PID_FS 19553 +#define USBD_MANUFACTURER_STRING "MightyPork" +#define USBD_PID_FS 0x4c61 #define USBD_PRODUCT_STRING_FS "GEX wireless dongle" #define USBD_SERIALNUMBER_STRING_FS "00000000001A" #define USBD_CONFIGURATION_STRING_FS "CDC Config" @@ -290,14 +291,14 @@ uint8_t * USBD_FS_ManufacturerStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *l */ uint8_t * USBD_FS_SerialStrDescriptor(USBD_SpeedTypeDef speed, uint16_t *length) { - if(speed == USBD_SPEED_HIGH) - { - USBD_GetString((uint8_t *)USBD_SERIALNUMBER_STRING_FS, USBD_StrDesc, length); - } - else - { - USBD_GetString((uint8_t *)USBD_SERIALNUMBER_STRING_FS, USBD_StrDesc, length); - } + char buff[27]; + sprintf(buff, "%08"PRIX32"-%08"PRIX32"-%08"PRIX32, + LL_GetUID_Word0(), + LL_GetUID_Word1(), + LL_GetUID_Word2() + ); + + USBD_GetString ((uint8_t *) &buff[0], USBD_StrDesc, length); return USBD_StrDesc; }