wip rx handler
This commit is contained in:
@@ -85,3 +85,5 @@ cmake-build-*
|
||||
/disassembly.lst
|
||||
/main.ram.map
|
||||
build/*
|
||||
.dep/
|
||||
|
||||
|
||||
@@ -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})
|
||||
+10
@@ -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
|
||||
@@ -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
|
||||
@@ -64,6 +64,9 @@
|
||||
#include "stm32f1xx_ll_usart.h"
|
||||
#include "stm32f1xx.h"
|
||||
#include "stm32f1xx_ll_gpio.h"
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <inttypes.h>
|
||||
|
||||
/* USER CODE BEGIN Includes */
|
||||
|
||||
|
||||
@@ -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
|
||||
@@ -0,0 +1,37 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/03/31.
|
||||
//
|
||||
|
||||
#ifndef GEX_NRF_MSG_QUEUE_H
|
||||
#define GEX_NRF_MSG_QUEUE_H
|
||||
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#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
|
||||
@@ -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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#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
|
||||
@@ -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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <stdbool.h>
|
||||
#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
|
||||
@@ -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 <stdint.h>
|
||||
#include <stddef.h>
|
||||
|
||||
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
|
||||
@@ -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
|
||||
|
||||
+3
-3
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/03/31.
|
||||
//
|
||||
|
||||
#include "debug.h"
|
||||
#include "main.h"
|
||||
#include <stdarg.h>
|
||||
#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');
|
||||
}
|
||||
@@ -0,0 +1,111 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/03/31.
|
||||
//
|
||||
|
||||
#include <string.h>
|
||||
#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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+18
-9
@@ -47,6 +47,7 @@
|
||||
******************************************************************************
|
||||
*/
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include <gex_gateway.h>
|
||||
#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 */
|
||||
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
//
|
||||
// Created by MightyPork on 2018/03/31.
|
||||
//
|
||||
|
||||
#include "main.h"
|
||||
#include <stdbool.h>
|
||||
#include <string.h>
|
||||
#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;
|
||||
}
|
||||
@@ -0,0 +1,100 @@
|
||||
#include <string.h>
|
||||
#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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
+35
-5
@@ -49,6 +49,7 @@
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include "usart.h"
|
||||
#include <stdbool.h>
|
||||
|
||||
#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 */
|
||||
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include <debug.h>
|
||||
#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 */
|
||||
}
|
||||
|
||||
+12
-11
@@ -48,6 +48,7 @@
|
||||
*/
|
||||
|
||||
/* Includes ------------------------------------------------------------------*/
|
||||
#include <inttypes.h>
|
||||
#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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user