blinkenlights working w sonar

This commit is contained in:
2016-05-12 01:32:35 +02:00
parent 11764cbd7a
commit d01e40e174
48 changed files with 4627 additions and 952 deletions
+96
View File
@@ -0,0 +1,96 @@
#include "main.h"
#include "com_fileio.h"
#include "com_iface.h"
#include "utils/str_utils.h"
// Holding fields for ifaces
ComIface *debug_iface = NULL;
ComIface *data_iface = NULL;
// --- File descriptor names ------------------------------
struct name_fd {
const char *name;
const int fd;
};
#define NAME_FD_MAP_LEN 1
/** pre-assigned file descriptors for names */
static const struct name_fd name_fd_map[NAME_FD_MAP_LEN] = {
{FNAME_DLNK, FD_DLNK}
};
// --- Syscalls -------------------------------------------
/**
* @brief Write to a file by file descriptor.
*
* @param fd : open file descriptor
* @param buf : data to write
* @param len : buffer size
* @return number of written bytes
*/
int _write(int fd, const char *buf, int len)
{
switch (fd) {
case FD_STDOUT: return (int)com_tx_block(debug_iface, buf, (size_t)len);
case FD_STDERR: return (int)com_tx_block(debug_iface, buf, (size_t)len);
case FD_DLNK: return (int)com_tx_block(data_iface, buf, (size_t)len);
default:
return 0;
}
}
// For some reason, reading does not work.
#if 0
/**
* @brief Read from a file descriptor
*
* @param fd : file descriptor
* @param buf : destination buffer
* @param len : number of bytes to read
* @return actual number of read bytes
*/
int _read(int fd, char *buf, int len)
{
switch (fd) {
case FD_STDIN: return com_rx_block(debug_iface, buf, len);
case FD_ESP: return com_rx_block(esp_iface, buf, len);
default:
return 0;
}
}
#endif
/**
* @brief Open a file by name.
*
* This stub is called by newlib when fopen is used.
* It returns a pre-assigned file descriptor based
* on the name.
*
* @note
* stdout, stderr, stdin are open implicitly
*
* @param name : file name
* @param flags : file flags (ignored)
* @return file descriptor
*/
int _open(const char *name, int flags, ...)
{
(void)flags;
for (int i = 0; i < NAME_FD_MAP_LEN; i++) {
if (streq(name_fd_map[i].name, name)) {
return name_fd_map[i].fd;
}
}
return -1;
}
+23
View File
@@ -0,0 +1,23 @@
#pragma once
#include "com_iface.h"
/** Debug USART iface */
extern ComIface *debug_iface;
/** ESP8266 com iface */
extern ComIface *data_iface;
/** Do-nothing iface */
extern ComIface *com_iface_noop;
/** File descriptors for use with built-in "files" */
enum {
FD_STDIN = 0,
FD_STDOUT = 1,
FD_STDERR = 2,
FD_DLNK = 3,
};
#define FNAME_DLNK "dlnk"
+179
View File
@@ -0,0 +1,179 @@
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include "com_iface.h"
#include "utils/timebase.h"
// ---- accessor methods ----------------------
bool com_rx_rdy(ComIface *iface)
{
return iface->rx_rdy(iface);
}
bool com_tx_rdy(ComIface *iface)
{
return iface->tx_rdy(iface);
}
bool com_tx_done(ComIface *iface)
{
return iface->tx_done(iface);
}
bool com_tx(ComIface *iface, uint8_t b)
{
return iface->tx(iface, b);
}
bool com_rx(ComIface *iface, uint8_t *b)
{
return iface->rx(iface, (uint8_t*) b);
}
bool com_unrx(ComIface *iface, uint8_t b)
{
if (!iface->unrx) {
return false; // not all may have it implemented
}
return iface->unrx(iface, b);
}
size_t com_tx_block(ComIface *iface, const void *blob, size_t size)
{
return iface->txb(iface, blob, size);
}
size_t com_rx_block(ComIface *iface, void *buf, size_t length)
{
return iface->rxb(iface, buf, length);
}
void com_poll(ComIface *iface)
{
iface->poll(iface);
}
bool com_rx_char(ComIface *iface, char * c)
{
return iface->rx(iface, (uint8_t*) c);
}
bool com_tx_char(ComIface *iface, const char c)
{
return iface->tx(iface, (uint8_t)c);
}
/** Read string, terminate with \0. Returns real read size. */
size_t com_rx_str(ComIface *iface, char* buf, size_t buflen)
{
size_t len = iface->rxb(iface, buf, buflen);
buf[len] = 0; // zero terminator
return len;
}
size_t com_tx_str(ComIface *iface, const char * string)
{
return iface->txb(iface, string, strlen(string));
}
/** Wait for incoming byte */
bool com_rx_wait(ComIface *iface, uint16_t timeout)
{
until_timeout(timeout) {
if (iface->rx_rdy(iface)) return true;
}
return false;
}
/** Wait for tx buf ready */
bool com_tx_rdy_wait(ComIface *iface, uint16_t timeout)
{
until_timeout(timeout) {
if (iface->tx_rdy(iface)) return true;
}
return false;
}
/** Wait for tx complete */
bool com_tx_done_wait(ComIface *iface, uint16_t timeout)
{
until_timeout(timeout) {
if (iface->tx_done(iface)) return true;
}
return false;
}
void com_printf(ComIface *iface, const char *fmt, ...)
{
if (iface->file == NULL) {
com_tx_str(iface, "com_printf(), no iface file!\r\n");
return;
}
// use the file descriptor attached
va_list va;
va_start(va, fmt);
vfprintf(iface->file, fmt, va);
va_end(va);
}
void com_vprintf(ComIface *iface, const char *fmt, va_list va)
{
if (iface->file == NULL) {
com_tx_str(iface, "com_vprintf(), no iface file!\r\n");
com_tx_str(iface, fmt); // poor mans fallback
return;
}
// use the file descriptor attached
vfprintf(iface->file, fmt, va);
}
void com_v100_attr_(ComIface *iface, uint8_t count, ...)
{
va_list va;
va_start(va, count);
com_tx_char(iface, 27);
com_tx_char(iface, '[');
for (int i = 0; i < count; i++) {
int attr = va_arg(va, int);
// comma
if (i > 0) com_tx_char(iface, ';');
// number
com_printf(iface, "%d", attr);
}
com_tx_char(iface, 'm');
va_end(va);
}
+168
View File
@@ -0,0 +1,168 @@
#pragma once
#include <stdint.h>
#include <stdbool.h>
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
// Implementation-independent UI (command handler)
typedef struct ComIface_struct ComIface;
struct ComIface_struct {
// --- Variables ---
/** Implementation-specific data object */
void *opts;
/** File descriptor for this stream */
FILE *file;
/**
* User callback for data ready, triggered on poll().
* Can be null.
*/
void (*rx_callback)(ComIface *iface);
// --- Interface methods ---
/** Data ready to be read (RX buffer Not Empty) */
bool (*rx_rdy)(ComIface *iface);
/** Free space in TX buffer */
bool (*tx_rdy)(ComIface *iface);
/** Everything sent */
bool (*tx_done)(ComIface *iface);
/** Send 1 byte. Blocking, timeout after some time. */
bool (*tx)(ComIface *iface, uint8_t b);
/** Read one byte. False on failure. Blocking, timeout after some time. */
bool (*rx)(ComIface *iface, uint8_t *b);
/** Unreceive one byte. False on failure. */
bool (*unrx)(ComIface *iface, uint8_t b);
/** Send a binary block. False on failure. */
size_t (*txb)(ComIface *iface, const void *blob, size_t size);
/** Read a binary block. Returns real read length. Blocking, timeout after some time. */
size_t (*rxb)(ComIface *iface, void *buf, size_t length);
/** Poll for changes */
void (*poll)(ComIface *iface);
};
// ---- Functions for working with iface --------------
/** Wait for incoming byte */
bool com_rx_wait(ComIface *iface, uint16_t timeout);
/** Wait for free space in tx buffer */
bool com_tx_rdy_wait(ComIface *iface, uint16_t timeout);
/** Wait for tx complete */
bool com_tx_done_wait(ComIface *iface, uint16_t timeout);
/** Check if there's data in the receive buffer */
bool com_rx_rdy(ComIface *iface);
/** Check if transmit buffer can accept data */
bool com_tx_rdy(ComIface *iface);
/** Check if transmit buffer is empty */
bool com_tx_done(ComIface *iface);
/** Send 1 byte */
bool com_tx(ComIface *iface, uint8_t b);
/** Read one byte. False on failure. Fails on timeout. */
bool com_rx(ComIface *iface, uint8_t *b);
/** Unrx one byte. False on failure. */
bool com_unrx(ComIface *iface, uint8_t b);
/** Send a binary blob. False on failure. Fails on timeout. */
size_t com_tx_block(ComIface *iface, const void *blob, size_t size);
/** Read a blob. Returns real read length. Stops on timeout. */
size_t com_rx_block(ComIface *iface, void *buf, size_t length);
/** Poll for changes */
void com_poll(ComIface *iface);
/** Send 1 char */
bool com_tx_char(ComIface *iface, char c);
/** Read one char. False on failure. Fails on timeout. */
bool com_rx_char(ComIface *iface, char *c);
/** Send a string. False on failure. */
size_t com_tx_str(ComIface *iface, const char *str);
/** Read a string. Returns real read length. Stops on timeout. */
size_t com_rx_str(ComIface *iface, char *buf, size_t length);
/**
* Printf to a serial interface.
* Max length is 255 chars.
*/
void com_printf(ComIface *iface, const char *fmt, ...)
__attribute__ ((format (printf, 2, 3)));
/**
* Printf to a serial interface, with va_list.
*/
void com_vprintf(ComIface *iface, const char *fmt, va_list va);
// ---- VT100/ANSI color support -------------
/** ANSI formatting attributes */
typedef enum {
// Non-colour Attributes
FMT_RESET = 0, // Reset all attributes
FMT_BRIGHT = 1, // Bright
FMT_DIM = 2, // Dim
FMT_UNDER = 4, // Underscore
FMT_BLINK = 5, // Blink
FMT_INVERS = 7, // Reverse
FMT_HIDDEN = 8, // Hidden
FMT_ITALIC = 16, // Italic font
FMT_FAINT = 32, // Faint color
// Foreground Colours
FMT_BLACK = 30, // Black
FMT_RED = 31, // Red
FMT_GREEN = 32, // Green
FMT_YELLOW = 33, // Yellow
FMT_BLUE = 34, // Blue
FMT_MAGENTA = 35, // Magenta
FMT_CYAN = 36, // Cyan
FMT_WHITE = 37, // White
// Background Colours
FMT_BLACK_BG = 40, // Black
FMT_RED_BG = 41, // Red
FMT_GREEN_BG = 42, // Green
FMT_YELLOW_BG = 43, // Yellow
FMT_BLUE_BG = 44, // Blue
FMT_MAGENTA_BG = 45, // Magenta
FMT_CYAN_BG = 46, // Cyan
FMT_WHITE_BG = 47, // White
} ANSI_attr_t;
#define VA_NUM_ARGS(...) VA_NUM_ARGS_IMPL(__VA_ARGS__, 5,4,3,2,1)
#define VA_NUM_ARGS_IMPL(_1,_2,_3,_4,_5,N,...) N
#define com_v100_attr(iface, ...) com_v100_attr_(iface, VA_NUM_ARGS(__VA_ARGS__), __VA_ARGS__)
/**
* Send formatting code to a com interface
*/
void com_v100_attr_(ComIface *iface, uint8_t count, ...);
+48
View File
@@ -0,0 +1,48 @@
#include "datalink.h"
#include "com_fileio.h"
#include "debug.h"
#include "com_fileio.h"
SBMP_Endpoint *dlnk_ep;
static void dlnk_tx(uint8_t b);
static void dlnk_rx_bridge(ComIface *iface);
/** Set up the datalink */
void dlnk_init(void)
{
// Allocate & setup the endpoint
dlnk_ep = sbmp_ep_init(NULL, NULL, 100, dlnk_rx, dlnk_tx);
sbmp_ep_seed_session(dlnk_ep, 0x3FFF); // just in case arbitration fails
sbmp_ep_enable(dlnk_ep, true);
sbmp_ep_init_listeners(dlnk_ep, NULL, 4); // really don' need many here..
data_iface->rx_callback = dlnk_rx_bridge;
}
/**
* Bridge between USART subsystem's Rx buffer, and the SBMP driver
*
* Called if bytes are received in the USART buffer,
* and the USART subsystem is polled.
*/
static void dlnk_rx_bridge(ComIface *iface)
{
uint8_t b;
while (com_rx(iface, &b)) {
SBMP_RxStatus st = sbmp_ep_receive(dlnk_ep, b);
// If byte was not accepted, try to put it back into the buffer
if (st == SBMP_RX_BUSY || st == SBMP_RX_DISABLED) {
com_unrx(iface, b);
break;
}
}
}
/** Datalink Tx func */
static void dlnk_tx(uint8_t b)
{
com_tx(data_iface, b);
}
+26
View File
@@ -0,0 +1,26 @@
#pragma once
/**
* SBMP setup & funcs
*/
#include "main.h"
#include <sbmp.h>
#define DG_REQUEST_RAW 40 // request raw vector. Sample count [u16], Frequency [u32]
#define DG_REQUEST_FFT 41 // request fft vector. Sample count [u16], Frequency [u32]. Result - count/2 bins. Count must be 2^n, 16..2048
#define DG_REQUEST_STORE_REF 42 // calculate signal signature & store for comparing
#define DG_REQUEST_COMPARE_REF 43
// wifi status & control
#define DG_SETMODE_AP 44 // request AP mode (AP button pressed)
#define DG_WPS_START 45 // start WPS
#define DG_WIFI_STATUS 46 // WiFi status report
#define DG_REQUEST_STM_VERSION 47 // Get acquisition module firmware version
extern SBMP_Endpoint *dlnk_ep;
void dlnk_init(void);
/** Received datagram handler */
extern void dlnk_rx(SBMP_Datagram *dg);
+108
View File
@@ -0,0 +1,108 @@
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "com_iface.h"
#include "utils/timebase.h"
#include "debug.h"
void dbg_printf(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
com_vprintf(debug_iface, fmt, va); // vsnprintf(strbuf, DBG_BUF_LEN, fmt, va);
va_end(va);
}
void dbg_va_base(const char *fmt, const char *tag, va_list va)
{
ms_time_t now = ms_now();
uint32_t secs = now / 1000;
uint32_t ms = now % 1000;
com_printf(debug_iface, "%4"PRIu32".%03"PRIu32" ", secs, ms);
dbg_raw(tag);
com_vprintf(debug_iface, fmt, va);
dbg_raw(DEBUG_EOL);
}
/** Print a log message with an INFO tag and newline (ONLY FOR BANNER - always shown) */
void banner_info(const char *fmt, ...)
{
com_v100_attr(debug_iface, FMT_GREEN);
va_list va;
va_start(va, fmt);
dbg_va_base(fmt, DEBUG_TAG_INFO, va);
va_end(va);
com_v100_attr(debug_iface, FMT_RESET);
}
#if VERBOSE_LOGGING
/** Print a log message with a DEBUG tag and newline */
void dbg(const char *fmt, ...)
{
va_list va;
va_start(va, fmt);
dbg_va_base(fmt, DEBUG_TAG_BASE, va);
va_end(va);
}
/** Print a log message with an INFO tag and newline */
void info(const char *fmt, ...) __attribute__((alias("banner_info")));
#endif
/** Print a log message with an INFO tag and newline */
void banner(const char *fmt, ...)
{
com_v100_attr(debug_iface, FMT_GREEN, FMT_BRIGHT);
va_list va;
va_start(va, fmt);
dbg_va_base(fmt, DEBUG_TAG_INFO, va);
va_end(va);
com_v100_attr(debug_iface, FMT_RESET);
}
/** Print a log message with a warning tag and newline */
void warn(const char *fmt, ...)
{
com_v100_attr(debug_iface, FMT_YELLOW, FMT_BRIGHT);
va_list va;
va_start(va, fmt);
dbg_va_base(fmt, DEBUG_TAG_WARN, va);
va_end(va);
com_v100_attr(debug_iface, FMT_RESET);
}
/** Print a log message with an ERROR tag and newline */
void error(const char *fmt, ...)
{
com_v100_attr(debug_iface, FMT_RED, FMT_BRIGHT);
va_list va;
va_start(va, fmt);
dbg_va_base(fmt, DEBUG_TAG_ERROR, va);
va_end(va);
com_v100_attr(debug_iface, FMT_RESET);
}
+73
View File
@@ -0,0 +1,73 @@
#pragma once
#include "main.h"
#include "com_iface.h"
#include "com_fileio.h"
#include "bus/event_queue.h"
// helper to mark printf functions
#define PRINTF_LIKE __attribute__((format(printf, 1, 2)))
#define DBG_BUF_LEN 256
#define ESCAPE_DEBUG_MESSAGES 1
// formatting symbols
#define DEBUG_EOL "\r\n"
#define DEBUG_TAG_WARN "[W] "
#define DEBUG_TAG_ERROR "[E] "
#define DEBUG_TAG_BASE "[ ] "
#define DEBUG_TAG_INFO "[i] "
/** Print a log message with no tag and no newline */
void dbg_printf(const char *fmt, ...) PRINTF_LIKE;
/** Print via va_list */
void dbg_va_base(const char *fmt, const char *tag, va_list va);
/** Print a string to the debug interface (length not limited) */
static inline void dbg_raw(const char *str)
{
com_tx_str(debug_iface, str);
}
/** Print a char to the debug interface */
static inline void dbg_raw_c(char c)
{
com_tx(debug_iface, (uint8_t)c);
}
#if VERBOSE_LOGGING
/** Print a log message with a "debug" tag and newline */
void dbg(const char *fmt, ...) PRINTF_LIKE;
/** Print a log message with an "info" tag and newline */
void info(const char *fmt, ...) PRINTF_LIKE;
#else
#define dbg(fmt, ...)
#define info(fmt, ...)
#endif
/** Print a log message with an "info" tag and newline */
void banner_info(const char *fmt, ...) PRINTF_LIKE;
/** Print a log message with a "banner" tag and newline */
void banner(const char *fmt, ...) PRINTF_LIKE;
/** Print a log message with a "warning" tag and newline */
void warn(const char *fmt, ...) PRINTF_LIKE;
/** Print a log message with an "error" tag and newline */
void error(const char *fmt, ...) PRINTF_LIKE;
+91
View File
@@ -0,0 +1,91 @@
#include <stdlib.h>
#include "iface_noop.h"
#include "com_fileio.h"
#include "malloc_safe.h"
// ==== NOOP com driver ====
static bool if_rx_rdy(ComIface *iface)
{
(void)iface;
return false;
}
static bool if_tx_rdy(ComIface *iface)
{
(void)iface;
return true;
}
static bool if_tx_done(ComIface *iface)
{
(void)iface;
return true;
}
static bool if_rx(ComIface *iface, uint8_t *b)
{
(void)iface;
(void)b;
return false;
}
static bool if_unrx(ComIface *iface, uint8_t b)
{
(void)iface;
(void)b;
return false;
}
static bool if_tx(ComIface *iface, uint8_t b)
{
(void)iface;
(void)b;
return true;
}
static size_t if_rxb(ComIface *iface, void *buf, size_t buflen)
{
(void)iface;
(void)buf;
(void)buflen;
return 0;
}
static size_t if_txb(ComIface *iface, const void *blob, size_t size)
{
(void)iface;
(void)blob;
return size;
}
static void if_poll(ComIface *iface)
{
(void)iface;
}
ComIface *com_noop_init(void)
{
ComIface *iface = malloc_s(sizeof(ComIface));
iface->rx_rdy = if_rx_rdy;
iface->tx_rdy = if_tx_rdy;
iface->tx_done = if_tx_done;
iface->rx = if_rx;
iface->unrx = if_unrx;
iface->tx = if_tx;
iface->rxb = if_rxb;
iface->txb = if_txb;
iface->poll = if_poll;
iface->rx_callback = NULL;
return iface;
}
+14
View File
@@ -0,0 +1,14 @@
#pragma once
/**
* NOOP iface works like /dev/null
*/
#include "com_iface.h"
/**
* @brief Initialize a do-nothing interface.
* @param iface : iface pointer. If NULL, it'll be allocated.
* @return the iface pointer.
*/
ComIface *com_noop_init(void);
+328
View File
@@ -0,0 +1,328 @@
#include "main.h"
#include "malloc_safe.h"
#include "iface_usart.h"
#include "utils/timebase.h"
#include "utils/circbuf.h"
#include "com/com_fileio.h"
#include "com/debug.h"
#include "bus/event_queue.h"
#define DEF_WAIT_TO_MS 5
typedef struct {
uint16_t wait_timeout;
USART_TypeDef *dev;
CircBuf *rxbuf; // allocated receive buffer
CircBuf *txbuf; // allocated transmit buffer, can be NULL -> no buffer
} usart_opts;
#define opts(iface) ((usart_opts *)(iface)->opts)
// ---- Instances ----
// (needed for async rx/tx with interrupts)
static ComIface *usart1_iface = NULL;
static ComIface *usart2_iface = NULL;
static ComIface *usart3_iface = NULL;
// -------------------
/** Check if data is ready for reading */
static bool if_rx_rdy(ComIface *iface)
{
CircBuf *buf = opts(iface)->rxbuf;
return !cbuf_empty(buf);
}
/** Check if sending is done */
static bool if_tx_rdy(ComIface *iface)
{
CircBuf *buf = opts(iface)->txbuf;
if (buf == NULL) {
// non-buffered mode
USART_TypeDef* USARTx = opts(iface)->dev;
return (USARTx->SR & USART_SR_TXE);
}
return !cbuf_full(buf);
}
/** Check if sending is done */
static bool if_tx_done(ComIface *iface)
{
CircBuf *buf = opts(iface)->txbuf;
USART_TypeDef* USARTx = opts(iface)->dev;
// NULL buffer is considered empty
return cbuf_empty(buf) && (USARTx->SR & USART_SR_TC);
}
/** Read one byte (wait for it). False on error. */
static bool if_rx(ComIface *iface, uint8_t *b)
{
// wait for data in the buffer
if (!com_rx_wait(iface, opts(iface)->wait_timeout) || b == NULL) {
return false;
}
// read from buffer
cbuf_pop(opts(iface)->rxbuf, b);
return true;
}
/** Try to unreceive a byte. False on error. */
static bool if_unrx(ComIface *iface, uint8_t b)
{
// push back
return cbuf_push(opts(iface)->rxbuf, &b);
}
/** Send one byte (waits for tx) */
static bool if_tx(ComIface *iface, uint8_t b)
{
usart_opts *uopts = opts(iface);
USART_TypeDef* USARTx = uopts->dev;
if (uopts->txbuf == NULL) {
// Blocking tx mode
until_timeout(uopts->wait_timeout) {
if (USARTx->SR & USART_SR_TXE) {
USARTx->DR = b;
return true; // success
}
}
return false;
} else {
// Buffered mode
// wait for free space in the buffer
bool ready = com_tx_rdy_wait(iface, uopts->wait_timeout);
if (ready) {
// append to the buffer
cbuf_append(uopts->txbuf, &b);
}
// regardless ready state, start Tx if there are bytes
// (should fix a bug where full buffer was never emptied)
// If TXE (send buffer empty), start sending the buffer
// Otherwise, IRQ chain is in progress.
if (USARTx->SR & USART_SR_TXE) {
USART_ITConfig(USARTx, USART_IT_TXE, ENABLE); // start tx chain
}
return ready;
}
}
/** Read a blob. Returns real read size */
static size_t if_rxb(ComIface *iface, void *buf, size_t buflen)
{
if (buf == NULL) return false;
//if (!com_rx_wait(iface, opts(iface)->wait_timeout)) return 0;
uint8_t* byteptr = (uint8_t*)buf;
for (size_t i = 0; i < buflen; i++) {
if (!if_rx(iface, byteptr++)) return i;
}
return buflen;
}
/** Send a binary blob. False on error. */
static size_t if_txb(ComIface *iface, const void *blob, size_t size)
{
if (blob == NULL) return false;
//if (!com_tx_rdy_wait(iface, opts(iface)->wait_timeout)) return false;
const uint8_t* byteptr = (const uint8_t*)blob;
for (size_t i = 0; i < size; i++) {
if (!if_tx(iface, *byteptr++)) return i;
}
return size;
}
/** Check for incoming data */
static void if_poll(ComIface *iface)
{
if (if_rx_rdy(iface)) {
// call user cb
if (iface->rx_callback) {
iface->rx_callback(iface);
}
}
}
// ---- Init interface ----
//void usart_iface_set_baudrate(ComIface *iface, uint32_t baud)
//{
// USART_TypeDef* USARTx = opts(iface)->dev;
//
// USART_SetBaudrate(USARTx, baud);
//}
/* public */
ComIface *usart_iface_init(USART_TypeDef* USARTx, uint32_t baud, size_t rxbuf_len, size_t txbuf_len)
{
assert_param(IS_USART_BAUDRATE(baud));
assert_param(rxbuf_len > 0);
ComIface *iface = malloc_s(sizeof(ComIface));
// --- setup device specific iface data ---
// Allocate the opts config object
iface->opts = malloc_s(sizeof(usart_opts));
// Set device ID
opts(iface)->dev = USARTx;
opts(iface)->wait_timeout = DEF_WAIT_TO_MS;
// Initialize the rx/tx buffers (malloc's the array)
opts(iface)->rxbuf = cbuf_create(rxbuf_len, 1);
// zero-length TX buffer -> blocking Tx
opts(iface)->txbuf = (txbuf_len == 0) ? NULL : cbuf_create(txbuf_len, 1);
// --- driver instance ---
iface->rx_rdy = if_rx_rdy;
iface->tx_rdy = if_tx_rdy;
iface->tx_done = if_tx_done;
iface->rx = if_rx;
iface->unrx = if_unrx;
iface->tx = if_tx;
iface->txb = if_txb;
iface->rxb = if_rxb;
iface->poll = if_poll;
iface->rx_callback = NULL; // user can replace
/* enable peripehral clock, assign to holder var, enable IRQ */
IRQn_Type irqn;
if (USARTx == USART1) {
// USART1
usart1_iface = iface;
irqn = USART1_IRQn;
RCC->APB2ENR |= RCC_APB2ENR_USART1EN;
} else if (USARTx == USART2) {
// USART2
usart2_iface = iface;
irqn = USART2_IRQn;
RCC->APB1ENR |= RCC_APB1ENR_USART2EN;
} else {
// USART3
usart3_iface = iface;
irqn = USART3_IRQn;
RCC->APB1ENR |= RCC_APB1ENR_USART3EN;
}
// Enable IRQ
NVIC_EnableIRQ(irqn);
// lower priority than SysTick, but high
NVIC_SetPriority(irqn, 1); // function does the shifting
/* Setup UART parameters. */
USART_InitTypeDef usart;
USART_StructInit(&usart);
usart.USART_BaudRate = baud;
USART_Init(USARTx, &usart);
/* Enable */
USART_Cmd(USARTx, ENABLE);
// Enable Rx interrupt
USART_ITConfig(USARTx, USART_IT_RXNE, ENABLE); // disable IRQ
return iface;
}
// ---- IRQ handlers for chained writing and rx ----
/**
* @brief Common USART irq handler
* @param iface the interface at which the event occured
*/
static void usart_iface_irq_base(ComIface* iface)
{
USART_TypeDef* USARTx = opts(iface)->dev;
if (USARTx->SR & USART_SR_RXNE) {
// Byte received.
uint8_t rxb = USARTx->DR & 0xFF;
if (!cbuf_append(opts(iface)->rxbuf, &rxb)) {
// Buffer overflow
// Can't print debug msg, can cause deadlock
}
}
if (USARTx->SR & USART_SR_TXE) {
// Byte sent.
uint8_t txb;
// Send next byte (if buffer is NULL, cbuf_pop also returns false)
if (cbuf_pop(opts(iface)->txbuf, &txb)) {
USARTx->DR = txb; // send data
} else {
USART_ITConfig(USARTx, USART_IT_TXE, DISABLE); // disable IRQ
}
}
// Clear ORE flag if set
USART_ClearFlag(USARTx, USART_FLAG_ORE);
}
void USART1_IRQHandler(void)
{
usart_iface_irq_base(usart1_iface);
}
void USART2_IRQHandler(void)
{
usart_iface_irq_base(usart2_iface);
}
void USART3_IRQHandler(void)
{
usart_iface_irq_base(usart3_iface);
}
+19
View File
@@ -0,0 +1,19 @@
#pragma once
#include "main.h"
#include "com_iface.h"
// Hardware USART.
/**
* @brief Init an USART interface. Caller must configure GPIO's & AF manually.
* @param USARTx device
* @param baud baud rate (ex.: 9600)
* @param rxbuf_len receive buffer size, must be > 0
* @param txbuf_len send buffer size. If 0, tx is blocking.
* @return the iface structure
*/
ComIface *usart_iface_init(USART_TypeDef* USARTx, uint32_t baud, size_t rxbuf_len, size_t txbuf_len);
///** Set baud rate */
//void usart_iface_set_baudrate(ComIface *iface, uint32_t baud);