├── README.md ├── debug.c ├── include ├── debug.h ├── math.h ├── ringbuffer.h ├── ringbufferdma.h ├── time.h ├── timer.h └── utils.h ├── math.c ├── pango-component.js ├── ringbuffer.c ├── ringbufferdma.c ├── syscalls.c ├── test ├── .gitignore ├── Makefile ├── test.c ├── test.h └── testMath.c ├── time.c ├── timer.c └── utils.c /README.md: -------------------------------------------------------------------------------- 1 | 2 | # UART debug 3 | 4 | 1. Enable one of the UARTs 5 | 1. Enable USARTx_RX (Peripheral to Memory, Circular) 6 | 1. Enable USARTx_TX (Memory to Peripheral, Circular) 7 | -------------------------------------------------------------------------------- /debug.c: -------------------------------------------------------------------------------- 1 | 2 | #include "debug.h" 3 | 4 | #include "include/utils.h" 5 | #include 6 | #include 7 | #include "include/ringbufferdma.h" 8 | #ifdef CONTIKI 9 | #include 10 | 11 | PROCESS(debug_process, "Debug"); 12 | #endif 13 | 14 | #define DEBUG_RX_BUFFER_SIZE 32 15 | RingBufferDmaU8 debugRxRing; 16 | uint8_t debugRxBuffer[DEBUG_RX_BUFFER_SIZE]; 17 | 18 | __weak void debug_processLine(const char* line); 19 | 20 | void debug_setup() { 21 | RingBufferDmaU8_initUSARTRx(&debugRxRing, &DEBUG_UART, debugRxBuffer, DEBUG_RX_BUFFER_SIZE); 22 | #ifdef CONTIKI 23 | process_start(&debug_process, NULL); 24 | #endif 25 | } 26 | 27 | __weak void debug_processLine(const char* line) { 28 | if (strlen(line) == 0) { 29 | } else { 30 | printf("invalid debug command: %s\n", line); 31 | } 32 | printf("> "); 33 | } 34 | 35 | #ifdef CONTIKI 36 | PROCESS_THREAD(debug_process, ev, data) { 37 | char line[30]; 38 | 39 | PROCESS_BEGIN(); 40 | while (1) { 41 | PROCESS_PAUSE(); 42 | if (RingBufferDmaU8_readLine(&debugRxRing, line, sizeof(line)) > 0) { 43 | strTrimRight(line); 44 | debug_processLine(line); 45 | } 46 | } 47 | PROCESS_END(); 48 | } 49 | #else 50 | void debug_tick() { 51 | char line[30]; 52 | if (RingBufferDmaU8_readLine(&debugRxRing, line, sizeof(line)) > 0) { 53 | strTrimRight(line); 54 | debug_processLine(line); 55 | } 56 | } 57 | #endif 58 | 59 | #ifdef __GNUC__ 60 | # define PUTCHAR_PROTOTYPE int __io_putchar(int ch) 61 | # define GETCHAR_PROTOTYPE int __io_getchar(void) 62 | #else 63 | # define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f) 64 | # define GETCHAR_PROTOTYPE int fgetc(FILE *f) 65 | #endif /* __GNUC__ */ 66 | 67 | PUTCHAR_PROTOTYPE { 68 | HAL_UART_Transmit(&DEBUG_UART, (uint8_t*)&ch, 1, DEBUG_TIMEOUT); 69 | return ch; 70 | } 71 | 72 | GETCHAR_PROTOTYPE { 73 | while (RingBufferDmaU8_available(&debugRxRing) == 0); 74 | return RingBufferDmaU8_read(&debugRxRing); 75 | } 76 | -------------------------------------------------------------------------------- /include/debug.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _DEBUG_H_ 3 | #define _DEBUG_H_ 4 | 5 | #include 6 | 7 | #define DEBUG_TIMEOUT 1000 8 | 9 | #if defined(CONFIG_DEBUG_UART1) 10 | extern UART_HandleTypeDef huart1; 11 | #define DEBUG_UART huart1 12 | #elif defined(CONFIG_DEBUG_UART2) 13 | extern UART_HandleTypeDef huart2; 14 | #define DEBUG_UART huart2 15 | #elif defined(CONFIG_DEBUG_UART3) 16 | extern UART_HandleTypeDef huart3; 17 | #define DEBUG_UART huart3 18 | #elif defined(CONFIG_DEBUG_UART4) 19 | extern UART_HandleTypeDef huart4; 20 | #define DEBUG_UART huart4 21 | #elif defined(CONFIG_DEBUG_UART5) 22 | extern UART_HandleTypeDef huart5; 23 | #define DEBUG_UART huart5 24 | #else 25 | #error "CONFIG_DEBUG_UARTx not defined" 26 | #endif 27 | 28 | void debug_setup(); 29 | 30 | #ifndef CONTIKI 31 | void debug_tick(); 32 | #endif 33 | 34 | #endif 35 | -------------------------------------------------------------------------------- /include/math.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _UTILS_MATH_H_ 3 | #define _UTILS_MATH_H_ 4 | 5 | #include 6 | 7 | uint16_t trig_int16_atan2deg(int16_t y, int16_t x); 8 | int16_t smallestDeltaBetweenAnglesInDegrees(int32_t source, int32_t target); 9 | 10 | #endif 11 | -------------------------------------------------------------------------------- /include/ringbuffer.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _STM32LIB_RINGBUFFER_H_ 3 | #define _STM32LIB_RINGBUFFER_H_ 4 | 5 | #include 6 | 7 | typedef struct { 8 | uint8_t* storage; 9 | uint8_t* end; 10 | uint16_t size; 11 | volatile uint8_t* read; 12 | volatile uint8_t* write; 13 | volatile uint16_t available; 14 | } RingBufferU8; 15 | 16 | void RingBufferU8_init(RingBufferU8* ring, uint8_t* storage, uint16_t size); 17 | uint16_t RingBufferU8_available(RingBufferU8* ring); 18 | uint16_t RingBufferU8_free(RingBufferU8* ring); 19 | void RingBufferU8_clear(RingBufferU8* ring); 20 | void RingBufferU8_read(RingBufferU8* ring, uint8_t* buffer, uint16_t size); 21 | uint8_t RingBufferU8_readByte(RingBufferU8* ring); 22 | void RingBufferU8_write(RingBufferU8* ring, const uint8_t* buffer, uint16_t size); 23 | void RingBufferU8_writeByte(RingBufferU8* ring, uint8_t b); 24 | uint16_t RingBufferU8_readUntil(RingBufferU8* ring, char* buffer, uint16_t size, uint8_t stopByte); 25 | uint16_t RingBufferU8_readLine(RingBufferU8* ring, char* buffer, uint16_t size); 26 | uint8_t RingBufferU8_peek(RingBufferU8* ring); 27 | uint8_t RingBufferU8_peekn(RingBufferU8* ring, uint16_t i); 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /include/ringbufferdma.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _RINGBUFFER_DMA_H_ 3 | #define _RINGBUFFER_DMA_H_ 4 | 5 | #include 6 | #include 7 | #include 8 | 9 | typedef struct { 10 | volatile uint8_t* buffer; 11 | uint16_t size; 12 | volatile uint8_t* tailPtr; 13 | DMA_HandleTypeDef* dmaHandle; 14 | } RingBufferDmaU8; 15 | 16 | void RingBufferDmaU8_initUSARTRx(RingBufferDmaU8* ring, UART_HandleTypeDef* husart, uint8_t* buffer, uint16_t size); 17 | uint16_t RingBufferDmaU8_available(RingBufferDmaU8* ring); 18 | bool RingBufferDmaU8_readLine(RingBufferDmaU8* ring, char* line, uint16_t size); 19 | uint8_t RingBufferDmaU8_read(RingBufferDmaU8* ring); 20 | 21 | #endif 22 | -------------------------------------------------------------------------------- /include/time.h: -------------------------------------------------------------------------------- 1 | #ifndef _STM32LIB_TIME_H 2 | #define _STM32LIB_TIME_H 3 | 4 | #include 5 | #include 6 | 7 | #ifdef __cplusplus 8 | extern "C" { 9 | #endif 10 | 11 | void sleep_ms(uint32_t ms); 12 | void sleep_us(uint32_t us); 13 | 14 | struct tm* gmtime(register const time_t* timer); 15 | 16 | #ifdef __cplusplus 17 | } 18 | #endif 19 | 20 | #endif /* _STM32LIB_TIME_H */ 21 | 22 | -------------------------------------------------------------------------------- /include/timer.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _TIMER_H_ 3 | #define _TIMER_H_ 4 | 5 | #include 6 | #include 7 | 8 | typedef struct { 9 | uint32_t nextTick; 10 | uint32_t intervalMs; 11 | } PeriodicTimer; 12 | 13 | void periodicTimer_setup(PeriodicTimer* timer, uint32_t intervalMs); 14 | bool periodicTimer_hasElapsed(PeriodicTimer* timer); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /include/utils.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _STM32LIB_UTILS_H_ 3 | #define _STM32LIB_UTILS_H_ 4 | 5 | #include 6 | 7 | #ifndef min 8 | # define min(a,b) ( ((a) < (b)) ? (a) : (b) ) 9 | #endif 10 | #ifndef max 11 | # define max(a,b) ( ((a) > (b)) ? (a) : (b) ) 12 | #endif 13 | #ifndef clamp 14 | # define clamp(x, min, max) ( ((x) < (min)) ? (min) : ( ((x) > (max)) ? (max) : (x) ) ) 15 | #endif 16 | #ifndef testBits 17 | # define testBits(x, bits) ( ((x) & (bits)) == (bits) ) 18 | #endif 19 | 20 | #ifdef UTILS_DEBUG 21 | #define UTILS_DEBUG_OUT(format, ...) printf("%s:%d: " format, __FILE__, __LINE__, ##__VA_ARGS__) 22 | #else 23 | #define UTILS_DEBUG_OUT(format, ...) 24 | #endif 25 | 26 | #ifndef SWAP_UINT16 27 | # define SWAP_UINT16(x) (((x) >> 8) | ((x) << 8)) 28 | #endif 29 | #ifndef SWAP_UINT32 30 | # define SWAP_UINT32(x) (((x) >> 24) | (((x) & 0x00FF0000) >> 8) | (((x) & 0x0000FF00) << 8) | ((x) << 24)) 31 | #endif 32 | 33 | #define returnNonOKHALStatus(fn) { \ 34 | HAL_StatusTypeDef status = fn; \ 35 | if (status != HAL_OK) { \ 36 | return status; \ 37 | } \ 38 | } 39 | 40 | #define assertNonOKHALStatus(fn) { \ 41 | HAL_StatusTypeDef status = fn; \ 42 | if (status != HAL_OK) { \ 43 | UTILS_DEBUG_OUT("assert %d\n", status); \ 44 | while(1); \ 45 | } \ 46 | } 47 | 48 | uint32_t swapEndian(uint32_t val); 49 | void strTrim(char* str); 50 | void strTrimLeft(char* str); 51 | void strTrimRight(char* str); 52 | int isWhitespace(char ch); 53 | char* urlDecode(char* str); 54 | void printMemory(uint8_t* buffer, uint32_t length); 55 | 56 | #endif 57 | -------------------------------------------------------------------------------- /math.c: -------------------------------------------------------------------------------- 1 | 2 | #include "math.h" 3 | #include 4 | 5 | /** 6 | * http://www.romanblack.com/integer_degree.htm 7 | * 8 | * Fast XY vector to integer degree algorithm - Jan 2011 www.RomanBlack.com 9 | * Converts any XY values including 0 to a degree value that should be 10 | * within +/- 1 degree of the accurate value without needing 11 | * large slow trig functions like ArcTan() or ArcCos(). 12 | * NOTE! at least one of the X or Y values must be non-zero! 13 | * This is the full version, for all 4 quadrants and will generate 14 | * the angle in integer degrees from 0-360. 15 | * Any values of X and Y are usable including negative values provided 16 | * they are between -1456 and 1456 so the 16bit multiply does not overflow. 17 | */ 18 | uint16_t trig_int16_atan2deg(int16_t y, int16_t x) { 19 | unsigned char negflag; 20 | unsigned char tempdegree; 21 | unsigned char comp; 22 | unsigned int degree; 23 | unsigned int ux; 24 | unsigned int uy; 25 | 26 | if (x == 0 && y == 0) { 27 | return 0; 28 | } 29 | 30 | // Save the sign flags then remove signs and get XY as unsigned ints 31 | negflag = 0; 32 | if (x < 0) { 33 | negflag += 0x01; // x flag bit 34 | x = (0 - x); // is now + 35 | } 36 | ux = x; // copy to unsigned var before multiply 37 | if (y < 0) { 38 | negflag += 0x02; // y flag bit 39 | y = (0 - y); // is now + 40 | } 41 | uy = y; // copy to unsigned var before multiply 42 | 43 | // 1. Calc the scaled "degrees" 44 | if (ux > uy) { 45 | degree = (uy * 45) / ux; // degree result will be 0-45 range 46 | negflag += 0x10; // octant flag bit 47 | } else { 48 | degree = (ux * 45) / uy; // degree result will be 0-45 range 49 | } 50 | 51 | // 2. Compensate for the 4 degree error curve 52 | comp = 0; 53 | tempdegree = degree; // use an unsigned char for speed! 54 | if (tempdegree > 22) { // if top half of range 55 | if (tempdegree <= 44) { 56 | comp++; 57 | } 58 | if (tempdegree <= 41) { 59 | comp++; 60 | } 61 | if (tempdegree <= 37) { 62 | comp++; 63 | } 64 | if (tempdegree <= 32) { 65 | comp++; // max is 4 degrees compensated 66 | } 67 | } else { // else is lower half of range 68 | if (tempdegree >= 2) { 69 | comp++; 70 | } 71 | if (tempdegree >= 6) { 72 | comp++; 73 | } 74 | if (tempdegree >= 10) { 75 | comp++; 76 | } 77 | if (tempdegree >= 15) { 78 | comp++; // max is 4 degrees compensated 79 | } 80 | } 81 | degree += comp; // degree is now accurate to +/- 1 degree! 82 | 83 | // Invert degree if it was X>Y octant, makes 0-45 into 90-45 84 | if (negflag & 0x10) { 85 | degree = (90 - degree); 86 | } 87 | 88 | // 3. Degree is now 0-90 range for this quadrant, 89 | // need to invert it for whichever quadrant it was in 90 | if (negflag & 0x02) { // if -Y 91 | if (negflag & 0x01) { // if -Y -X 92 | degree = (180 + degree); 93 | } else { // else is -Y +X 94 | degree = (180 - degree); 95 | } 96 | } else { // else is +Y 97 | if (negflag & 0x01) { // if +Y -X 98 | degree = (360 - degree); 99 | } 100 | } 101 | 102 | return degree; 103 | } 104 | 105 | int16_t smallestDeltaBetweenAnglesInDegrees(int32_t source, int32_t target) { 106 | int16_t a; 107 | a = target - source; 108 | a += (a > 180) ? -360 : (a < -180) ? 360 : 0; 109 | return a; 110 | } 111 | -------------------------------------------------------------------------------- /pango-component.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const GccTargetBuilder = require('pango-gcc').GccTargetBuilder; 3 | 4 | module.exports = { 5 | targets: { 6 | 'stm32-utils': { 7 | run(projectOptions) { 8 | projectOptions.gcc.includeDirs.push(path.join(__dirname, 'include')); 9 | return GccTargetBuilder.createTargets(projectOptions, __dirname); 10 | }, 11 | postRequisites: ['build'] 12 | } 13 | } 14 | }; 15 | -------------------------------------------------------------------------------- /ringbuffer.c: -------------------------------------------------------------------------------- 1 | 2 | #include "ringbuffer.h" 3 | #include "utils.h" 4 | 5 | void RingBufferU8_init(RingBufferU8* ring, uint8_t* storage, uint16_t size) { 6 | ring->storage = storage; 7 | ring->size = size; 8 | ring->end = ring->storage + ring->size; 9 | ring->read = ring->storage; 10 | ring->write = ring->storage; 11 | ring->available = 0; 12 | } 13 | 14 | uint16_t RingBufferU8_available(RingBufferU8* ring) { 15 | return ring->available; 16 | } 17 | 18 | uint16_t RingBufferU8_free(RingBufferU8* ring) { 19 | return ring->size - ring->available; 20 | } 21 | 22 | void RingBufferU8_clear(RingBufferU8* ring) { 23 | ring->read = ring->storage; 24 | ring->write = ring->storage; 25 | ring->available = 0; 26 | } 27 | 28 | uint8_t RingBufferU8_readByte(RingBufferU8* ring) { 29 | if (ring->available == 0) { 30 | return 0; 31 | } 32 | uint8_t ret = *ring->read++; 33 | ring->available--; 34 | if (ring->read >= ring->end) { 35 | ring->read = ring->storage; 36 | } 37 | return ret; 38 | } 39 | 40 | void RingBufferU8_read(RingBufferU8* ring, uint8_t* buffer, uint16_t size) { 41 | uint16_t i; 42 | 43 | // TODO can be optimized 44 | for (i = 0; i < size; i++) { 45 | buffer[i] = RingBufferU8_readByte(ring); 46 | } 47 | } 48 | 49 | void RingBufferU8_writeByte(RingBufferU8* ring, uint8_t b) { 50 | if (ring->available >= ring->size) { 51 | RingBufferU8_readByte(ring); 52 | } 53 | 54 | *ring->write = b; 55 | ring->write++; 56 | ring->available++; 57 | if (ring->write >= ring->end) { 58 | ring->write = ring->storage; 59 | } 60 | } 61 | 62 | void RingBufferU8_write(RingBufferU8* ring, const uint8_t* buffer, uint16_t size) { 63 | uint16_t i; 64 | 65 | // TODO can be optimized 66 | for (i = 0; i < size; i++) { 67 | RingBufferU8_writeByte(ring, buffer[i]); 68 | } 69 | } 70 | 71 | uint16_t RingBufferU8_readLine(RingBufferU8* ring, char* buffer, uint16_t size) { 72 | return RingBufferU8_readUntil(ring, buffer, size, '\r'); 73 | } 74 | 75 | uint16_t RingBufferU8_readUntil(RingBufferU8* ring, char* buffer, uint16_t size, uint8_t stopByte) { 76 | uint8_t b; 77 | uint16_t i; 78 | for (i = 0; i < min(ring->available, size - 1); i++) { 79 | b = RingBufferU8_peekn(ring, i); 80 | if (b == stopByte) { 81 | i++; 82 | RingBufferU8_read(ring, (uint8_t*) buffer, i); 83 | buffer[i] = '\0'; 84 | return i; 85 | } 86 | } 87 | buffer[0] = '\0'; 88 | return 0; 89 | } 90 | 91 | uint8_t RingBufferU8_peek(RingBufferU8* ring) { 92 | return RingBufferU8_peekn(ring, 0); 93 | } 94 | 95 | uint8_t RingBufferU8_peekn(RingBufferU8* ring, uint16_t i) { 96 | if (i >= ring->available) { 97 | return 0; 98 | } 99 | 100 | uint8_t* read = (uint8_t*)ring->read; 101 | uint8_t* p = read + i; 102 | if (p >= ring->end) { 103 | p -= ring->size; 104 | } 105 | return *p; 106 | } 107 | -------------------------------------------------------------------------------- /ringbufferdma.c: -------------------------------------------------------------------------------- 1 | 2 | #include "include/ringbufferdma.h" 3 | #include "include/utils.h" 4 | 5 | void RingBufferDmaU8_initUSARTRx(RingBufferDmaU8* ring, UART_HandleTypeDef* husart, uint8_t* buffer, uint16_t size) { 6 | ring->buffer = buffer; 7 | ring->size = size; 8 | ring->tailPtr = buffer; 9 | ring->dmaHandle = husart->hdmarx; 10 | HAL_UART_Receive_DMA(husart, buffer, size); 11 | } 12 | 13 | uint16_t RingBufferDmaU8_available(RingBufferDmaU8* ring) { 14 | #ifdef __HAL_DMA_GET_COUNTER 15 | uint32_t leftToTransfer = __HAL_DMA_GET_COUNTER(ring->dmaHandle); 16 | #else 17 | uint32_t leftToTransfer = ring->dmaHandle->Instance->CNDTR; 18 | #endif 19 | volatile uint8_t const* head = ring->buffer + ring->size - leftToTransfer; 20 | volatile uint8_t const* tail = ring->tailPtr; 21 | if (head >= tail) { 22 | return head - tail; 23 | } else { 24 | return head - tail + ring->size; 25 | } 26 | } 27 | 28 | bool RingBufferDmaU8_readLine(RingBufferDmaU8* ring, char* line, uint16_t size) { 29 | volatile uint8_t* in = ring->tailPtr; 30 | uint8_t* out = (uint8_t*)line; 31 | uint8_t total = min(size, RingBufferDmaU8_available(ring)); 32 | for (uint16_t i = 0; i < total; i++) { 33 | uint8_t c = *in++; 34 | *out = c; 35 | if (in >= ring->buffer + ring->size) { 36 | in -= ring->size; 37 | } 38 | if (c == '\n' || c == '\r') { 39 | *out = 0x00; 40 | ring->tailPtr = in; 41 | return true; 42 | } 43 | out++; 44 | } 45 | return false; 46 | } 47 | 48 | uint8_t RingBufferDmaU8_read(RingBufferDmaU8* ring) { 49 | uint8_t ret = *ring->tailPtr++; 50 | if (ring->tailPtr >= ring->buffer + ring->size) { 51 | ring->tailPtr -= ring->size; 52 | } 53 | return ret; 54 | } 55 | -------------------------------------------------------------------------------- /syscalls.c: -------------------------------------------------------------------------------- 1 | /* Support files for GNU libc. Files in the system namespace go here. 2 | Files in the C namespace (ie those that do not start with an 3 | underscore) go in .c. */ 4 | 5 | //#include <_ansi.h> 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | //#include 16 | #include 17 | #include 18 | 19 | #undef errno 20 | extern int errno; 21 | 22 | #define MAX_STACK_SIZE 0x2000 23 | 24 | extern int __io_putchar(int ch) __attribute__((weak)); 25 | extern int __io_getchar(void) __attribute__((weak)); 26 | 27 | #ifndef FreeRTOS 28 | register char* stack_ptr asm("sp"); 29 | #endif 30 | 31 | caddr_t _sbrk(int incr) { 32 | extern char end asm("end"); 33 | static char* heap_end; 34 | char* prev_heap_end, *min_stack_ptr; 35 | 36 | if (heap_end == 0) { 37 | heap_end = &end; 38 | } 39 | 40 | prev_heap_end = heap_end; 41 | 42 | #ifdef FreeRTOS 43 | /* Use the NVIC offset register to locate the main stack pointer. */ 44 | min_stack_ptr = (char*)(*(unsigned int*) * (unsigned int*)0xE000ED08); 45 | /* Locate the STACK bottom address */ 46 | min_stack_ptr -= MAX_STACK_SIZE; 47 | 48 | if (heap_end + incr > min_stack_ptr) 49 | #else 50 | if (heap_end + incr > stack_ptr) 51 | #endif 52 | { 53 | // write(1, "Heap and stack collision\n", 25); 54 | // abort(); 55 | errno = ENOMEM; 56 | return (caddr_t) - 1; 57 | } 58 | 59 | heap_end += incr; 60 | 61 | return (caddr_t) prev_heap_end; 62 | } 63 | 64 | /* 65 | * _gettimeofday primitive (Stub function) 66 | * */ 67 | int _gettimeofday (struct timeval* tp, struct timezone* tzp) { 68 | /* Return fixed data for the timezone. */ 69 | if (tzp) { 70 | tzp->tz_minuteswest = 0; 71 | tzp->tz_dsttime = 0; 72 | } 73 | 74 | return 0; 75 | } 76 | void initialise_monitor_handles() { 77 | } 78 | 79 | int _getpid(void) { 80 | return 1; 81 | } 82 | 83 | int _kill(int pid, int sig) { 84 | errno = EINVAL; 85 | return -1; 86 | } 87 | 88 | void _exit (int status) { 89 | _kill(status, -1); 90 | while (1) {} 91 | } 92 | 93 | int _write(int file, char* ptr, int len) { 94 | int DataIdx; 95 | 96 | for (DataIdx = 0; DataIdx < len; DataIdx++) { 97 | __io_putchar( *ptr++ ); 98 | } 99 | return len; 100 | } 101 | 102 | int _close(int file) { 103 | return -1; 104 | } 105 | 106 | int _fstat(int file, struct stat* st) { 107 | st->st_mode = S_IFCHR; 108 | return 0; 109 | } 110 | 111 | int _isatty(int file) { 112 | return 1; 113 | } 114 | 115 | int _lseek(int file, int ptr, int dir) { 116 | return 0; 117 | } 118 | 119 | int _read(int file, char* ptr, int len) { 120 | int DataIdx; 121 | 122 | for (DataIdx = 0; DataIdx < len; DataIdx++) { 123 | *ptr++ = __io_getchar(); 124 | } 125 | 126 | return len; 127 | } 128 | 129 | int _open(char* path, int flags, ...) { 130 | /* Pretend like we always fail */ 131 | return -1; 132 | } 133 | 134 | int _wait(int* status) { 135 | errno = ECHILD; 136 | return -1; 137 | } 138 | 139 | int _unlink(char* name) { 140 | errno = ENOENT; 141 | return -1; 142 | } 143 | 144 | int _times(struct tms* buf) { 145 | return -1; 146 | } 147 | 148 | int _stat(char* file, struct stat* st) { 149 | st->st_mode = S_IFCHR; 150 | return 0; 151 | } 152 | 153 | int _link(char* old, char* new) { 154 | errno = EMLINK; 155 | return -1; 156 | } 157 | 158 | int _fork(void) { 159 | errno = EAGAIN; 160 | return -1; 161 | } 162 | 163 | int _execve(char* name, char** argv, char** env) { 164 | errno = ENOMEM; 165 | return -1; 166 | } 167 | -------------------------------------------------------------------------------- /test/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /test/Makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all test 2 | 3 | CC = gcc 4 | CFLAGS = -c -Wall -I. -I.. 5 | LDFLAGS = 6 | SOURCES = test.c testMath.c ../math.c 7 | OBJECTS = $(addprefix build/test/,$(SOURCES:.c=.o)) 8 | EXECUTABLE = build/utils-test 9 | 10 | all: $(SOURCES) $(EXECUTABLE) 11 | 12 | test: all 13 | ./build/utils-test 14 | 15 | $(EXECUTABLE): $(OBJECTS) 16 | $(CC) $(LDFLAGS) $(OBJECTS) -o $@ 17 | 18 | build/test/%.o: %.c 19 | @mkdir -p build/test 20 | $(CC) $(CFLAGS) $< -o $@ 21 | -------------------------------------------------------------------------------- /test/test.c: -------------------------------------------------------------------------------- 1 | 2 | #include "test.h" 3 | #include "math.h" 4 | #include 5 | 6 | int tests_run; 7 | 8 | static char* all_tests(); 9 | extern char* math_test(); 10 | 11 | int main(int argc, char* argv[]) { 12 | printf("-------- BEGIN TEST --------\n"); 13 | char* result = all_tests(); 14 | if (result != 0) { 15 | printf("%s\n", result); 16 | } else { 17 | printf("ALL TESTS PASSED\n"); 18 | } 19 | printf("Tests run: %d\n", tests_run); 20 | 21 | return result != 0; 22 | } 23 | 24 | static char* all_tests() { 25 | mu_run_test(math_test); 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /test/test.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef _UTILS_TEST_H_ 3 | #define _UTILS_TEST_H_ 4 | 5 | #include 6 | #include 7 | 8 | #define mu_assert(message, test) do { if (!(test)) return message; } while (0) 9 | #define mu_assert_equals_int(expected, found) do { if ((expected)!=(found)) { printf("FAIL: expected: %d found: %d (%s:%d)\n", expected, found, __FILE__, __LINE__); return "not equal"; } } while (0) 10 | #define mu_run_test(test) do { char *message = test(); tests_run++; if (message) return message; } while (0) 11 | extern int tests_run; 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /test/testMath.c: -------------------------------------------------------------------------------- 1 | 2 | #include "test.h" 3 | #include "../math.h" 4 | 5 | static char* math_trig_int16_atan2deg(); 6 | static char* math_testSmallestDeltaBetweenAnglesInDegrees(); 7 | 8 | char* math_test() { 9 | mu_run_test(math_trig_int16_atan2deg); 10 | mu_run_test(math_testSmallestDeltaBetweenAnglesInDegrees); 11 | return NULL; 12 | } 13 | 14 | static char* math_trig_int16_atan2deg() { 15 | mu_assert_equals_int(0, trig_int16_atan2deg(0, 0)); 16 | mu_assert_equals_int(0, trig_int16_atan2deg(1, 0)); 17 | mu_assert_equals_int(90, trig_int16_atan2deg(0, 1)); 18 | mu_assert_equals_int(180, trig_int16_atan2deg(-1, 0)); 19 | mu_assert_equals_int(270, trig_int16_atan2deg(0, -1)); 20 | return NULL; 21 | } 22 | 23 | static char* math_testSmallestDeltaBetweenAnglesInDegrees() { 24 | mu_assert_equals_int(0, smallestDeltaBetweenAnglesInDegrees(0, 0)); 25 | mu_assert_equals_int(1, smallestDeltaBetweenAnglesInDegrees(0, 1)); 26 | mu_assert_equals_int(-1, smallestDeltaBetweenAnglesInDegrees(1, 0)); 27 | mu_assert_equals_int(2, smallestDeltaBetweenAnglesInDegrees(359, 1)); 28 | mu_assert_equals_int(-2, smallestDeltaBetweenAnglesInDegrees(1, 359)); 29 | mu_assert_equals_int(180, smallestDeltaBetweenAnglesInDegrees(0, 180)); 30 | mu_assert_equals_int(-179, smallestDeltaBetweenAnglesInDegrees(0, 181)); 31 | return NULL; 32 | } 33 | -------------------------------------------------------------------------------- /time.c: -------------------------------------------------------------------------------- 1 | 2 | #include "time.h" 3 | #ifdef CONTIKI 4 | #include 5 | #endif 6 | 7 | extern uint32_t SystemCoreClock; 8 | 9 | void sleep_ms(uint32_t ms) { 10 | volatile uint32_t i; 11 | for (i = ms; i != 0; i--) { 12 | sleep_us(1000); 13 | } 14 | } 15 | 16 | void sleep_us(uint32_t us) { 17 | volatile uint32_t i; 18 | for (i = ((SystemCoreClock / 8000000) * us); i != 0; i--) {} 19 | } 20 | 21 | #ifdef CONTIKI 22 | void HAL_SYSTICK_Callback() { 23 | etimer_request_poll(); 24 | } 25 | 26 | CCIF unsigned long clock_seconds() { 27 | return HAL_GetTick() / 1000; 28 | } 29 | 30 | clock_time_t clock_time(void) { 31 | return HAL_GetTick(); 32 | } 33 | #endif 34 | -------------------------------------------------------------------------------- /timer.c: -------------------------------------------------------------------------------- 1 | 2 | #include "timer.h" 3 | 4 | extern uint32_t HAL_GetTick(); 5 | 6 | void periodicTimer_setup(PeriodicTimer* timer, uint32_t intervalMs) { 7 | timer->nextTick = HAL_GetTick() + intervalMs; 8 | timer->intervalMs = intervalMs; 9 | } 10 | 11 | bool periodicTimer_hasElapsed(PeriodicTimer* timer) { 12 | int32_t currentTime = HAL_GetTick(); 13 | if (currentTime > timer->nextTick) { 14 | timer->nextTick = currentTime + timer->intervalMs; 15 | return true; 16 | } else { 17 | return false; 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /utils.c: -------------------------------------------------------------------------------- 1 | 2 | #include "utils.h" 3 | #include 4 | #include 5 | #include 6 | 7 | uint32_t swapEndian(uint32_t val) { 8 | return ((val << 24) & 0xff000000) 9 | | ((val << 8) & 0x00ff0000) 10 | | ((val >> 8) & 0x0000ff00) 11 | | ((val >> 24) & 0x000000ff); 12 | } 13 | 14 | void strTrim(char* str) { 15 | strTrimLeft(str); 16 | strTrimRight(str); 17 | } 18 | 19 | void strTrimLeft(char* str) { 20 | char* p = str; 21 | char* out = str; 22 | while (*p && isWhitespace(*p)) { 23 | p++; 24 | } 25 | while (*p) { 26 | *out++ = *p++; 27 | } 28 | } 29 | 30 | void strTrimRight(char* str) { 31 | char* p = str + strlen(str) - 1; 32 | while (p >= str && isWhitespace(*p)) { 33 | *p-- = '\0'; 34 | } 35 | } 36 | 37 | int isWhitespace(char ch) { 38 | switch (ch) { 39 | case '\n': 40 | case '\r': 41 | case '\t': 42 | case ' ': 43 | return 1; 44 | } 45 | return 0; 46 | } 47 | 48 | char* urlDecode(char* str) { 49 | char tmp[3]; 50 | char* in = str; 51 | char* out = str; 52 | while (*in) { 53 | if (*in == '+') { 54 | in++; 55 | *out++ = ' '; 56 | } else if (*in == '%') { 57 | in++; 58 | tmp[0] = *in++; 59 | tmp[1] = *in++; 60 | tmp[2] = '\0'; 61 | *out++ = (char)strtol(tmp, NULL, 16); 62 | } else { 63 | *out++ = *in++; 64 | } 65 | } 66 | *out = '\0'; 67 | return str; 68 | } 69 | 70 | void printMemory(uint8_t* buffer, uint32_t length) { 71 | uint8_t col; 72 | for (uint32_t offset = 0; offset < length; offset += 16) { 73 | printf("%08lX ", offset); 74 | for (col = 0; col < 16; col++) { 75 | if (offset + col < length) { 76 | printf("%02X ", buffer[offset + col]); 77 | } else { 78 | printf(" "); 79 | } 80 | } 81 | for (col = 0; col < 16; col++) { 82 | if (offset + col < length) { 83 | char ch = buffer[offset + col]; 84 | if (ch >= '.' && ch <= '~') { 85 | printf("%c", ch); 86 | } else { 87 | printf("."); 88 | } 89 | } else { 90 | printf(" "); 91 | } 92 | } 93 | printf("\n"); 94 | } 95 | } --------------------------------------------------------------------------------