From f306df9daf542f3494521dd91dcf60d10cc7c014 Mon Sep 17 00:00:00 2001 From: Didas72 Date: Fri, 7 Nov 2025 15:57:11 +0000 Subject: [PATCH] First draft --- .gitignore | 2 + README.md | 15 ++ doc/examples/OBC+TTC/shared/bus/bus.h | 10 + .../OBC+TTC/shared/incp/asn1/asn1_wrapper.c | 11 ++ .../OBC+TTC/shared/incp/asn1/asn1_wrapper.h | 23 +++ .../shared/incp/asn1/incp_generated.asn | 19 ++ .../OBC+TTC/shared/incp/asn1/incp_static.asn | 51 +++++ doc/examples/OBC+TTC/shared/incp/incp2.h | 11 ++ doc/examples/OBC+TTC/shared/incp/messaging.h | 15 ++ doc/examples/OBC+TTC/shared/incp/service.c | 177 ++++++++++++++++++ doc/examples/OBC+TTC/shared/incp/service.h | 75 ++++++++ doc/examples/OBC+TTC/subsystems/OBC/main.c | 43 +++++ doc/examples/OBC+TTC/subsystems/TTC/main.c | 50 +++++ 13 files changed, 502 insertions(+) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 doc/examples/OBC+TTC/shared/bus/bus.h create mode 100644 doc/examples/OBC+TTC/shared/incp/asn1/asn1_wrapper.c create mode 100644 doc/examples/OBC+TTC/shared/incp/asn1/asn1_wrapper.h create mode 100644 doc/examples/OBC+TTC/shared/incp/asn1/incp_generated.asn create mode 100644 doc/examples/OBC+TTC/shared/incp/asn1/incp_static.asn create mode 100644 doc/examples/OBC+TTC/shared/incp/incp2.h create mode 100644 doc/examples/OBC+TTC/shared/incp/messaging.h create mode 100644 doc/examples/OBC+TTC/shared/incp/service.c create mode 100644 doc/examples/OBC+TTC/shared/incp/service.h create mode 100644 doc/examples/OBC+TTC/subsystems/OBC/main.c create mode 100644 doc/examples/OBC+TTC/subsystems/TTC/main.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..b853745 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +**.vscode/ +**out/ diff --git a/README.md b/README.md new file mode 100644 index 0000000..97c2369 --- /dev/null +++ b/README.md @@ -0,0 +1,15 @@ +# INCP2 + +This is the home of the INCP remastering. + +## QOL implemented + +- Automatic 'answering' of requests (pings, datareqs, etc.) + +## Current problems and things to change + +- Subsystem code should not see ASN1 Encode/Decode functions. (Split ASN1 code files, structs and typedefs on one side, functions on other?) + +## Improvements to make + +- Optional metrics (messages of each type tx/rx, etc.) diff --git a/doc/examples/OBC+TTC/shared/bus/bus.h b/doc/examples/OBC+TTC/shared/bus/bus.h new file mode 100644 index 0000000..5f8a1b2 --- /dev/null +++ b/doc/examples/OBC+TTC/shared/bus/bus.h @@ -0,0 +1,10 @@ +#pragma once + +#include +#include + +//This shoulb be handled by CSP +#define ADDRESS_OBC ((int)1) +#define ADDRESS_TTC ((int)2) + +bool bus_send(int destination, void *buf, size_t size); diff --git a/doc/examples/OBC+TTC/shared/incp/asn1/asn1_wrapper.c b/doc/examples/OBC+TTC/shared/incp/asn1/asn1_wrapper.c new file mode 100644 index 0000000..77b6706 --- /dev/null +++ b/doc/examples/OBC+TTC/shared/incp/asn1/asn1_wrapper.c @@ -0,0 +1,11 @@ +#include "asn1_wrapper.h" + +err_t incp_decode_header(BitStream *in_bs, IncpMsg *msg) +{ + int asn1_err = 0; + + if (!IncpMsg_Decode(msg, in_bs, &asn1_err)) + return ERR_ERROR; //TODO: Proper error setting based on asn1_err + + return ERR_SUCCESS; +} diff --git a/doc/examples/OBC+TTC/shared/incp/asn1/asn1_wrapper.h b/doc/examples/OBC+TTC/shared/incp/asn1/asn1_wrapper.h new file mode 100644 index 0000000..110f0af --- /dev/null +++ b/doc/examples/OBC+TTC/shared/incp/asn1/asn1_wrapper.h @@ -0,0 +1,23 @@ +// asn1_wrapper.h - Wraps all ASN.1 generated files to conform with the rest of the C interface (return type to err_t +// and alike). +// Should only be used inside INCP implementation. + +#pragma once + +#ifndef _INCP_INTERNAL +#error "asn1_wrapper.h should not be imported outside the implementation of INCP" +#endif + +#include "incp2.h" +#include "messaging.h" +#include "out/incp_static.h" + +typedef IncpMsg_selection incp_msgt_t; + +err_t incp_encode_header(BitStream *bs, IncpMsg *msg); +err_t incp_decode_header(BitStream *bs, IncpMsg *msg); + +err_t incp_encode_datareq(BitStream *bs, U32 id); +err_t incp_decode_datareq(BitStream *bs, U32 id); +err_t incp_encode_dataret(BitStream *bs, AnyData *data); +err_t incp_decode_dataret(BitStream *bs, AnyData *data); diff --git a/doc/examples/OBC+TTC/shared/incp/asn1/incp_generated.asn b/doc/examples/OBC+TTC/shared/incp/asn1/incp_generated.asn new file mode 100644 index 0000000..9383a3b --- /dev/null +++ b/doc/examples/OBC+TTC/shared/incp/asn1/incp_generated.asn @@ -0,0 +1,19 @@ +INCP-Generated DEFINITIONS AUTOMATIC TAGS ::= BEGIN + +EXPORTS ALL; +IMPORTS U32 FROM INCP-Types; + +TTC-TxTotal ::= SEQUENCE { + bytes U32 +} + +TTC-RxTotal ::= SEQUENCE { + bytes U32 +} + +AnyData ::= CHOICE { + ttcTxTotal TTC-TxTotal, + ttcRxTotal TTC-RxTotal +} + +END diff --git a/doc/examples/OBC+TTC/shared/incp/asn1/incp_static.asn b/doc/examples/OBC+TTC/shared/incp/asn1/incp_static.asn new file mode 100644 index 0000000..844afcf --- /dev/null +++ b/doc/examples/OBC+TTC/shared/incp/asn1/incp_static.asn @@ -0,0 +1,51 @@ +INCP-Types DEFINITIONS AUTOMATIC TAGS ::= BEGIN + +EXPORTS ALL; + +U8 ::= INTEGER(0..255) +U16 ::= INTEGER(0..65535) +U24 ::= INTEGER(8388608..16777215) +U32 ::= INTEGER(0..4294967295) +U64 ::= INTEGER(0..18446744073709551615) +I8 ::= INTEGER(-128..127) +I16 ::= INTEGER(-32768..32767) +I24 ::= INTEGER(-8388608..8388607) +I32 ::= INTEGER(-2147483648..2147483647) + +END + +INCP-Static DEFINITIONS AUTOMATIC TAGS ::= BEGIN + +IMPORTS U8, U16, U32 FROM INCP-Types + AnyData FROM INCP-Generated; + +PingMsg ::= SEQUENCE { + payload SEQUENCE (SIZE(32)) OF U8 +} + +DataReqMsg ::= SEQUENCE { + id U32 -- REVIEW: How to limit range to only accept IDs that are valid +} + +DataRetMsg ::= SEQUENCE { + data AnyData +} + +CommandReqMsg ::= SEQUENCE { + id U16 +} + +CommandRetMsg ::= SEQUENCE { + id U16 +} + +IncpMsg ::= CHOICE { + ping PingMsg, + pong PingMsg, + dataReq DataReqMsg, + dataRet DataRetMsg, + commandReq CommandReqMsg, + commandRet CommandRetMsg +} + +END diff --git a/doc/examples/OBC+TTC/shared/incp/incp2.h b/doc/examples/OBC+TTC/shared/incp/incp2.h new file mode 100644 index 0000000..fb22b5d --- /dev/null +++ b/doc/examples/OBC+TTC/shared/incp/incp2.h @@ -0,0 +1,11 @@ +// incp2.h - Defines types common to all INCP interfaces. + +#pragma once + +typedef enum { + ERR_SUCCESS = 0, + ERR_ERROR, + ERR_NOT_IMPL, + ERR_NOT_MINE, +} err_t; + diff --git a/doc/examples/OBC+TTC/shared/incp/messaging.h b/doc/examples/OBC+TTC/shared/incp/messaging.h new file mode 100644 index 0000000..eed2a77 --- /dev/null +++ b/doc/examples/OBC+TTC/shared/incp/messaging.h @@ -0,0 +1,15 @@ +// messaging.h - Defines structures used during (de)construction of messages. + +#pragma once + +#include +#include + +#include "incp2.h" + +typedef int endpoint_t; //REVIEW: Figure this one out. Where the values come from, where they + // are defined, etc. +#define INCP_ENDPOINT_NVAL (~(endpoint_t)0) +#define INCP_ENDPOINT_TTC ((endpoint_t)1) + +#define DEFAULT_MSGBUF_SIZE 64 diff --git a/doc/examples/OBC+TTC/shared/incp/service.c b/doc/examples/OBC+TTC/shared/incp/service.c new file mode 100644 index 0000000..5fc6055 --- /dev/null +++ b/doc/examples/OBC+TTC/shared/incp/service.c @@ -0,0 +1,177 @@ +#define _INCP_INTERNAL + +#include + +#include "incp2.h" +#include "service.h" +#include "messaging.h" +#include "asn1/asn1_wrapper.h" + + + +static err_t handle_incoming(endpoint_t source, BitStream *in_bs); + + + +void incp_receiver_task(void *args) +{ + (void)args; //Stfu + + while (1) + { + //LATER: Blocking wait for RTOS queue to fetch bus / radio message (go wild on that routing) + BitStream in_bs = { 0 }; // <-- Populate from transport + endpoint_t source = INCP_ENDPOINT_NVAL; // <-- Populate from transport + + handle_incoming(source, &in_bs); + } +} + + + +err_t incp_async_datareq(endpoint_t subsystem, U32 id) +{ + err_t err; //Don't init on purpose + BitStream out_bs; + uint8_t buf[DEFAULT_MSGBUF_SIZE]; + BitStream_Init(&out_bs, buf, sizeof(buf)); + + IncpMsg msg; + msg.kind = dataReq_PRESENT; + msg.u.dataReq.id = id; + + err = incp_encode_header(&out_bs, &msg); + if (err != ERR_SUCCESS) goto _exit; + + err = impl_transmit(subsystem, buf, BitStream_GetLength(&out_bs)); + +_exit: + return err; +} + +err_t incp_async_ping(endpoint_t subsystem, uint8_t *bytes) +{ + err_t err; //Don't init on purpose + BitStream out_bs; + uint8_t buf[DEFAULT_MSGBUF_SIZE]; + BitStream_Init(&out_bs, buf, sizeof(buf)); + + IncpMsg msg; + msg.kind = ping_PRESENT; + memcpy(&msg.u.ping.payload, bytes != NULL ? bytes : "I am a very fancy ping payload!", 32); + + err = incp_encode_header(&out_bs, &msg); + if (err != ERR_SUCCESS) goto _exit; + + err = impl_transmit(subsystem, buf, BitStream_GetLength(&out_bs)); + +_exit: + return err; +} + + + +static inline err_t handle_incoming_ping(endpoint_t source, IncpMsg *in_msg, BitStream *in_bs) +{ + (void)in_bs; + err_t err; //Don't init on purpose + BitStream out_bs; + uint8_t buf[DEFAULT_MSGBUF_SIZE]; + BitStream_Init(&out_bs, buf, sizeof(buf)); + + IncpMsg msg = *in_msg; + msg.kind = pong_PRESENT; + + err = incp_encode_header(&out_bs, &msg); + if (err != ERR_SUCCESS) goto _exit; + + err = impl_transmit(source, buf, BitStream_GetLength(&out_bs)); //"Destroy a Ghast with a fireball" + +_exit: + return err; +} + +static inline err_t handle_incoming_pong(endpoint_t source, IncpMsg *in_msg, BitStream *in_bs) +{ + (void)in_bs; + err_t err; //Don't init on purpose + + impl_callback_pong(source, in_msg); + err = ERR_SUCCESS; + +_exit: + return err; +} + +static inline err_t handle_incoming_datareq(endpoint_t source, IncpMsg *in_msg, BitStream *in_bs) +{ + err_t err; //Don't init on purpose + BitStream out_bs; + uint8_t buf[DEFAULT_MSGBUF_SIZE]; + BitStream_Init(&out_bs, buf, sizeof(buf)); + + AnyData data = { 0 }; + data.kind = in_msg->u.dataReq.id; //REVIEW: Dubious types + + err = impl_populate_dataret(&data); + if (err != ERR_SUCCESS) goto _exit; + + err = incp_encode_dataret(&out_bs, &data); + if (err != ERR_SUCCESS) goto _exit; + + err = impl_transmit(source, buf, BitStream_GetLength(&out_bs)); + +_exit: + return err; +} + +static inline err_t handle_incoming_dataret(endpoint_t source, IncpMsg *in_msg, BitStream *in_bs) +{ + err_t err; //Don't init on purpose + AnyData data; //Careful with lifetime of this! Rust my beloved (never tried it) + + err = incp_decode_dataret(in_bs, &data); + if (err != ERR_SUCCESS) goto _exit; + + impl_callback_dataret(source, &data); + err = ERR_SUCCESS; + +_exit: + return err; +} + +static err_t handle_incoming(endpoint_t source, BitStream *in_bs) +{ + err_t err; //Don't init on purpose + IncpMsg msg; + + + err = incp_decode_header(in_bs, &msg); + if (err != ERR_SUCCESS) goto _exit; + + switch (msg.kind) + { + case ping_PRESENT: + err = handle_incoming_ping(source, &msg, in_bs); + break; + + case pong_PRESENT: + err = handle_incoming_pong(source, &msg, in_bs); + break; + + case dataReq_PRESENT: + err = handle_incoming_datareq(source, &msg, in_bs); + break; + + case dataRet_PRESENT: + err = handle_incoming_dataret(source, &msg, in_bs); + break; + + default: + err = ERR_NOT_IMPL; + break; + } + +_exit: + return err; +} diff --git a/doc/examples/OBC+TTC/shared/incp/service.h b/doc/examples/OBC+TTC/shared/incp/service.h new file mode 100644 index 0000000..8881359 --- /dev/null +++ b/doc/examples/OBC+TTC/shared/incp/service.h @@ -0,0 +1,75 @@ +// serivce.h - Defines INCP service interface and functions to implement per subsystem. + +#pragma once + +#include "incp2.h" +#include "messaging.h" +#include "asn1/out/incp_generated.h" + + + +// ========================== +// === RTOS SETUP RELATED === +// ========================== + +/// @brief [DO NOT CALL] Entry point for the receiver task of the INCP service. +/// @param args Not used +/// @remark Do not call directly, instead, pass it to the RTOS during task creation. +void incp_receiver_task(void *args); + + + +// ======================== +// === INCP SERVICE API === +// ======================== + +/// @brief Sends a datareq message of a given ID to a given subsystem. +/// @param subsystem The subsystem to target. +/// @param id The ID of the variable/report to request. +/// @return ERR_SUCCESS if successfully transmitted, an adequate error otherwise. +err_t incp_async_datareq(endpoint_t subsystem, U32 id); + +/// @brief Sends a ping message to a given subsystem. +/// @param subsystem The subsystem to target. +/// @param bytes The data to populate the ping with. Must NULL or contain 32 readable bytes. +/// @return ERR_SUCCESS if successfully transmitted, an adequate error otherwise. +err_t incp_async_ping(endpoint_t subsystem, uint8_t *bytes); + + + +// ================================== +// === TO IMPLEMENT PER SUBSYSTEM === +// ================================== + +/// @brief Implement this function to send (through whatever means, that's a you problem) the given buffer to a given +/// destination. +/// @param destination Where to send the buffer. +/// @param buf The buffer to send. +/// @param size The length of the data in the buffer. +/// @return ERR_SUCCESS if successful, an adequate error otherwise. +/// @remark Do not __attribute__((weak)) to force linker error. +err_t impl_transmit(endpoint_t destination, void *buf, size_t size); + +/// @brief Implement this function to populate msg_buf with the requested variables. +/// @param data The destination to write to. Includes the variable/report id, which should not be changed. +/// @return ERR_SUCCESS if successful, an adequate error otherwise. +/// @remark Do not __attribute__((weak)) to force linker error. +err_t impl_populate_dataret(AnyData *data); + + + +// === Callbacks === + +/// @brief Implement this function as the callback handler to a dataret message. Can (but shoudln't) be empty. +/// @param source The subsystem that send the message. +/// @param data The buffer that holds the data. (See remarks) +/// @remark Do not copy this value by reference, it's validity is only ensured during the execution of this function. +/// @remark Do not __attribute__((weak)) to force linker error if undefined. +void impl_callback_dataret(endpoint_t source, AnyData *data); + +/// @brief Implement this function as the callback handler to a pong message. Can (but shoudln't) be empty. +/// @param source The subsystem that send the message. +/// @param pong The received pong. (See remarks) +/// @remark Do not copy this value by reference, it's validity is only ensured during the execution of this function. +/// @remark Do not __attribute__((weak)) to force linker error if undefined. +void impl_callback_pong(endpoint_t source, PingMsg *pong); diff --git a/doc/examples/OBC+TTC/subsystems/OBC/main.c b/doc/examples/OBC+TTC/subsystems/OBC/main.c new file mode 100644 index 0000000..65d3bce --- /dev/null +++ b/doc/examples/OBC+TTC/subsystems/OBC/main.c @@ -0,0 +1,43 @@ +#include + +#include "../../shared/incp/service.h" +#include "../../shared/incp/asn1/out/incp_generated.h" +#include "../../shared/bus/bus.h" + + + +//In this example, OBC will only ping and then request a variable from TTC + + + +int main() +{ + incp_async_ping(INCP_ENDPOINT_TTC, NULL); + incp_async_datareq(INCP_ENDPOINT_TTC, ttcRxTotal_PRESENT); + + for (;;); + return 1; +} + + + +// === SUBSYSTEM SPECIFIC INCP IMPLEMENTATIONS === +err_t impl_transmit(endpoint_t destination, void *buf, size_t size) +{ + bus_send(destination, buf, size); +} + +err_t impl_populate_dataret(AnyData *data) +{ + //LATER: Populate or deny +} + +void impl_callback_dataret(endpoint_t source, AnyData *data) +{ + //LATER: Do whatever +} + +void impl_callback_pong(endpoint_t source, PingMsg *pong) +{ + //LATER: Do whatever +} diff --git a/doc/examples/OBC+TTC/subsystems/TTC/main.c b/doc/examples/OBC+TTC/subsystems/TTC/main.c new file mode 100644 index 0000000..1c435e8 --- /dev/null +++ b/doc/examples/OBC+TTC/subsystems/TTC/main.c @@ -0,0 +1,50 @@ +#include "../../shared/incp/service.h" +#include "../../shared/incp/asn1/out/incp_generated.h" +#include "../../shared/bus/bus.h" + + + +//In this example, TTC will be passive and will only reply to datareqs and pings + + + +int main() +{ + for (;;); + return 1; +} + + + +// === SUBSYSTEM SPECIFIC INCP IMPLEMENTATIONS === +err_t impl_transmit(endpoint_t destination, void *buf, size_t size) +{ + bus_send(destination, buf, size); +} + +err_t impl_populate_dataret(AnyData *data) +{ + switch (data->kind) + { + case ttcRxTotal_PRESENT: + data->u.ttcRxTotal.bytes = 69; //LATER: Proper data + return ERR_SUCCESS; + + case ttcTxTotal_PRESENT: + data->u.ttcTxTotal.bytes = 420; //LATER: Proper data + return ERR_SUCCESS; + + default: + return ERR_NOT_MINE; + } +} + +void impl_callback_dataret(endpoint_t source, AnyData *data) +{ + //LATER: Do whatever +} + +void impl_callback_pong(endpoint_t source, PingMsg *pong) +{ + //LATER: Do whatever +}