feat: Framework to handle INCP messages

This commit is contained in:
2026-03-31 14:04:12 +01:00
parent 5a7d3a9864
commit f7c2b65ebc
9 changed files with 271 additions and 53 deletions

View File

@@ -1,7 +1,7 @@
FetchContent_Declare( FetchContent_Declare(
pyincp pyincp
GIT_REPOSITORY git@repo.dsi.tecnico.ulisboa.pt:nanosatlab/istsat-2/incp.git GIT_REPOSITORY git@repo.dsi.tecnico.ulisboa.pt:nanosatlab/istsat-2/incp.git
GIT_TAG feat/cli-rework GIT_TAG develop
) )
FetchContent_MakeAvailable(pyincp) FetchContent_MakeAvailable(pyincp)

View File

@@ -1,10 +1,67 @@
modules: modules:
- name: mod_a - name: calc
enums: [] enums:
- name: enum_a
doc: Enum a
values: [a, b]
variables: variables:
- name: var_a - name: time_boot
doc: Var a doc: Time in seconds since last reboot
type: U32
- name: time_real
doc: Time in seconds since epoch
type: U32
- name: test_str
doc: A test string with the fixed value TEST
type: S16
- name: test_enum
doc: Tests enums
type: enum_a
reports:
- name: time
doc: Collection of all time variables
variables:
- time_boot
- time_real
commands:
- name: add
doc: Sums two numbers
args:
- name: left
doc: First operand
type: I32 type: I32
reports: [] - name: right
commands: [] doc: Second operand
events: [] type: I32
rets:
- name: val
doc: Result
type: I32
- name: div
doc: Divides two numbers
args:
- name: left
doc: First operand
type: I32
- name: right
doc: Second operand
type: I32
rets:
- name: val
doc: Result
type: I32
- name: err
doc: Error flag, set on error
type: Bool
events:
- name: event_a
doc: Event a
- name: event_b
doc: Event b

View File

@@ -1,3 +1,5 @@
target_sources(${EXECUTABLE} PRIVATE target_sources(${EXECUTABLE} PRIVATE
main.c main.c
incp_handler.c
msg_buf.c
) )

View File

@@ -1,31 +0,0 @@
#ifndef _CIRCULAR_BUFF_H_
#define _CIRCULAR_BUFF_H_
#include <stdbool.h>
#define _CB_COUNT(buffer) (sizeof((buffer)->buf) / sizeof((buffer)->buf[0]))
#define _CB_WRAP(buffer, idx) ((idx) % (_CB_COUNT(buffer)))
#define CIRCULAR_BUFFER_ALL(name, type, capacity) \
typedef struct { \
volatile uint32_t tail, count; \
volatile type buf[capacity]; \
} name##_t; \
void name##_init(volatile name##_t *buffer) { buffer->tail = buffer->count = 0; } \
bool name##_append(volatile name##_t *buffer, type element) { if (buffer->count == _CB_COUNT(buffer)) return false; buffer->buf[_CB_WRAP(buffer, buffer->tail + buffer->count)] = element; ++buffer->count; return true; } \
bool name##_append_range(volatile name##_t *buffer, type *elements, int count) { \
for (int i = 0; i < count; ++i) \
if (!name##_append(buffer, elements[i])) return false; \
return true; \
} \
int name##_take(volatile name##_t *buffer, type *dest, uint32_t count) { \
count = count > buffer->count ? buffer->count : count; \
for (uint32_t i = 0; i < count; ++i) { \
dest[i] = buffer->buf[_CB_WRAP(buffer, buffer->tail)]; \
++buffer->tail; --buffer->count; \
} \
return count; \
} \
#endif

22
app/src/incp_handler.c Normal file
View File

@@ -0,0 +1,22 @@
#include "incp_handler.h"
#include "main.h"
#define INCP_IMPL_CALC
#include "gen_wrapper.h"
void handle_incp(msg_buf_t *msgs)
{
uint8_t *bytes;
uint32_t len;
err_t err;
err = msg_buf_peek(msgs, (void**)&bytes, &len);
if (err == ERR_EMPTY)
return;
if (err != ERR_OK)
Error_Handler();
//TODO: React to INCP
}

8
app/src/incp_handler.h Normal file
View File

@@ -0,0 +1,8 @@
#ifndef INCP_HANDLER_H_
#define INCP_HANDLER_H_
#include "msg_buf.h"
void handle_incp(msg_buf_t *msgs);
#endif

View File

@@ -6,14 +6,15 @@
#include "stm32f4xx_hal_gpio.h" #include "stm32f4xx_hal_gpio.h"
#include "stm32f4xx_ll_i2c.h" #include "stm32f4xx_ll_i2c.h"
#include "gen_wrapper.h" #include "incp_handler.h"
#include "msg_buf.h"
#include "circular_buffer.h" #define I2C_BUF_SIZE 512
uint8_t i2c_buf[I2C_BUF_SIZE];
#define CIRC_BUF_SIZE (2*1024) #define MSG_BUF_CAPACITY (2*1024)
CIRCULAR_BUFFER_ALL(circ_buff, uint8_t, CIRC_BUF_SIZE) uint8_t i2c_msg_store[MSG_BUF_CAPACITY];
msg_buf_t i2c_msgs;
static volatile circ_buff_t i2c_buf;
void I2C1_EV_IRQHandler() void I2C1_EV_IRQHandler()
{ {
@@ -24,8 +25,10 @@ void I2C1_EV_IRQHandler()
//Skip checking if receiving or transmitting (should always be false) //Skip checking if receiving or transmitting (should always be false)
LL_I2C_ClearFlag_ADDR(I2C1); LL_I2C_ClearFlag_ADDR(I2C1);
//Allow buffer to grow until full int head = 0;
while (i2c_buf.count < _CB_COUNT(&i2c_buf))
//Allow buffer to grow until full (and inclusive)
while (head <= I2C_BUF_SIZE)
{ {
//Wait for data or stop flag //Wait for data or stop flag
while (!LL_I2C_IsActiveFlag_STOP(I2C1) && !LL_I2C_IsActiveFlag_RXNE(I2C1)); while (!LL_I2C_IsActiveFlag_STOP(I2C1) && !LL_I2C_IsActiveFlag_RXNE(I2C1));
@@ -37,14 +40,16 @@ void I2C1_EV_IRQHandler()
} }
else //Data received else //Data received
{ {
if (head >= I2C_BUF_SIZE) //Overflow for sure
Error_Handler();
uint8_t data = LL_I2C_ReceiveData8(I2C1); uint8_t data = LL_I2C_ReceiveData8(I2C1);
circ_buff_append_range(&i2c_buf, &data, 1); i2c_buf[head++] = data;
} }
} }
//Overflow or stop condition reached //Stop condition reached, save msg
if (i2c_buf.count >= _CB_COUNT(&i2c_buf)) msg_buf_push(&i2c_msgs, i2c_buf, head);
Error_Handler();
} }
bool I2C1_transmit_master(uint8_t addr, uint8_t *buf, uint8_t count) bool I2C1_transmit_master(uint8_t addr, uint8_t *buf, uint8_t count)
@@ -85,10 +90,16 @@ bool I2C1_transmit_master(uint8_t addr, uint8_t *buf, uint8_t count)
int my_main() int my_main()
{ {
msg_buf_init(&i2c_msgs, i2c_msg_store, sizeof(i2c_msg_store));
while (1) while (1)
{ {
HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin); HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
HAL_Delay(500); for (int i = 0; i < 500; ++i)
{
HAL_Delay(1);
handle_incp(&i2c_msgs);
}
} }
return 0; return 0;

113
app/src/msg_buf.c Normal file
View File

@@ -0,0 +1,113 @@
#include "msg_buf.h"
typedef uint16_t len_prefix_t;
#define _PADDING_BYTE (0xFF)
#define _PADDING_VALUE ((len_prefix_t)0xFFFF)
#define _LENGTH_SIZE (sizeof(len_prefix_t))
int msg_buf_init(msg_buf_t *buf, void *storage, uint32_t capacity)
{
if ((capacity % _LENGTH_SIZE) != 0)
return ERR_ARGS;
buf->storage = storage;
buf->capacity = capacity;
buf->head = buf->count = 0;
return ERR_OK;
}
static inline void pad_to_end(msg_buf_t *buf)
{
//Pad to end, advancing head and count
uint32_t len = buf->capacity - buf->head;
memset(buf->storage + buf->head, _PADDING_BYTE, len);
buf->count += len;
buf->head = 0;
}
int msg_buf_push(msg_buf_t *buf, void *data, uint32_t len)
{
if (len > MAX_LEN)
return ERR_ARGS;
//Length of prefix+message
uint32_t len_f = _LENGTH_SIZE + len;
if (buf->capacity - buf->head < len_f) //No space ahead
{
if (buf->head - buf->count < len_f) //No space behind
return ERR_FULL;
pad_to_end(buf);
//Reset head
buf->head = 0;
}
//At this point head is at the first free location and there is enough space after it
*(len_prefix_t*)(buf->storage + buf->head) = len;
memcpy(buf->storage + buf->head + _LENGTH_SIZE, buf, len);
buf->head += len_f;
buf->count += len_f;
return ERR_OK;
}
static inline uint32_t buf_tail(msg_buf_t *buf)
{
if (buf->head >= buf->count)
return buf->head - buf->count;
return buf->capacity + buf->head - buf->count;
}
int msg_buf_peek(msg_buf_t *buf, void **ptr, uint32_t *len)
{
if (buf->count == 0)
return ERR_EMPTY;
uint32_t tail = buf_tail(buf);
//No need to worry about padding, pop will do cleanups
*len = *(uint16_t*)(buf->storage + tail);
*ptr = buf->storage + tail + _LENGTH_SIZE;
return ERR_OK;
}
int msg_buf_pop(msg_buf_t *buf)
{
if (buf->count == 0)
return ERR_EMPTY;
uint32_t tail = buf_tail(buf);
uint32_t len = *(uint16_t*)(buf->storage + tail);
buf->count -= _LENGTH_SIZE + len;
//If empty, reset head to start (minimize fragmentation)
if (buf->count == 0)
{
buf->head = 0;
return ERR_OK;
}
//At this point tail can either be at thestart of padding
// -> Clear padding (wraps back to 0)
tail = buf_tail(buf);
len = *(uint16_t*)(buf->storage + tail);
//Leave as is if not padding
if (len != _PADDING_VALUE)
return ERR_OK;
//Clear padding
uint32_t padding_len = buf->capacity - tail;
buf->count -= padding_len;
//Tail is now at storage start.
//If the buffer is empty, it is also aligned as a consequence.
return ERR_OK;
}

36
app/src/msg_buf.h Normal file
View File

@@ -0,0 +1,36 @@
#ifndef MSG_BUF_H_
#define MSG_BUF_H_
#include <stdint.h>
#include <stdbool.h>
#include <string.h>
#define MAX_LEN (0xFFFE)
typedef uint32_t err_t;
#define ERR_OK ((err_t)0)
#define ERR_ARGS ((err_t)1)
#define ERR_FULL ((err_t)2)
#define ERR_EMPTY ((err_t)3)
// Message buffer
// Variable-sized entry circular buffer
// No modulo, contiguous memory read/write
// Maximum message size 0xFFFE (0xFFFF is padding)
// Minimum message size 0
// NOT thread/task safe
typedef struct msg_buf {
uint8_t *storage;
uint32_t capacity;
uint32_t head, count;
} msg_buf_t;
int msg_buf_init(msg_buf_t *buf, void *storage, uint32_t capacity);
int msg_buf_push(msg_buf_t *buf, void *data, uint32_t len);
int msg_buf_peek(msg_buf_t *buf, void **ptr, uint32_t *len);
int msg_buf_pop(msg_buf_t *buf);
#endif