parent
							
								
									6338d3d1b4
								
							
						
					
					
						commit
						896df82e27
					
				@ -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}) | 
				
			||||
@ -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
 | 
				
			||||
@ -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
 | 
				
			||||
@ -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; | 
				
			||||
            } | 
				
			||||
        } | 
				
			||||
    } | 
				
			||||
} | 
				
			||||
 | 
				
			||||
@ -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; | 
				
			||||
} | 
				
			||||
					Loading…
					
					
				
		Reference in new issue