diff --git a/EmbededSw/src/Makefile b/EmbededSw/src/Makefile new file mode 100644 index 0000000000000000000000000000000000000000..97cfb7464350ae286a6c15d26b44f945f227f984 --- /dev/null +++ b/EmbededSw/src/Makefile @@ -0,0 +1,30 @@ +CC=gcc +CFLAGS=-W -std=c99 -Wall -Wbad-function-cast -Wcast-align -Wconversion -Wnull-dereference -Wshadow -Wswitch-enum -Wduplicated-branches -Wduplicated-cond -Wformat-signedness -Wswitch-default -Wjump-misses-init -Wlogical-op -Wnested-externs -Wnormalized -Wsuggest-attribute=format +LDFLAGS= -lws2_32 +EXEC=spinoSimulator + +all: $(EXEC) + +spinoSimulator: main.o ax25/ax25.o core/command.o core/control.o core/informationMessage.o core/setup.o digipeaterMode/ModeDigipeater.o drivers/modem.o dropMsgMngt/DropMessage.o logMngt/log.o mailboxMode/mailbox.o mailboxMode/modeMailbox.o simulation/SpinoSimuServerTCP.o simulation/lecfic.o surveyMode/survey.o payloadMode/payloadMode.o experimentalMode\experimentalMode.o + $(CC) -o $@ $^ $(LDFLAGS) + +%.o: %.c + $(CC) -o $@ -c $< $(CFLAGS) + +clean: + del .\*.o + del ax25\*.o + del core\*.o + del digipeaterMode\*.o + del drivers\*.o + del dropMsgMngt\*.o + del logMngt\*.o + del mailboxMode\*.o + del simulation\*.o + del surveyMode\*.o + del payloadMode\*.o + del experimentalMode\*.o + +mrproper: clean + rm -rf $(EXEC) + diff --git a/EmbededSw/src/ax25/ax25.c b/EmbededSw/src/ax25/ax25.c new file mode 100644 index 0000000000000000000000000000000000000000..f14deac9a3e1f385f0f8bb38adf9903a913dd8cd --- /dev/null +++ b/EmbededSw/src/ax25/ax25.c @@ -0,0 +1,117 @@ +/** + * \file ax25.c + * \brief ax25 driver + * \author Xtophe + * \version 0.2 + * \date 01/08/2022 + */ + +#include +#include "../errorMngt/error.h" +#include "ax25.h" + +/** + * \fn void convertToAX25Header ( t_ax25_header *data, char *dest, char ssidDest, char *src, char ssidSrc) + * \brief convert header structure to AX25 Header + * \param header structure + * \param destination callsign + * \param SSID destionation + * \param source callsign + * \param SSID source + * + * \return void + * + */ + +void convertToAX25Header(s_ax25_header *data, unsigned char *dest, + unsigned char ssidDest, unsigned char *src, unsigned char ssidSrc) { + int i; + unsigned char c; + + data->ssidDestination = (unsigned char) (ssidDest << 1 & 0xFE); + data->ssidSource = (unsigned char) (ssidSrc << 1 & 0xFE); + for (i = 0; i < 6; i++) { + c = (unsigned char) dest[i]; + data->destinationAdress[i] = (unsigned char) (c << 1 & 0xFE); + ; + } + + for (i = 0; i < 6; i++) { + c = (unsigned char) src[i]; + data->sourceAdress[i] = (unsigned char) (c << 1 & 0xFE); + ; + } + +} +/** + * \fn void encodeAX25Header(t_ax25_header *data) + * \brief encode callsign + * \param SSID source + * + * \return void + * + */ + +void encodeAX25Header(s_ax25_header *data) { + int i = 0; + unsigned char c; + c = (unsigned char) (data->ssidDestination << 1 & 0xFE); + data->ssidDestination = c; + c = (unsigned char) (data->ssidSource << 1 & 0xFE); + data->ssidSource = c; + for (i = 0; i < 6; i++) { + c = (unsigned char) data->destinationAdress[i]; + data->destinationAdress[i] = (unsigned char) (c << 1 & 0xFE); + ; + } + + for (i = 0; i < 6; i++) { + c = (unsigned char) data->sourceAdress[i]; + data->sourceAdress[i] = (unsigned char) (c << 1 & 0xFE); + ; + } +} + +/** + * \fn int convertDataToAx25 (t_ax25_packet *data, char *rawdata, unsigned int size ) + * \brief Decode calssign from AX25 + * \param ax25 structure + * \param raw data + * \param raw data size + * + * \return error value SUCCES or ERROR_AX25_EXCEED_MAX_LENGH + * + */ +int convertDataToAx25(s_ax25_packet *data, char *rawdata, int size) { + + int error = SUCCESS; + int i; + unsigned char c; + + if (size < (int) sizeof(s_ax25_packet)) { + memcpy(data, rawdata, (size_t) size); + + /* Convert */ + c = data->header.ssidDestination; + data->header.ssidDestination = c >> 1 & 0x7F; + c = data->header.ssidSource; + data->header.ssidSource = c >> 1 & 0x7F; + + for (i = 0; i < 6; i++) { + c = data->header.destinationAdress[i]; + data->header.destinationAdress[i] = c >> 1 & 0x7F; + + } + + for (i = 0; i < 6; i++) { + c = data->header.sourceAdress[i]; + data->header.sourceAdress[i] = c >> 1 & 0x7F; + } + + } else { + error = ERROR_AX25_EXCEED_MAX_LENGH; + } + return error; + +} + diff --git a/EmbededSw/src/ax25/ax25.h b/EmbededSw/src/ax25/ax25.h new file mode 100644 index 0000000000000000000000000000000000000000..6fffaed028f472bedc2c13ca623c6ffbf383b104 --- /dev/null +++ b/EmbededSw/src/ax25/ax25.h @@ -0,0 +1,36 @@ +/** + * \file ax25.h + * \brief ax25 driver + * \author Xtophe + * \version 0.2 + * \date 01/08/2022 + */ + +#ifndef AX25_H +#define AX25_H + +#define MAX_DATA_SIZE 256 +#define CALLSIGN_SIZE 6 + +typedef struct ax25_header { + unsigned char destinationAdress[6]; + unsigned char ssidDestination; + unsigned char sourceAdress[6]; + unsigned char ssidSource; + unsigned char ctrl; + unsigned char pid; + +} s_ax25_header; + +typedef struct ax25_packet { + s_ax25_header header; + char data[MAX_DATA_SIZE]; + +} s_ax25_packet; + +extern int convertDataToAx25(s_ax25_packet *data, char *rawdata, int size); +extern void convertToAX25Header(s_ax25_header *data, unsigned char *dest, + unsigned char ssidDest, unsigned char *src, unsigned char ssidSrc); +extern void encodeAX25Header(s_ax25_header *data); + +#endif // AX25_H diff --git a/EmbededSw/src/core/command.c b/EmbededSw/src/core/command.c new file mode 100644 index 0000000000000000000000000000000000000000..b14e81e29e4b00f0f0c7b9f78dd68c7a60dc9670 --- /dev/null +++ b/EmbededSw/src/core/command.c @@ -0,0 +1,379 @@ +/** + * \file command.c + * \brief perform treatment of standard SPINO Command + * \author Xtophe + * \version 0.2 + * \date 01/08/2022 + * + * \todo renforcer l'analyse par verfication de la taille des parametres pour la gestion des commandes + */ + +#include +#include +#include "setup.h" +#include "command.h" +#include "informationMessage.h" +#include "../logMngt/log.h" +#include "../dropMsgMngt/DropMessage.h" +#include "../errorMngt/error.h" + +extern void writeData(s_ax25_packet ax25Frame, int length); +extern int changeState(short state); +/** + * \fn int reset() + * \brief réinitialise le logiciel SPINO + * + * \return SUCCESS if ok else + * ERROR_COMMAND_NOT_IMPLEMENTED + * + * \todo : int reset() is to be implemented + */ + +static unsigned char reset() { + + return ERROR_COMMAND_NOT_IMPLEMENTED; +} + +/** + * \fn int setValue(t_set_value value,t_tc_response *resp) + * \brief set value accordting to information in t_set_value strruture + * \param value structure with data to set + * \param *resp output structure with result of command + * \return SUCCESS if ok else + * ERROR_COMMAND_NOT_IMPLEMENTED + * + * \todo : int setValie() renforcer l'analyse par verfication de la taille des parametres + */ +static unsigned char setValue(const s_set_value value, t_tc_response *resp) { + + unsigned char returnValue = SUCCESS; + + resp->size = SIZE_HEADER_FIELD; + + switch (value.fied_id) { + + case VALUE_SPINO_DELAY: + gv_spinoConfig.telemetryDelay = (unsigned char) value.value[0]; + break; + + case VALUE_DELAY_INFO_MESSAGE: + memcpy(&gv_spinoConfig.delay_info_message, value.value, + sizeof(gv_spinoConfig.delay_info_message)); + break; + + case VALUE_ACTIVE_INFO_MESSAGE: + memcpy(&gv_spinoConfig.info_message_actif, value.value, + sizeof(gv_spinoConfig.info_message_actif)); + break; + + case VALUE_CALLSIGN_SRC_SPINO: + memcpy(&gv_spinoConfig.spinoSrcCallsign, value.value, CALLSIGN_SIZE); + break; + + case VALUE_CALLSIGN_DES_SPINO: + memcpy(&gv_spinoConfig.spinoDesCallsign, value.value, CALLSIGN_SIZE); + break; + + case VALUE_CALLSIGN_PAYLOAD_SPINO: + memcpy(&gv_spinoConfig.payloadCallsign, value.value, CALLSIGN_SIZE); + break; + + case VALUE_TIMESTAMP: + logger(LOG_LEVEL_INFO, "Commande VALUE_TIMESTAMP"); + memcpy(&gv_spino.timestamps, value.value, sizeof(gv_spino.timestamps)); + logger(LOG_LEVEL_INFO, "Commande VALUE_TIMESTAMP SET"); + break; + + case VALUE_LOG_LEVEL: + logger(LOG_LEVEL_INFO, "Commande VALUE_LOG_LEVEL"); + gv_SelectedLogLevel = (unsigned char) value.value[0]; + break; + default: + // generation code erreur + returnValue = ERROR_VALUE_FIELD_UNKNOW; + break; + } + // memcpy (resp->parameter,&response,resp->size ); + return returnValue; + +} +/** + * \fn int getValue(t_get_value value, t_tc_response *resp) + * \brief get value accordting to information in t_set_value strruture + * \param value structure with data to get. + * \param *resp output structure with result of command + * \return SUCCESS if ok else + * ERROR_COMMAND_NOT_IMPLEMENTED + * + * \todo : int getValue() renforcer l'analyse par verfication de la taille des parametres + */ +static unsigned char getValue(const s_get_value value, t_tc_response *resp) { + unsigned char returnValue = SUCCESS; + s_field response; + + response.field_id = value.field_id; + + switch (value.field_id) { + + case VALUE_SPINO_VERSION: + response.size = sizeof(gv_version); + memcpy(response.field_value, &gv_version, response.size); + resp->size = SIZE_HEADER_FIELD + response.size; + memcpy(resp->parameter, &response, resp->size); + break; + + case VALUE_SPINO_DELAY: + + response.size = sizeof(gv_spinoConfig.telemetryDelay); + response.field_value[0] = gv_spinoConfig.telemetryDelay; + resp->size = SIZE_HEADER_FIELD + response.size; + memcpy(resp->parameter, &response, resp->size); + break; + + case VALUE_CALLSIGN_SRC_SPINO: + response.size = 6; + memcpy(response.field_value, gv_spinoConfig.spinoSrcCallsign, 6); + resp->size = SIZE_HEADER_FIELD + response.size; + memcpy(resp->parameter, &response, resp->size); + break; + + case VALUE_CALLSIGN_DES_SPINO: + + response.size = 6; + memcpy(response.field_value, gv_spinoConfig.spinoDesCallsign, 6); + resp->size = SIZE_HEADER_FIELD + response.size; + memcpy(resp->parameter, &response, resp->size); + break; + + case VALUE_CALLSIGN_PAYLOAD_SPINO: + response.size = 6; + memcpy(response.field_value, gv_spinoConfig.payloadCallsign, 6); + resp->size = SIZE_HEADER_FIELD + response.size; + memcpy(resp->parameter, &response, resp->size); + break; + + case VALUE_LOG_LEVEL: + response.size = sizeof(gv_SelectedLogLevel); + memcpy(response.field_value, &gv_SelectedLogLevel, response.size); + resp->size = SIZE_HEADER_FIELD + response.size; + memcpy(resp->parameter, &response, resp->size); + break; + + case VALUE_ACTIVE_INFO_MESSAGE: + response.size = sizeof(gv_spinoConfig.info_message_actif); + memcpy(response.field_value, &gv_spinoConfig.info_message_actif, + response.size); + resp->size = SIZE_HEADER_FIELD + response.size; + memcpy(resp->parameter, &response, resp->size); + break; + + case VALUE_DELAY_INFO_MESSAGE: + response.size = sizeof(gv_spinoConfig.delay_info_message); + memcpy(response.field_value, &gv_spinoConfig.delay_info_message, + response.size); + resp->size = SIZE_HEADER_FIELD + response.size; + memcpy(resp->parameter, &response, resp->size); + break; + + case VALUE_TIMESTAMP: /*! Non implemented !*/ + default: + // generation code erreur + sprintf(gvLogMsg, "valeur inconnue %d \r\n", value.field_id); + logger(LOG_LEVEL_CRITICAL, gvLogMsg); + returnValue = ERROR_VALUE_FIELD_UNKNOW; + response.size = 0; + resp->size = SIZE_HEADER_FIELD; + memcpy(resp->parameter, &response, resp->size); + break; + + } + + return returnValue; + +} +/** + * \fn t_tc_response interpretcommand(const t_command cmd) + * \brief interpretCommand + * \param cmd structure + * \return SUCCESS if ok else + * ERROR_COMMAND_NOT_IMPLEMENTED + * \todo implementer LOAD PROG + */ + +t_tc_response interpretcommand(s_command cmd) { + + t_tc_response resp; + unsigned char reponse = SUCCESS; + + resp.header.responseType = RESULT_CMD; + resp.header.timeStamp = gv_spino.timestamps; + resp.header.cmd_id = cmd.id; + + switch (cmd.id) { + case CMD_RESET: + logger(LOG_LEVEL_INFO, "Commande RESET"); + reponse = reset(); + break; + case SET_VALUE: /* modify configuration value */ + logger(LOG_LEVEL_INFO, "Commande SET VALUE"); + s_set_value setvalue; + memcpy(&setvalue, cmd.parameter, cmd.size); + reponse = setValue(setvalue, &resp); + break; + + case SET_STATE: /*modify mode */ + logger(LOG_LEVEL_INFO, "Commande SET STATE"); + if (cmd.size == 1) { + // gv_spino.currentState = cmd.parameter[0]; + reponse = changeState((int) cmd.parameter[0]); + + } + resp.size = 0; + break; + + case GET_VALUE: // return value of field + + logger(LOG_LEVEL_INFO, "Commande GET VALUE"); + s_get_value getvalue; + memcpy(&getvalue, cmd.parameter, cmd.size); + reponse = getValue(getvalue, &resp); + break; + + case GET_CONGIG: // return Configuration structure + logger(LOG_LEVEL_INFO, "Commande GET CONFIG"); + resp.size = sizeof(s_configuration_spino); + memcpy(resp.parameter, &gv_spinoConfig, sizeof(s_configuration_spino)); + break; + + case PROG_INIT: // initialise memory prog structure + logger(LOG_LEVEL_INFO, "Commande PROG INIT"); + gv_prog.indexCourrant = 0; + for (int i = 0; i < MAX_MEM_PRG; i++) { + gv_prog.memory[i] = 0; + } + resp.size = 0; + break; + + case PROG_LOAD: + logger(LOG_LEVEL_INFO, "Commande PROG LOAD"); + s_load_prg load_prg; + memcpy(&load_prg, cmd.parameter, sizeof(s_load_prg)); + // check index + if (load_prg.index + MAX_MEM_PRG_LOAD > MAX_MEM_PRG) { + reponse = ERROR_PROG_INDEX_OUT_OF_BOUND; + } else if (gv_prog.indexCourrant == load_prg.index) { + if (memcmp(load_prg.mem1, load_prg.mem2, MAX_MEM_PRG_LOAD) == 0) { + memcpy(&gv_prog.memory[gv_prog.indexCourrant], load_prg.mem1, + MAX_MEM_PRG_LOAD); + gv_prog.indexCourrant += MAX_MEM_PRG_LOAD; + + s_field response; + response.field_id = PROG_INDEX; + response.size = sizeof(s_configuration_spino); + memcpy(resp.parameter, &gv_spinoConfig, + sizeof(s_configuration_spino)); + resp.size = SIZE_HEADER_FIELD + response.size; + } else { + reponse = ERROR_PROG_MEM1_MEM2_NOT_EQUAL; + + } + + } else { + reponse = ERROR_PROG_INDEX_NOT_EQUAL; + } + break; + case PROG_CHECK: + logger(LOG_LEVEL_INFO, "Commande PROG CHECK"); + reponse = ERROR_COMMAND_NOT_IMPLEMENTED; + resp.size = 0; + break; + case PROG_SET_ADDRESS: + logger(LOG_LEVEL_INFO, "Commande SET ADRESS"); + logger(LOG_LEVEL_CRITICAL, gvLogMsg); + reponse = ERROR_COMMAND_NOT_IMPLEMENTED; + resp.size = 0; + break; + case GET_LAST_DROPED_MESSAGE: + + logger(LOG_LEVEL_CRITICAL, "Commande GET_LAST_DROPED_MESSAGE"); + reponse = getLastDroppedMessage(&resp); + break; + case GET_ALL_DROPED_MESSAGE: + logger(LOG_LEVEL_INFO, "Commande GET_ALL_DROPED_MESSAGE"); + reponse = getAllDroppedMessage(&resp); + break; + case GET_LAST_LOG: + + logger(LOG_LEVEL_CRITICAL, "Commande GET_LAST_LOG"); + reponse = getLastLog(&resp); + + break; + case GET_ALL_LOG: + logger(LOG_LEVEL_INFO, "Commande GET_ALL_LOG"); + reponse = getAllLogs(&resp); + break; + + case SET_INFO_MESSAGE: + logger(LOG_LEVEL_INFO, "Commande SET_INFO_MESSAGE"); + reponse = setInfoMessage(cmd.parameter, &resp); + break; + case DEL_INFO_MESSAGE: + logger(LOG_LEVEL_INFO, "Commande DEL_INFO_MESSAGE"); + reponse = delInfoMessage(cmd.parameter[0], &resp); + break; + + default: + // generation code erreur + logger(LOG_LEVEL_CRITICAL, "erreur cmd %d "); + reponse = ERROR_COMMAND_UNKNOW; + resp.size = 0; + + break; + } + + if (reponse != SUCCESS) { + resp.header.error_code = reponse; + logger(LOG_LEVEL_INFO, "ERREUR COMMAND"); + } else { + resp.header.error_code = SUCCESS; + } + return resp; +} + +/** + * \fn void processCommand(t_ax25_packet data_ax25) + * \brief process command ax25 packet + * \param Ax25 packet + * \return SUCCESS if or Error code + * + */ +void processCommand(s_ax25_packet data_ax25) { + + t_tc_response result; + s_command cmd; + + gv_spino.nbCommandeReceived++; + memcpy(&cmd, data_ax25.data, sizeof(s_command)); + if (cmd.key != gv_spino_cmd_key) { + result.header.responseType = RESULT_CMD; + result.header.timeStamp = gv_spino.timestamps; + result.header.cmd_id = cmd.id; + result.header.error_code = ERROR_COMMAND_WITH_WRONG_KEY; + result.size = 0; + } else { + result = interpretcommand(cmd); + } + + if (result.header.error_code != SUCCESS) { + gv_spino.nbCommandeWithError++; + } + s_ax25_packet ax25Frame; + ax25Frame.header = gv_headerTlm; + memcpy(ax25Frame.data, &result, TC_REPONSE_HEADER_SIZE + result.size); + /* envoyer la reponse de la commande */ + writeData(ax25Frame, TC_REPONSE_HEADER_SIZE + result.size); + sprintf(gvLogMsg, "RESULT COMMAND %x %x ", result.header.cmd_id, + result.header.error_code); + logger(LOG_LEVEL_CRITICAL, gvLogMsg); +} + diff --git a/EmbededSw/src/core/command.h b/EmbededSw/src/core/command.h new file mode 100644 index 0000000000000000000000000000000000000000..a08b9be109a8a8116db2a02c500690f35f3dcc18 --- /dev/null +++ b/EmbededSw/src/core/command.h @@ -0,0 +1,114 @@ +#ifndef COMMAND_H +#define COMMAND_H + +#define PARAMETER_SIZE 256 /*!< Max size of command parameter. */ +#define FIELD_SIZE 32 /*!< Max size of field parameter. */ + +/* define type of response */ + +#define RESULT_CMD 128 /*!< response type : Result from command received by SPINO */ +#define TELEMETRY 64 /*!< response type : SPINO Telemetry */ +#define INFORMATION_MSG 65 /*!< response type : SPINO Information Message */ +#define RESULT_DROP_MESSAGE 32 /*!< response type : Drop message */ +#define EXPEBEACON 16 /*!< response type : Drop message */ + +/* COMMAND LIST */ +#define CMD_RESET 100 +#define SET_VALUE 101 +#define GET_VALUE 102 +#define GET_CONGIG 103 +#define GET_LAST_DROPED_MESSAGE 120 +#define GET_ALL_DROPED_MESSAGE 121 +#define GET_LAST_LOG 130 +#define GET_ALL_LOG 131 +#define SET_INFO_MESSAGE 132 +#define DEL_INFO_MESSAGE 133 + +#define SET_STATE 255 + +/* load new program */ +#define PROG_INIT 64 +#define PROG_LOAD 65 +#define PROG_CHECK 66 +#define PROG_SET_ADDRESS 67 + +/* SET GET VALUE */ + +#define VALUE_SPINO_VERSION 128 +#define VALUE_SPINO_DELAY 1 +#define VALUE_CALLSIGN_SRC_SPINO 2 +#define VALUE_CALLSIGN_DES_SPINO 3 +#define VALUE_CALLSIGN_PAYLOAD_SPINO 4 +#define VALUE_TIMESTAMP 5 +#define VALUE_LOG_LEVEL 6 +#define VALUE_ACTIVE_INFO_MESSAGE 7 +#define VALUE_DELAY_INFO_MESSAGE 8 + +#define PROG_INDEX 4 + +typedef struct tm_tc_header { + unsigned long long timeStamp; + unsigned int spare; + unsigned char responseType; + unsigned char error_code; + unsigned short cmd_id; +} s_tm_tc_header; + +#define TC_REPONSE_HEADER_SIZE sizeof(s_tm_tc_header) + 2 // taille de la partie fixe + 2 pour taille de la size + +typedef struct tc_response { + + s_tm_tc_header header; + unsigned short size; + char parameter[PARAMETER_SIZE]; +} t_tc_response; + +#define SIZE_HEADER_FIELD 2 + +typedef struct field { + unsigned char field_id; + unsigned char size; + unsigned char field_value[FIELD_SIZE]; + +} s_field; + +typedef struct command { + unsigned short key; /* clé */ + unsigned short id; /* command ID */ + unsigned short size; /* parameter size */ + char parameter[PARAMETER_SIZE]; +} s_command; + +typedef struct set_value { + unsigned char fied_id; + unsigned char size; + char value[FIELD_SIZE]; + +} s_set_value; + +typedef struct get_value { + unsigned char field_id; + unsigned char size; + +} s_get_value; + +#define MAX_MEM_PRG 4096 + +typedef struct prog_mngt { + long indexCourrant; + char *memory; +} s_prog_mngt; + +#define MAX_MEM_PRG_LOAD 64 + +typedef struct load_prog { + long index; + char mem1[MAX_MEM_PRG_LOAD]; + char mem2[MAX_MEM_PRG_LOAD]; +} s_load_prg; + +extern t_tc_response interpretcommand(s_command cmd); +extern void processCommand(s_ax25_packet data_ax25); +extern void processDropMessage(char *data_ax25, unsigned short size); + +#endif // COMMAND_H diff --git a/EmbededSw/src/core/configuration.h b/EmbededSw/src/core/configuration.h new file mode 100644 index 0000000000000000000000000000000000000000..e0b8a675733253b5aa5d5307d07a94bfc4081ad6 --- /dev/null +++ b/EmbededSw/src/core/configuration.h @@ -0,0 +1,47 @@ + +#ifndef CONFIGURATION_H +#define CONFIGURATION_H + +#include "../ax25/ax25.h" +/* + * Define Spino configuration + */ + +#define SSID_SPINO_TMTC 15 +#define SSID_SPINO_DIGIPEATER 3 +#define SSID_SPINO_MAILBOX 2 +#define SSID_SPINO_CUBESAT 4 +#define SSID_SPINO_EXPERIMENTAL 5 + +#define RESET_CAUSE_STATE_UNKNOWN 1 + +typedef struct configuration { + + long spinoTxFrequency; + long spinoRxFrequency; + unsigned short spinoTxModemSpeed; + unsigned short spinoRxModemSpeed; + unsigned char spinoRXModemMode; + unsigned char spinoTXModemMode; + unsigned char telemetryDelay; /* delay in seconde */ + unsigned char spare; /* delay in seconde */ + unsigned char info_message_actif; + unsigned char delay_info_message; + unsigned char spinoSrcCallsign[CALLSIGN_SIZE]; + unsigned char spinoDesCallsign[CALLSIGN_SIZE]; + unsigned char payloadCallsign[CALLSIGN_SIZE]; +} s_configuration_spino; + +typedef struct globalVariable { + + unsigned long nbCommandeReceived; + unsigned long nbCommandeWithError; + unsigned long nbFrameNotprocessed; + unsigned long nbDigipeaterMesssageProcessed; + unsigned long long timestamps; + unsigned short lastResetCause; + unsigned short currentState; +} s_globalVariable; + +#endif // CONFIGURATION_H + diff --git a/EmbededSw/src/core/control.c b/EmbededSw/src/core/control.c new file mode 100644 index 0000000000000000000000000000000000000000..5d4bd281f80c1f91b0cb57fb189b9bb44624a8c2 --- /dev/null +++ b/EmbededSw/src/core/control.c @@ -0,0 +1,164 @@ +/** + * \file control.c + * \brief manage spino mode + * \author Xtophe + * \version 0.2 + * \date 01/08/2022 + * + */ + +#include +#include +#include "setup.h" +#include "../errorMngt/error.h" +#include "../drivers/modem.h" +#include "informationMessage.h" +#include "control.h" + +#define SLEEP_TIME 500 /* sleep time */ + +extern unsigned short survey(); +extern unsigned short digipeater(); +extern unsigned short modeMailbox(); +extern unsigned short payloadMode(); +extern unsigned short experimentalMode(); +extern void initExpe(); + +unsigned long long lv_spino_timeStampPrevious = 0; +t_tc_response resptlm; + +static void inittlm() { + resptlm.header.responseType = TELEMETRY; + resptlm.header.error_code = 0; + resptlm.header.cmd_id = 0; + resptlm.size = sizeof(s_globalVariable); +} + +static void sendTLM() { + if (gv_spino.timestamps + > (lv_spino_timeStampPrevious + gv_spinoConfig.telemetryDelay * 1000)) { + s_ax25_packet ax25Frame; + lv_spino_timeStampPrevious = gv_spino.timestamps; + resptlm.header.timeStamp = gv_spino.timestamps; + memcpy(resptlm.parameter, &gv_spino, sizeof(s_globalVariable)); + ax25Frame.header = gv_headerTlm; + memcpy(ax25Frame.data, &resptlm, TC_REPONSE_HEADER_SIZE + resptlm.size); + writeData(ax25Frame, TC_REPONSE_HEADER_SIZE + resptlm.size); + logger(LOG_LEVEL_INFO, "Envoie TLM"); + } +} + +unsigned char changeState(int state) { + + unsigned char response = SUCCESS; + + switch (state) { + + case STATE_INIT: + gv_spino.currentState = STATE_INIT; + break; + case STATE_SURVEY: + gv_spino.currentState = STATE_SURVEY; + break; + + case STATE_DIGIPEATER: + if (gv_spino.currentState == STATE_SURVEY) { + gv_spino.currentState = STATE_DIGIPEATER; + } else { + logger(LOG_LEVEL_CRITICAL, "ERROR_WRONG_STATE"); + response = ERROR_WRONG_STATE; + } + break; + + case STATE_MAILBOX: + if (gv_spino.currentState == STATE_SURVEY) { + gv_spino.currentState = STATE_MAILBOX; + } else { + logger(LOG_LEVEL_CRITICAL, "ERROR_WRONG_STATE"); + response = ERROR_WRONG_STATE; + } + break; + + case STATE_EXPE_DATA: + if (gv_spino.currentState == STATE_SURVEY) { + gv_spino.currentState = STATE_EXPE_DATA; + initExpe(); + } else { + logger(LOG_LEVEL_CRITICAL, "ERROR_WRONG_STATE"); + response = ERROR_WRONG_STATE; + } + break; + + case STATE_MAIN_PAYLOAD: + if (gv_spino.currentState == STATE_SURVEY) { + gv_spino.currentState = STATE_MAIN_PAYLOAD; + } else { + logger(LOG_LEVEL_CRITICAL, "ERROR_WRONG_STATE"); + response = ERROR_WRONG_STATE; + } + break; + + default: + /* remplacer par reinit */ + + logger(LOG_LEVEL_CRITICAL, "ERROR_WRONG_STATE"); + response = ERROR_WRONG_STATE; + break; + } + + return response; +} + +void control() { + inittlm(); + + while (1) { + switch (gv_spino.currentState) { + + case STATE_INIT: + + logger(LOG_LEVEL_INFO, "STATE INIT"); + setupGlobalVariable(); + break; + case STATE_SURVEY: + logger(LOG_LEVEL_INFO, "STATE SURVEY"); + gv_spino.currentState = survey(); + break; + + case STATE_DIGIPEATER: + logger(LOG_LEVEL_INFO, "STATE DIGIPEATER"); + gv_spino.currentState = digipeater(); + break; + + case STATE_MAILBOX: + + logger(LOG_LEVEL_INFO, "STATE MAILBOX"); + gv_spino.currentState = modeMailbox(); + break; + + case STATE_EXPE_DATA: + logger(LOG_LEVEL_INFO, "STATE EXPE"); + gv_spino.currentState = experimentalMode(); + break; + + case STATE_MAIN_PAYLOAD: + logger(LOG_LEVEL_INFO, "STATE_MAIN_PAYLOAD"); + gv_spino.currentState = payloadMode(); + break; + + default: + /* remplacer par reinit */ + sprintf(gvLogMsg, "State default %d \r\n", gv_spino.currentState); + logger(LOG_LEVEL_CRITICAL, "STATE DEFAULT"); + gv_spino.currentState = STATE_INIT; + gv_spino.lastResetCause = RESET_CAUSE_STATE_UNKNOWN; + break; + } + + Sleep(SLEEP_TIME); + gv_spino.timestamps = gv_spino.timestamps + SLEEP_TIME; + sendTLM(); + sendInfoMessage(); + } + +} diff --git a/EmbededSw/src/core/control.h b/EmbededSw/src/core/control.h new file mode 100644 index 0000000000000000000000000000000000000000..88aadebf5bf7590c33b7edc0c0e95341c6d3de0d --- /dev/null +++ b/EmbededSw/src/core/control.h @@ -0,0 +1,14 @@ + +#ifndef CONTROL_H +#define CONTROL_H + +#define STATE_INIT 0 +#define STATE_SURVEY 1 +#define STATE_MAILBOX 2 +#define STATE_DIGIPEATER 3 +#define STATE_EXPE_DATA 4 +#define STATE_MAIN_PAYLOAD 5 + +extern unsigned char changeState(int state); +extern void control(); +#endif // CONTROL_H diff --git a/EmbededSw/src/core/informationMessage.c b/EmbededSw/src/core/informationMessage.c new file mode 100644 index 0000000000000000000000000000000000000000..5177be03a9d2f054339df2113d8f9cbd799095ff --- /dev/null +++ b/EmbededSw/src/core/informationMessage.c @@ -0,0 +1,193 @@ +/** + * \file InformationMessage.c + * \brief manage information message + * \author Xtophe + * \version 0.2 + * \date 21/08/2022 + * + */ +#include +#include +#include "setup.h" +#include "informationMessage.h" +#include "../errorMngt/error.h" +#include "../logMngt/log.h" +#include "../drivers/modem.h" + +s_inf_msg gv_information_msg[MAX_INF_MESSAGE]; + +unsigned long long lv_spino_timeStampInfoMsgPrevious = 0; +unsigned char lv_index_message_actif = 0; + +/** + * \fn void setupInfoMessage() + * \brief initialise information global variable + * \return void + * + */ +void setupInfoMessage() { + int i = 0; + int j = 0; + for (i = 0; i < MAX_INF_MESSAGE; i++) { + gv_information_msg[i].used = INFO_MSG_NOT_USED; + for (j = 0; j < MAX_SIZE_INF_MSG; j++) { + gv_information_msg[i].message[j] = 0; + } + + } +} + +/** + * \fn int setInfoMessage(char *data,t_tc_response *resp) + * \param information data in raw => to be set in s_add_inf_msg structure + * \param *resp output structure with result of command + * + * \brief add information message + * + * \return SUCCESS or ERROR_INFO_MSG_INDEX_OUT_OF_BOUND + * + */ +unsigned char setInfoMessage(char *data, t_tc_response *resp) { + + unsigned char reponse = SUCCESS; + int index; + s_add_inf_msg info_msg; + + memcpy(&info_msg, data, sizeof(s_add_inf_msg)); + index = info_msg.index; + logger(LOG_LEVEL_INFO, "SET INFO MESSAGE"); + + if (info_msg.index < MAX_INF_MESSAGE) { + gv_information_msg[index].message[0] = 0; + gv_information_msg[index].used = INFO_MSG_USED; + strncat(gv_information_msg[index].message, info_msg.message, + MAX_SIZE_INF_MSG); + + /* + gv_information_msg[index].used = INFO_MSG_USED; + if( strlen (info_msg.message)>=MAX_SIZE_INF_MSG ) + { + strncpy(gv_information_msg[index].message, info_msg.message, MAX_SIZE_INF_MSG); + } else + { + strcpy(gv_information_msg[index].message, info_msg.message); + } + */ + } else { + reponse = ERROR_INFO_MSG_INDEX_OUT_OF_BOUND; + } + + resp->size = 0; + return reponse; + +} + +/** + * \fn int delInfoMessage(char index ,t_tc_response *resp) + * \param index of message to remove + * \param *resp output structure with result of command + * + * \brief add information message + * + * \return SUCCESS or ERROR_INFO_MSG_INDEX_OUT_OF_BOUND or ERROR_INFO_MSG_ALREADY_NOT_USED + * + */ + +unsigned char delInfoMessage(char index, t_tc_response *resp) + +{ + unsigned char reponse = SUCCESS; + int ind = (int) index; + + if (index < MAX_INF_MESSAGE) { + if (gv_information_msg[ind].used == INFO_MSG_NOT_USED) { + reponse = ERROR_INFO_MSG_ALREADY_NOT_USED; + } + gv_information_msg[ind].used = (char) INFO_MSG_NOT_USED; + gv_information_msg[ind].message[0] = (char) 0; + + } else { + reponse = ERROR_INFO_MSG_INDEX_OUT_OF_BOUND; + } + resp->size = 0; + return reponse; +} + +/** + * \fn void sendInfoMessage() + * + * \brief Send information message when information mode is actif + * + * \return void + * + */ + +void sendInfoMessage() { + int find = 0; + int cpt = 0; + + if (gv_spinoConfig.info_message_actif == INFO_MSG_USED) { + + if (gv_spino.timestamps + > (lv_spino_timeStampInfoMsgPrevious + + gv_spinoConfig.delay_info_message * 1000)) { + + lv_spino_timeStampInfoMsgPrevious = gv_spino.timestamps; + + t_tc_response resp; + s_send_inf_msg infMsg; + + resp.header.responseType = INFORMATION_MSG; + resp.header.error_code = 0; + resp.header.cmd_id = 0; + resp.header.timeStamp = gv_spino.timestamps; + + // recherche message actif + while (find == 0) { + cpt++; + + if (gv_information_msg[lv_index_message_actif].used + == INFO_MSG_USED) { + + find = 1; + infMsg.index = lv_index_message_actif; + infMsg.used = + gv_information_msg[lv_index_message_actif].used; + resp.size = (unsigned short) strlen( + gv_information_msg[lv_index_message_actif].message) + + 2; + infMsg.message[0] = 0; + + strncat(infMsg.message, + gv_information_msg[lv_index_message_actif].message, + MAX_SIZE_INF_MSG); + + // strcpy(resp.parameter, gv_information_msg[lv_index_message_actif].message); + memcpy(resp.parameter, &infMsg, resp.size); + s_ax25_packet ax25Frame; + ax25Frame.header = gv_headerTlm; + memcpy(ax25Frame.data, &resp, + TC_REPONSE_HEADER_SIZE + resp.size); + /* envoyer la reponse de la commande */ + writeData(ax25Frame, TC_REPONSE_HEADER_SIZE + resp.size); + + logger(LOG_LEVEL_INFO, "MSG INFO SENT"); + + } else if (cpt > MAX_INF_MESSAGE) { + find = 1; + logger(LOG_LEVEL_CRITICAL, "NO MESSAGE INFO AVAILABLE"); + // stop information message transmission + gv_spinoConfig.info_message_actif = INFO_MSG_NOT_USED; + + } + lv_index_message_actif = + (unsigned char) ((lv_index_message_actif + 1) + % MAX_INF_MESSAGE); + + } + + } + } // do Nothing + +} + diff --git a/EmbededSw/src/core/informationMessage.h b/EmbededSw/src/core/informationMessage.h new file mode 100644 index 0000000000000000000000000000000000000000..3f11f9e65b598df87f4551bfb8d11e82fcaa75a8 --- /dev/null +++ b/EmbededSw/src/core/informationMessage.h @@ -0,0 +1,34 @@ +#ifndef INFORMATION_MESSAGE_H +#define INFORMATION_MESSAGE_H + +#include "command.h" + +#define MAX_SIZE_INF_MSG 256 +#define MAX_INF_MESSAGE 10 + +#define INFO_MSG_NOT_USED 0 +#define INFO_MSG_USED 1 + +typedef struct inf_msg { + char message[MAX_SIZE_INF_MSG]; + unsigned char used; + +} s_inf_msg; + +typedef struct add_inf_msg { + unsigned char index; + char message[MAX_SIZE_INF_MSG]; +} s_add_inf_msg; + +typedef struct send_in_msg { + unsigned char index; + unsigned char used; + char message[MAX_SIZE_INF_MSG]; +} s_send_inf_msg; + +extern unsigned char setInfoMessage(char *data, t_tc_response *resp); +extern unsigned char delInfoMessage(char index, t_tc_response *resp); +extern void sendInfoMessage(); +extern void setupInfoMessage(); + +#endif // INFORMATION_MESSAGE_H diff --git a/EmbededSw/src/core/setup.c b/EmbededSw/src/core/setup.c new file mode 100644 index 0000000000000000000000000000000000000000..b862c5b619315e29d2d48b78b5d1f265136ace3b --- /dev/null +++ b/EmbededSw/src/core/setup.c @@ -0,0 +1,93 @@ +/** + * \file setup.c + * \brief initialise all global variables needed for SPINO embeded software. + * \author Xtophe + * \version 0.1 + * \date 01/08/2022 + * + * \todo [ ] split set in different function + * \todo [ ] Set define for number and Callsign + * + */ + +/*========= INCLUDES ==========================================================================*/ + +#include + +#include "setup.h" +#include "../dropMsgMngt/DropMessage.h" +#include "informationMessage.h" +#include "control.h" +#include "informationMessage.h" + +extern void initExpe(); + +/*========= GLOBAL VARIABLES ===================================================================*/ + +s_configuration_spino gv_spinoConfig; +s_globalVariable gv_spino; +s_ax25_header gv_headerTlm; +s_unprocessedmessageList gv_unprocess_messages; +s_prog_mngt gv_prog; +char mem_prg[MAX_MEM_PRG]; +unsigned short gv_version = (unsigned short) 0x0103; + +unsigned short gv_spino_cmd_key = SPINO_CMD_KEY; + +/*========= FUNCTIONS ========================================================================*/ + +/*--------------------------------------------------------------------------------------------------------- + * + * setupGlobalVariable : + * \brief Setup SPINO global variable + * \details + * \param none + * \return void + * + ---------------------------------------------------------------------------------------------------------*/ +/** + * \fn void setupGlobalVariable(void) + * \brief initialise all global variable + * + */ + +void setupGlobalVariable() { + + setupInfoMessage(); + initExpe(); + + char cs[6] = { 'S', 'P', 'I', 'N', 'O', 'S' }; + char cd[6] = { 'S', 'P', 'I', 'N', 'O', 'D' }; + memcpy(gv_spinoConfig.spinoSrcCallsign, cs, 6); + memcpy(gv_spinoConfig.spinoDesCallsign, cd, 6); + gv_spinoConfig.telemetryDelay = 10; + gv_spinoConfig.spinoTxFrequency = 435000; + gv_spinoConfig.spinoTXModemMode = 1; + gv_spinoConfig.spinoTxModemSpeed = 1200; + gv_spinoConfig.spinoRxFrequency = 145000; + gv_spinoConfig.spinoRXModemMode = 1; + gv_spinoConfig.spinoRxModemSpeed = 9600; + gv_spinoConfig.delay_info_message = 30; + gv_spinoConfig.info_message_actif = INFO_MSG_NOT_USED; + + gv_headerTlm.pid = 255; + + convertToAX25Header(&gv_headerTlm, gv_spinoConfig.spinoDesCallsign, + gv_headerTlm.ssidDestination, gv_spinoConfig.spinoSrcCallsign, + gv_headerTlm.ssidSource); + + gv_prog.indexCourrant = 0; + gv_prog.memory = mem_prg; + gv_unprocess_messages.index = 0; + + int i = 0; + gv_unprocess_messages.index = 0; + for (i = 0; i < MAX_UNPROCESSED_MESSAGE_LIST_SIZE; i++) { + + gv_unprocess_messages.message[i].timestamps = 0; + gv_unprocess_messages.message[i].size = 0; + } + + gv_spino.currentState = STATE_SURVEY; + +} diff --git a/EmbededSw/src/core/setup.h b/EmbededSw/src/core/setup.h new file mode 100644 index 0000000000000000000000000000000000000000..6f6cd287e1d37a4cd133a563c7c5b2f3206753ac --- /dev/null +++ b/EmbededSw/src/core/setup.h @@ -0,0 +1,21 @@ +#ifndef SETUP_H +#define SETUP_H + +#include "configuration.h" +#include "../ax25/ax25.h" +#include "command.h" +#include "../logMngt/log.h" + +#define SPINO_CMD_KEY 0x0FF0 + +extern unsigned short gv_spino_cmd_key; + +extern s_configuration_spino gv_spinoConfig; +extern s_globalVariable gv_spino; +extern s_ax25_header gv_headerTlm; +extern unsigned short gv_version; +extern s_prog_mngt gv_prog; +extern char memory_reprog[]; +extern void setupGlobalVariable(); + +#endif // SETUP_H diff --git a/EmbededSw/src/digipeaterMode/ModeDigipeater.c b/EmbededSw/src/digipeaterMode/ModeDigipeater.c new file mode 100644 index 0000000000000000000000000000000000000000..182b021ae1cdc5caa61c676ca18befe15bd030f6 --- /dev/null +++ b/EmbededSw/src/digipeaterMode/ModeDigipeater.c @@ -0,0 +1,64 @@ +/** + * \file digipeater.c + * \brief MOde Digipeater + * \author Xtophe + * \version 0.2 + * \date 01/08/2022 + * + */ + +#include +#include +#include "../core/setup.h" +#include "../drivers/modem.h" +#include "../errorMngt/error.h" + +/** + * \fn unsigned short digipeater () + * \brief manage DIGIPEATER mode + * \return void + * + */ +unsigned short digipeater() { + char data[300]; + s_ax25_packet data_ax25; + + int nbc = readData(data); + + if (nbc != 0) { + /* traitement des donnees recues */ + int res = convertDataToAx25(&data_ax25, data, nbc); + if (res != SUCCESS) { + logger(LOG_LEVEL_CRITICAL, "AX25 CONVESTION ISSUE"); + } + if (memcmp(gv_spinoConfig.spinoDesCallsign, + data_ax25.header.destinationAdress, 6) == 0) { + + if (data_ax25.header.ssidDestination + == (unsigned char) SSID_SPINO_TMTC) { + processCommand(data_ax25); + } else if (data_ax25.header.ssidDestination + == (unsigned char) SSID_SPINO_DIGIPEATER) { + // renvoie la trame + memcpy(data_ax25.header.destinationAdress, + data_ax25.header.sourceAdress, 6); + memcpy(data_ax25.header.sourceAdress, + gv_spinoConfig.spinoSrcCallsign, 6); + data_ax25.header.ssidSource = SSID_SPINO_DIGIPEATER; + data_ax25.header.ssidDestination = data_ax25.header.ssidSource; + encodeAX25Header(&data_ax25.header); + nbc = nbc - (int) sizeof(s_ax25_header); + writeData(data_ax25, nbc); + gv_spino.nbDigipeaterMesssageProcessed++; + } else { + logger(LOG_LEVEL_CRITICAL, "WRONG SSID"); + processDropMessage(data, (unsigned short) nbc); + } + } else { + // Message not awaited - message dropped + processDropMessage(data, (unsigned short) nbc); + } + + } + return gv_spino.currentState; +} diff --git a/EmbededSw/src/drivers/modem.c b/EmbededSw/src/drivers/modem.c new file mode 100644 index 0000000000000000000000000000000000000000..55150152076c56c54b8454342e9c050a0c858669 --- /dev/null +++ b/EmbededSw/src/drivers/modem.c @@ -0,0 +1,60 @@ +/** + * \file modem.c + * \brief modem simulation + * \author Xtophe + * \version 0.2 + * \date 01/08/2022 + * + * \todo To adapt with embeded target + */ + +#include +#include "../ax25/ax25.h" +#include "../drivers/modem.h" +#include "../simulation/lefic.h" +#include "../simulation/SpinoSimuServerTCP.h" + +int gv_simu_mode = SIMU_MODE_TCP; + +void open() { + if (gv_simu_mode == SIMU_MODE_FILE) { + openfile("./header.bin"); + } else if (gv_simu_mode == SIMU_MODE_TCP) { + TCP_OpenAndWait(); + } +} + +int readData(char *data) { + int taille = 0; + + if (gv_simu_mode == SIMU_MODE_FILE) { + taille = lectureData(data); + + } else if (gv_simu_mode == SIMU_MODE_TCP) { + PerformSelect(gv_AcceptSocket, gv_m_client_list, 1); + if (gv_simu_nb_data_received != 0) { + printf("data received %d", gv_simu_nb_data_received); + taille = gv_simu_nb_data_received; + + memcpy(data, gv_simu_receiveddata, + (size_t) gv_simu_nb_data_received); + data = (char*) gv_simu_receiveddata; + gv_simu_nb_data_received = 0; + } + } + + return taille; + +} + +int writeData(const s_ax25_packet ax25Frame, const int length) { + + if (gv_simu_mode == SIMU_MODE_FILE) { + writefiledata(ax25Frame, length); + } else if (gv_simu_mode == SIMU_MODE_TCP) { + TCP_Send((char*) &ax25Frame, length + (int) sizeof(s_ax25_header)); + writefiledata(ax25Frame, length); + } + return 0; + +} diff --git a/EmbededSw/src/drivers/modem.h b/EmbededSw/src/drivers/modem.h new file mode 100644 index 0000000000000000000000000000000000000000..c71968f7ebb48a501c53f0d172f9319b56c67648 --- /dev/null +++ b/EmbededSw/src/drivers/modem.h @@ -0,0 +1,14 @@ +#ifndef MODEM_H +#define MODEM_H + +#include "../ax25/ax25.h" + +#define SIMU_MODE_FILE 1 +#define SIMU_MODE_TCP 2 + +extern int readData(char *data); +extern int writeData(s_ax25_packet ax25Frame, int length); + +extern int gv_simu_mode; + +#endif // MODEM_H diff --git a/EmbededSw/src/dropMsgMngt/DropMessage.c b/EmbededSw/src/dropMsgMngt/DropMessage.c new file mode 100644 index 0000000000000000000000000000000000000000..8b5d4c43e7f2640140c77b8340406198126b8da6 --- /dev/null +++ b/EmbededSw/src/dropMsgMngt/DropMessage.c @@ -0,0 +1,117 @@ +/** + * \file DropMessage.c + * \brief manage message dropped + * \author Xtophe + * \version 0.2 + * \date 01/08/2022 + * + */ + +#include +#include +#include "../core/setup.h" +#include "../errorMngt/error.h" +#include "DropMessage.h" + +extern void writeData(s_ax25_packet ax25Frame, int length); + +/** + * \fn void processDropMessage (char* data_ax25, int size) + * \param message Ax25 dropped message + * \param size message size of dropped message + * \brief manage message dropped + * + * \return void + * + */ +extern s_unprocessedmessageList gv_unprocess_messages; + +void processDropMessage(char *data_ax25, unsigned short size) { + logger(LOG_LEVEL_CRITICAL, "MESSAGE DROPPED"); + gv_spino.nbFrameNotprocessed++; + + gv_unprocess_messages.index = (gv_unprocess_messages.index + 1) + % MAX_UNPROCESSED_MESSAGE_LIST_SIZE; + gv_unprocess_messages.message[gv_unprocess_messages.index].timestamps = + gv_spino.timestamps; + + if (size > MAX_UNPROCESSED_MESSAGE_LENGHT) { + // trunck to MAX_MESSAGE_SIZE + gv_unprocess_messages.message[gv_unprocess_messages.index].size = + MAX_UNPROCESSED_MESSAGE_LENGHT; + + } else { + + gv_unprocess_messages.message[gv_unprocess_messages.index].size = size; + } + + logger(LOG_LEVEL_CRITICAL, data_ax25); + memcpy(&gv_unprocess_messages.message[gv_unprocess_messages.index].data, + data_ax25, + gv_unprocess_messages.message[gv_unprocess_messages.index].size); + +} + +/** + * \fn int getLastDroppedMessage(t_tc_response *resp) + * \brief set to response the last dropped message + * \param *resp output structure with result of command + * \return SUCCESS + * + */ + +unsigned char getLastDroppedMessage(t_tc_response *resp) { + + logger(LOG_LEVEL_CRITICAL, " GET_LAST_DROPED_MESSAGE"); + unsigned short taille_message = + gv_unprocess_messages.message[gv_unprocess_messages.index].size; + taille_message = taille_message + (unsigned short) SIZE_HEADER_DROP; + if (taille_message > MAX_DATA_SIZE) { + taille_message = MAX_DATA_SIZE; + } + memcpy(resp->parameter, + &gv_unprocess_messages.message[gv_unprocess_messages.index], + (size_t) taille_message); + resp->size = taille_message; + return SUCCESS; + +} + +/** + * \fn int getLastDroppedMessage(t_tc_response *resp) + * \brief set to response the last dropped message + * \param *resp output structure with result of command + * \return SUCCESS + * + * \todo : suprimer répétition dernier message dropped + * + */ + +unsigned char getAllDroppedMessage(t_tc_response *resp) { + s_ax25_packet ax25Frame; + ax25Frame.header = gv_headerTlm; + resp->header.error_code = SUCCESS; + + unsigned short taille_message; + int i = 0; + + for (i = 0; i < MAX_UNPROCESSED_MESSAGE_LIST_SIZE; i++) { + + taille_message = gv_unprocess_messages.message[i].size; + taille_message = taille_message + SIZE_HEADER_DROP; + if (taille_message > MAX_DATA_SIZE) { + taille_message = MAX_DATA_SIZE; + } + resp->size = taille_message; + memcpy(resp->parameter, &gv_unprocess_messages.message[i], + (size_t) taille_message); + + memcpy(ax25Frame.data, resp, + (size_t) (TC_REPONSE_HEADER_SIZE + resp->size)); + /* envoyer la reponse de la commande */ + writeData(ax25Frame, TC_REPONSE_HEADER_SIZE + resp->size); + } + resp->size = 0; + return SUCCESS; + +} diff --git a/EmbededSw/src/dropMsgMngt/DropMessage.h b/EmbededSw/src/dropMsgMngt/DropMessage.h new file mode 100644 index 0000000000000000000000000000000000000000..702c2aad8a4337dab8382c0e7a7f17cc61101001 --- /dev/null +++ b/EmbededSw/src/dropMsgMngt/DropMessage.h @@ -0,0 +1,24 @@ +#ifndef DOPMESSAGE_H +#define DOPMESSAGE_H + +#define MAX_UNPROCESSED_MESSAGE_LENGHT 256 +#define MAX_UNPROCESSED_MESSAGE_LIST_SIZE 5 + +#define SIZE_HEADER_DROP 8+2 /*taille de la structure hors data */ +typedef struct unprocessedmessage { + unsigned long long timestamps; + unsigned short size; + char data[MAX_UNPROCESSED_MESSAGE_LENGHT]; +} s_unprocessedmessage; + +typedef struct unprocessedmessageList { + int index; + s_unprocessedmessage message[MAX_UNPROCESSED_MESSAGE_LIST_SIZE]; + +} s_unprocessedmessageList; + +extern void processDropMessage(char *data_ax25, unsigned short size); +extern unsigned char getLastDroppedMessage(t_tc_response *resp); +extern unsigned char getAllDroppedMessage(t_tc_response *resp); + +#endif // DOPMESSAGE_H diff --git a/EmbededSw/src/errorMngt/error.h b/EmbededSw/src/errorMngt/error.h new file mode 100644 index 0000000000000000000000000000000000000000..f040ef43ef6c5e9bb0cd57e0e9fa9b01c0a3f03b --- /dev/null +++ b/EmbededSw/src/errorMngt/error.h @@ -0,0 +1,39 @@ +#ifndef ERROR_H +#define ERROR_H + +/* #define ERROR 1 + */ +#define SUCCESS 0 + +/* Command analysis */ + +#define ERROR_COMMAND_UNKNOW 1 +#define ERROR_COMMAND_NOT_IMPLEMENTED 2 +#define ERROR_COMMAND_WITH_WRONG_KEY 3 +#define ERROR_WRONG_STATE 4 + +#define ERROR_VALUE_FIELD_UNKNOW 101 + +/* AX25 Error */ +#define ERROR_AX25_EXCEED_MAX_LENGH 100 + +/* PROG ERROR */ +#define ERROR_PROG_INDEX_NOT_EQUAL 128 +#define ERROR_PROG_MEM1_MEM2_NOT_EQUAL 129 +#define ERROR_PROG_INDEX_OUT_OF_BOUND 130 + +/* MAILBOX ERROR */ + +#define ERROR_MAILBOX_FULL 10 +#define ERROR_MAILBOX_NOT_FOUND 11 +#define ERROR_MAILBOX_EMPTY 12 +#define ERROR_ADD_MSG_EXCED_SIZE 13 +#define ERROR_GET_LAST_MSG_CALLSIGN_WRONG_SIZE 14 +#define ERROR_MESSAGE_EMPTY 15 + +#define ERROR_INFO_MSG_INDEX_OUT_OF_BOUND 135 +#define ERROR_INFO_MSG_ALREADY_NOT_USED 136 + +#define ERROR_TLE_WRONG_SIZE 140 + +#endif // ERROR_H diff --git a/EmbededSw/src/experimentalMode/experimentalMode.c b/EmbededSw/src/experimentalMode/experimentalMode.c new file mode 100644 index 0000000000000000000000000000000000000000..ac3a76b7bdbeef102a5a5e2a889d188257645b30 --- /dev/null +++ b/EmbededSw/src/experimentalMode/experimentalMode.c @@ -0,0 +1,234 @@ +/** + * \file experimentalMode.c + * \brief manage experimental mode + * \author Xtophe + * \version 0.2 + * \date 01/08/2022 + * + */ + +#include +#include +#include "../core/setup.h" +#include "../drivers/modem.h" +#include "../mailboxMode/mailbox.h" +#include "../errorMngt/error.h" +#include "experimentalMode.h" + +int gv_experiemntal_command_nb = 0; +int gv_experiemntal_command_error_nb = 0; +unsigned long long lv_spino_expe_timeStampPrevious; + +t_tc_response respexpBeacon; +s_tle gv_tle; +s_experimental_beacon expBeacon; + +void initExpe() { + + expBeacon.id = 128; + expBeacon.delay = 10; + expBeacon.value[0] = 'A'; + expBeacon.value[1] = 'B'; + expBeacon.value[2] = 'C'; + expBeacon.value[3] = 'D'; + respexpBeacon.header.responseType = EXPEBEACON; + respexpBeacon.header.error_code = 0; + respexpBeacon.header.cmd_id = 0; + respexpBeacon.size = sizeof(s_experimental_beacon); + +} + +static unsigned char expDownloadTLE(t_tc_response *resp) { + + s_ax25_packet ax25Frame; + ax25Frame.header = gv_headerTlm; + + unsigned short taille_message = SIZE_TLE; + resp->header.cmd_id = CMD_DOWNLOAD_TLE_1; + resp->parameter[0] = 0; + strncat(resp->parameter, gv_tle.tleLine1, SIZE_TLE); + resp->size = taille_message; + memcpy(ax25Frame.data, resp, TC_REPONSE_HEADER_SIZE + resp->size); + /* envoyer la reponse de la commande */ + writeData(ax25Frame, TC_REPONSE_HEADER_SIZE + resp->size); + resp->header.cmd_id = CMD_DOWNLOAD_TLE_2; + resp->parameter[0] = 0; + strncat(resp->parameter, gv_tle.tleLine2, SIZE_TLE); + resp->size = taille_message; + memcpy(ax25Frame.data, resp, TC_REPONSE_HEADER_SIZE + resp->size); + /* envoyer la reponse de la commande */ + writeData(ax25Frame, TC_REPONSE_HEADER_SIZE + resp->size); + + return SUCCESS; +} + +t_tc_response interpretExperimentalCommmand(s_command cmd, + unsigned char *callsign) { + + t_tc_response resp; + + resp.header.responseType = RESULT_CMD; + resp.header.timeStamp = gv_spino.timestamps; + resp.header.cmd_id = cmd.id; + resp.header.error_code = SUCCESS; + + switch (cmd.id) { + + case CMD_EXPE_INIT: + logger(LOG_LEVEL_INFO, "Commande EXP RESET"); + resp.header.error_code = initialise(); + resp.size = 0; + break; + + case CMD_SET_EXPE_BEACON_DELAY: + logger(LOG_LEVEL_INFO, "Commande CMD_SET_EXPE_BEACON_DELAY"); + s_set_value setvalue; + memcpy(&setvalue, cmd.parameter, cmd.size); + expBeacon.delay = (unsigned short) setvalue.value[0]; + resp.header.error_code = SUCCESS; + resp.size = 0; + break; + + case CMD_LOAD_TLE_1: + logger(LOG_LEVEL_INFO, "Commande CMD_LOAD_TLE_1"); + if (cmd.size != SIZE_TLE) { + logger(LOG_LEVEL_INFO, "Commande CMD_LOAD_TLE_1 SIZE OK"); + gv_tle.tleLine1[0] = 0; + strncat(gv_tle.tleLine1, cmd.parameter, SIZE_TLE); + } else { + resp.header.error_code = ERROR_TLE_WRONG_SIZE; + + } + resp.size = 0; + break; + case CMD_LOAD_TLE_2: + logger(LOG_LEVEL_INFO, "Commande CMD_LOAD_TLE_2"); + if (cmd.size != SIZE_TLE) { + gv_tle.tleLine2[0] = 0; + strncat(gv_tle.tleLine2, cmd.parameter, SIZE_TLE); + } else { + resp.header.error_code = ERROR_TLE_WRONG_SIZE; + } + resp.size = 0; + break; + + case CMD_DOWNLOAD_TLE: + logger(LOG_LEVEL_INFO, "Commande CMD_DOWNLOAD_TLE"); + resp.header.error_code = expDownloadTLE(&resp); + resp.size = 0; + break; + case CMD_EXP_ADD_DATA: + logger(LOG_LEVEL_INFO, "Commande CMD_EXP_ADD_DATA"); + if (cmd.size > MAX_LENGHT_MESSAGE) { + resp.header.error_code = ERROR_ADD_MSG_EXCED_SIZE; + } else { + char message[MAX_LENGHT_MESSAGE]; + memcpy(message, &cmd.parameter, cmd.size); + logger(LOG_LEVEL_INFO, message); + resp.header.error_code = addMessage(callsign, message, cmd.size); + } + resp.size = 0; + break; + case CMD_EXPE_GET_LIST: + logger(LOG_LEVEL_INFO, "Commande CMD_EXPE_GET_LIST"); + resp.header.error_code = getListMailbox(&resp); + break; + case CMD_EXPE_DELETTE_ALL: + logger(LOG_LEVEL_INFO, "Commande MAILBOX DELETE MAILBOX"); + resp.header.error_code = deleteMailBox(callsign, &resp); + resp.size = 0; + break; + case CMD_EXPE_GET_ALL_DATA: + resp.header.error_code = getAllMesage(callsign); + resp.size = 0; + break; + + default: + sprintf(gvLogMsg, "erreur Experimental cmd %d \r\n", cmd.id); + logger(LOG_LEVEL_CRITICAL, gvLogMsg); + resp.header.error_code = ERROR_COMMAND_UNKNOW; + resp.size = 0; + break; + } + return resp; +} + +void sendBeaconExpe() { + + if (gv_spino.timestamps + > (lv_spino_expe_timeStampPrevious + + (unsigned long long) (expBeacon.delay * 1000))) { + s_ax25_packet ax25Frame; + lv_spino_expe_timeStampPrevious = gv_spino.timestamps; + respexpBeacon.header.timeStamp = gv_spino.timestamps; + memcpy(respexpBeacon.parameter, &expBeacon, + sizeof(s_experimental_beacon)); + ax25Frame.header = gv_headerTlm; + memcpy(ax25Frame.data, &respexpBeacon, + TC_REPONSE_HEADER_SIZE + respexpBeacon.size); + writeData(ax25Frame, TC_REPONSE_HEADER_SIZE + respexpBeacon.size); + logger(LOG_LEVEL_INFO, "Envoie TLM"); + } + +} + +static void processExperimental(s_ax25_packet data_ax25) { + + t_tc_response result; + s_command cmd; + + gv_experiemntal_command_nb++; + memcpy(&cmd, data_ax25.data, sizeof(s_command)); + result = interpretExperimentalCommmand(cmd, data_ax25.header.sourceAdress); + if (result.header.error_code != SUCCESS) { + gv_experiemntal_command_error_nb++; + } + s_ax25_packet ax25Frame; + + ax25Frame.header = gv_headerTlm; + memcpy(ax25Frame.data, &result, TC_REPONSE_HEADER_SIZE + result.size); + /* envoyer la reponse de la commande */ + writeData(ax25Frame, TC_REPONSE_HEADER_SIZE + result.size); + sprintf(gvLogMsg, "RESULT EXPE COMMAND %x %x ", result.header.cmd_id, + result.header.error_code); + logger(LOG_LEVEL_CRITICAL, gvLogMsg); + +} + +unsigned short experimentalMode() { + char data[300]; + s_ax25_packet data_ax25; + + logger(LOG_LEVEL_CRITICAL, "EXPERIMENTAL MODE "); + int nbc = readData(data); + + if (nbc != 0) { + /* traitement des donnees recues */ + int res = convertDataToAx25(&data_ax25, data, nbc); + if (res != SUCCESS) { + logger(LOG_LEVEL_CRITICAL, "AX25 CONVESTION ISSUE"); + } + + if (memcmp(gv_spinoConfig.spinoDesCallsign, + data_ax25.header.destinationAdress, 6) == 0) { + if (data_ax25.header.ssidDestination + == (unsigned char) SSID_SPINO_TMTC) { + logger(LOG_LEVEL_CRITICAL, "TRT COMMANDE NORMAL"); + processCommand(data_ax25); + } else if (data_ax25.header.ssidDestination + == (unsigned char) SSID_SPINO_EXPERIMENTAL) { + logger(LOG_LEVEL_CRITICAL, "TRT COMMANDE EXPE"); + processExperimental(data_ax25); + } else { + // Message not awaited - message dropped + processDropMessage(data, (unsigned short) nbc); + } + } else { + processDropMessage(data, (unsigned short) nbc); + } + } + + sendBeaconExpe(); + + return gv_spino.currentState; +} diff --git a/EmbededSw/src/experimentalMode/experimentalMode.h b/EmbededSw/src/experimentalMode/experimentalMode.h new file mode 100644 index 0000000000000000000000000000000000000000..e71092ecf9e8d8e83136e4b3d37a28fc3d48242f --- /dev/null +++ b/EmbededSw/src/experimentalMode/experimentalMode.h @@ -0,0 +1,34 @@ +#ifndef EXPERIMENTAL_MODE_H +#define EXPERIMENTAL_MODE_H + +#define SIZE_TLE 70 +#define CMD_LOAD_TLE_1 70 +#define CMD_LOAD_TLE_2 71 +#define CMD_DOWNLOAD_TLE 72 +#define CMD_DOWNLOAD_TLE_1 73 +#define CMD_DOWNLOAD_TLE_2 74 +#define CMD_EXP_ADD_DATA 75 +#define CMD_EXPE_GET_LIST 76 +#define CMD_EXPE_DELETTE_ALL 77 +#define CMD_EXPE_GET_ALL_DATA 78 +#define CMD_EXPE_INIT 79 +#define CMD_SET_EXPE_BEACON_DELAY 80 + +typedef struct tle { + char tleLine1[SIZE_TLE]; + char tleLine2[SIZE_TLE]; + +} s_tle; + +typedef struct experimental_beacon { + short id; + short delay; + char value[4]; + +} s_experimental_beacon; + +extern void initExpe(); +extern void sendBeaconExpe(); +extern unsigned short experimentalMode(); + +#endif //EXPERIMENTAL_MODE_H diff --git a/EmbededSw/src/logMngt/log.c b/EmbededSw/src/logMngt/log.c new file mode 100644 index 0000000000000000000000000000000000000000..d56c8672fa410115dca51c1045d519ee2f5c80ca --- /dev/null +++ b/EmbededSw/src/logMngt/log.c @@ -0,0 +1,98 @@ +/** + * \file log.c + * \brief manage log + * \author Xtophe + * \version 0.2 + * \date 01/08/2022 + * + */ + +#include +#include +#include "../core/setup.h" +#include "../errorMngt/error.h" + +extern void writeData(s_ax25_packet ax25Frame, int length); + +unsigned char gv_SelectedLogLevel = 0; + +s_logs logs[MAX_LOG]; +int gvLogIndex = 0; +char gvLogMsg[MAX_SIZE_MSG_LOG]; + +/** + * \fn void logger(char level, char *message) + * \brief log message in log Table + * \param level define type of log + * \param message Ascii message + * \return void + * + */ +void logger(char level, char *message) { + + if (level >= gv_SelectedLogLevel) { + gvLogIndex = (gvLogIndex + 1) % MAX_LOG; + logs[gvLogIndex].priority = level; + logs[gvLogIndex].timeStamps = gv_spino.timestamps; + logs[gvLogIndex].log[0] = 0; + strncat(logs[gvLogIndex].log, message, MAX_SIZE_MSG_LOG - 1); + printf("LOG : "); + printf(message); + printf("\r\n"); + } + +} + +/** + * \fn int getLastLog(t_tc_response *resp) + * \brief set to response the last log + * \param *resp output structure with result of command + * \return SUCCESS + * + * \todo : optimise message lenght in response + * + */ + +unsigned char getLastLog(t_tc_response *resp) { + + logger(LOG_LEVEL_INFO, " GET_LAST_LOG_MESSAGE"); + unsigned short taille_message = (unsigned short) strlen( + logs[gvLogIndex].log) + SIZE_S_LOG + 1; // +1 pour inclure le 0 + memcpy(resp->parameter, &logs[gvLogIndex], taille_message); + resp->size = taille_message; + return SUCCESS; + +} + +/** + * \fn int getAllLogs(t_tc_response *resp) + * \brief send all logs + * \param *resp output structure with result of command + * \return SUCCESS + * + * \todo : suprimer répétition dernier logs + * + */ + +unsigned char getAllLogs(t_tc_response *resp) { + s_ax25_packet ax25Frame; + ax25Frame.header = gv_headerTlm; + resp->header.error_code = SUCCESS; + logger(LOG_LEVEL_CRITICAL, " GET_ALL_LOG_MESSAGE"); + int i = 0; + + for (i = 0; i < MAX_LOG; i++) { + + unsigned short taille_message = (unsigned short) strlen(logs[i].log) + + SIZE_S_LOG + 1; // +1 pour inclure le 0 + memcpy(resp->parameter, &logs[i], taille_message); + resp->size = taille_message; + memcpy(ax25Frame.data, resp, TC_REPONSE_HEADER_SIZE + resp->size); + /* envoyer la reponse de la commande */ + writeData(ax25Frame, TC_REPONSE_HEADER_SIZE + resp->size); + } + /* return success of the command */ + resp->size = 0; + return SUCCESS; + +} diff --git a/EmbededSw/src/logMngt/log.h b/EmbededSw/src/logMngt/log.h new file mode 100644 index 0000000000000000000000000000000000000000..0f42efbe30ee9dfddaa68575051e9ade7d29db96 --- /dev/null +++ b/EmbededSw/src/logMngt/log.h @@ -0,0 +1,25 @@ +#ifndef LOG_H +#define LOG_H + +#define LOG_LEVEL_INFO 0 +#define LOG_LEVEL_WARNING 1 +#define LOG_LEVEL_CRITICAL 5 + +#define MAX_LOG 10 +#define MAX_SIZE_MSG_LOG 64 + +#define SIZE_S_LOG 8+1 +typedef struct logs { + unsigned long long timeStamps; + char priority; + char log[MAX_SIZE_MSG_LOG]; +} s_logs; + +extern unsigned char gv_SelectedLogLevel; + +extern void logger(char level, char *message); +extern char gvLogMsg[MAX_SIZE_MSG_LOG]; +extern unsigned char getAllLogs(t_tc_response *resp); +extern unsigned char getLastLog(t_tc_response *resp); + +#endif // LOG_H diff --git a/EmbededSw/src/mailboxMode/mailbox.c b/EmbededSw/src/mailboxMode/mailbox.c new file mode 100644 index 0000000000000000000000000000000000000000..4579bfe58fb8f6b28fa9fb48a5b8ecd233da6dc1 --- /dev/null +++ b/EmbededSw/src/mailboxMode/mailbox.c @@ -0,0 +1,624 @@ +/** + * \file mailbox.c + * \brief mailbox management + * \author Xtophe + * \version 0.2 + * \date 01/08/2022 + * + */ + +#include +#include +#include "../core/setup.h" +#include "../drivers/modem.h" +#include "mailbox.h" +#include "../errorMngt/error.h" +#include "../ax25/ax25.h" + +s_mailboxes gvMailboxes; + +/** + * \fn int initialise() + * \brief initialise mailboxes + * + * \return SUCCESS + * + */ + +unsigned char initialise() { + int i = 0; + int j = 0; + int k = 0; + + gvMailboxes.indexfreeMailbox = 0; + gvMailboxes.usedMailboxNumber = 0; + gvMailboxes.nbMailboxCommandeReceived = 0; + gvMailboxes.nbMailboxErrorCommandeReceived = 0; + + for (i = 0; i < MAX_MAILBOX; i++) { + gvMailboxes.mailbox[i].indexFreeMessage = MAX_MAILBOX - 1; + gvMailboxes.mailbox[i].indexNextMessage = 0; + gvMailboxes.mailbox[i].messageNumber = 0; + gvMailboxes.mailbox[i].timestampCreation = 0; + + for (j = 0; j < CALLSIGN_SIZE; j++) { + gvMailboxes.mailbox[i].callsign[j] = ' '; + } + for (j = 0; j < MAX_MESSAGE; j++) { + for (k = 0; k < MAX_LENGHT_MESSAGE; k++) { + gvMailboxes.mailbox[i].messages[j].message[k] = 0; + } + + gvMailboxes.mailbox[i].messages[j].size = 0; + gvMailboxes.mailbox[i].messages[j].timestamps = 0; + } + } + return SUCCESS; +} + +/** + * \fn int addMessage (char *callsign, char *message,int sizemMessage) + * \brief add message to the mailbox if the mailbox doesnot exist a new mailbox is created + * + * \return SUCCESS else ERROR_MAILBOX_FULL, + * + * + */ +unsigned char addMessage(unsigned char *callsign, char *message, + const unsigned short sizemMessage) { + unsigned char reponse = SUCCESS; + s_mailbox *pMailbox; + // create 1st mailbox + if (gvMailboxes.usedMailboxNumber == 0) { + + pMailbox = &gvMailboxes.mailbox[gvMailboxes.indexfreeMailbox]; + // creation de la mailbox + memcpy(pMailbox->callsign, callsign, 6); + + memcpy(pMailbox->messages[pMailbox->indexNextMessage].message, message, + sizemMessage); + pMailbox->messages[pMailbox->indexNextMessage].timestamps = + gv_spino.timestamps; + pMailbox->messages[pMailbox->indexNextMessage].size = sizemMessage; + + pMailbox->indexNextMessage = + (unsigned char) ((pMailbox->indexNextMessage + 1) % MAX_MAILBOX); + pMailbox->messageNumber++; + pMailbox->timestampCreation = gv_spino.timestamps; + + gvMailboxes.usedMailboxNumber++; + gvMailboxes.indexfreeMailbox++; + } else { /* recherche si BAL existe */ + + int i = 0; + char find = 0; + + while ((i < MAX_MAILBOX) & (find == 0)) { + //if (gvMailboxes.mailbox[i].messageNumber != 0) + //{ + if ((memcmp(gvMailboxes.mailbox[i].callsign, callsign, 6) == 0)) + + { // ajout de message + + pMailbox = &gvMailboxes.mailbox[i]; + // verifie place dispo + if (pMailbox->messageNumber < MAX_MESSAGE) { + memcpy( + pMailbox->messages[pMailbox->indexNextMessage].message, + message, sizemMessage); + pMailbox->messages[pMailbox->indexNextMessage].timestamps = + gv_spino.timestamps; + pMailbox->messages[pMailbox->indexNextMessage].size = + sizemMessage; + + pMailbox->indexNextMessage = + (unsigned char) ((pMailbox->indexNextMessage + 1) + % MAX_MAILBOX); + pMailbox->messageNumber++; + + } else { + reponse = ERROR_MAILBOX_FULL; + } + find = 1; + } + //} + i++; + } + + if (find == 0) { + // creation BAL + ajout Message + + if (gvMailboxes.usedMailboxNumber < MAX_MAILBOX) { + // reste de la place + pMailbox = &gvMailboxes.mailbox[gvMailboxes.indexfreeMailbox]; + // creation de la mailbox + memcpy(pMailbox->callsign, callsign, 6); + + memcpy(pMailbox->messages[pMailbox->indexNextMessage].message, + message, sizemMessage); + pMailbox->messages[pMailbox->indexNextMessage].timestamps = + gv_spino.timestamps; + pMailbox->messages[pMailbox->indexNextMessage].size = + sizemMessage; + pMailbox->indexNextMessage = + (unsigned char) ((pMailbox->indexNextMessage + 1) + % MAX_MAILBOX); + + pMailbox->messageNumber++; + pMailbox->timestampCreation = gv_spino.timestamps; + + // recher de la nouvelle mailbox libre + while ((i < MAX_MAILBOX) & (find == 0)) { + if (gvMailboxes.mailbox[i].messageNumber == 0) { + find = 1; + gvMailboxes.indexfreeMailbox = i; + } else { + i++; + } + } + + } + /* TODO MCR Cas ou pas trouvé verifier qua pas de PB */ + } + } + return reponse; +} + +/** + * \fn int deletteMessage ( char *callsign) + * \brief delete the first message + * + * \return SUCCESS or ERROR_MAILBOX_EMPTY + * + */ + +static unsigned char deletteMessage(unsigned char *callsign, + t_tc_response *resp) { + int i = 0; + int find = 0; + s_mailbox *pMailbox; + unsigned char reponse = SUCCESS; + while ((i < MAX_MAILBOX) & (find == 0)) { + + if ((memcmp(gvMailboxes.mailbox[i].callsign, callsign, 6) == 0)) { // delete message + find = 1; + pMailbox = &gvMailboxes.mailbox[i]; + if (gvMailboxes.mailbox->messageNumber > 0) { + pMailbox->indexFreeMessage = + (unsigned char) ((pMailbox->indexFreeMessage + 1) + % MAX_MESSAGE); + pMailbox->messageNumber--; + + } else { + reponse = ERROR_MAILBOX_EMPTY; + + } + + } + i++; + + } + + if (find == 0) { + reponse = ERROR_MAILBOX_NOT_FOUND; + } + + resp->size = 0; + + return reponse; + +} +/** + * \fn int getListMailbox(t_tc_response *resp) + * \brief return the list of mailboxes + * + * \return SUCCESS else ERROR_MAILBOX_FULL, + * + * + */ + +unsigned char getListMailbox(t_tc_response *resp) { + s_list_mailbox list[MAX_MAILBOX]; + unsigned char response = SUCCESS; + int i; + + for (i = 0; i < MAX_MAILBOX; i++) { + + memcpy(list[i].callsign, gvMailboxes.mailbox[i].callsign, (int) 6); + list[i].nb_message = gvMailboxes.mailbox[i].messageNumber; + + } + + resp->size = sizeof(s_list_mailbox) * MAX_MAILBOX; + memcpy(resp->parameter, list, resp->size); + + return response; +} + +/** + * \fn int deleteMailBox (char *callsign,t_tc_response *resp) + * \brief delette Mailbox + * + * \return SUCCESS else ERROR_MAILBOX_NOT_FOUND, + * + * + */ +unsigned char deleteMailBox(unsigned char *callsign, t_tc_response *resp) { + int i = 0; + int j = 0; + int find = 0; + s_mailbox *pMailbox; + unsigned char reponse = SUCCESS; + + while ((i < MAX_MAILBOX) & (find == 0)) { + + if ((memcmp(gvMailboxes.mailbox[i].callsign, callsign, 6) == 0)) { // delete message + + pMailbox = &gvMailboxes.mailbox[i]; + + pMailbox->indexFreeMessage = MAX_MESSAGE - 1; + pMailbox->indexNextMessage = 0; + pMailbox->messageNumber = 0; + pMailbox->timestampCreation = 0; + + gvMailboxes.indexfreeMailbox = i; + gvMailboxes.usedMailboxNumber--; + for (j = 0; j < CALLSIGN_SIZE; j++) { + pMailbox->callsign[j] = ' '; + } + + find = 1; + + } + + i++; + + } + + if (find == 0) { + reponse = ERROR_MAILBOX_NOT_FOUND; + + } + + resp->size = 0; + return reponse; +} + +/** + * \fn int getLastMessage (char * callsign,t_tc_response *resp) + * \brief return the last message + * + * \return SUCCESS else ERROR_MAILBOX_NOT_FOUND, + * + * + */ + +static unsigned char getLastMessage(unsigned char *callsign, + t_tc_response *resp) { + + int i = 0; + int find = 0; + s_mailbox *pMailbox; + unsigned char reponse = SUCCESS; + s_get_message messagelue; + + while ((i < MAX_MAILBOX) & (find == 0)) { + + if (gvMailboxes.mailbox[i].messageNumber != 0) { + + if ((memcmp(gvMailboxes.mailbox[i].callsign, callsign, 6) == 0)) { // retourn message + + pMailbox = &gvMailboxes.mailbox[i]; + int message_index = ((pMailbox->indexNextMessage - 1) + % MAX_MESSAGE); + if (message_index < 0) { + message_index = MAX_MESSAGE - 1; + } + + sprintf(gvLogMsg, "Taille INDEX %d LAST %d\r\n", + pMailbox->indexNextMessage, message_index); + logger(LOG_LEVEL_CRITICAL, gvLogMsg); + messagelue.index = (unsigned char) message_index; + memcpy(messagelue.callsign, callsign, 6); + messagelue.timestamps = + pMailbox->messages[message_index].timestamps; + sprintf(gvLogMsg, "Taille SIZE %d \r\n", + pMailbox->messages[message_index].size); + memcpy(messagelue.message, + pMailbox->messages[message_index].message, + pMailbox->messages[message_index].size); + resp->size = pMailbox->messages[message_index].size + + SIZE_T_GET_MESSAGE; + memcpy(resp->parameter, &messagelue, resp->size); + find = 1; + + } + + } + i++; + + } + + if (find == 0) { + logger(LOG_LEVEL_INFO, "Mesage non trouvé 4"); + reponse = ERROR_MAILBOX_NOT_FOUND; + resp->size = 0; + resp->header.error_code = ERROR_MAILBOX_NOT_FOUND; + } + + return reponse; + +} + +/** + * \fn int getMessage (char * callsign, unsigned char index, t_tc_response *resp) + * \brief return message from the callsign + * \param callsign + * \param index message index + * \param response structure + * + * \return SUCCESS else ERROR_MAILBOX_NOT_FOUND, + * + */ + +static unsigned char getMessage(unsigned char *callsign, unsigned char index, + t_tc_response *resp) { + int i = 0; + int find = 0; + s_mailbox *pMailbox; + unsigned char reponse = SUCCESS; + s_get_message messagelue; + + while ((i < MAX_MAILBOX) & (find == 0)) { + + if (gvMailboxes.mailbox[i].messageNumber != 0) { + + if ((memcmp(gvMailboxes.mailbox[i].callsign, callsign, 6) == 0)) { // retourn message + + pMailbox = &gvMailboxes.mailbox[i]; + + sprintf(gvLogMsg, "Taille INDEX %d LAST %d\r\n", + pMailbox->indexNextMessage, index); + logger(LOG_LEVEL_CRITICAL, gvLogMsg); + if (pMailbox->messages[index].size != 0) { + messagelue.index = index; + memcpy(messagelue.callsign, callsign, 6); + messagelue.timestamps = + pMailbox->messages[index].timestamps; + memcpy(messagelue.message, + pMailbox->messages[index].message, + pMailbox->messages[index].size); + resp->size = pMailbox->messages[index].size + + SIZE_T_GET_MESSAGE; + memcpy(resp->parameter, &messagelue, resp->size); + } else { + resp->size = 0; + resp->header.error_code = ERROR_MESSAGE_EMPTY; + } + + find = 1; + + } + + } + i++; + logger(LOG_LEVEL_INFO, "Mesage non trouvé 5"); + } + + if (find == 0) { + logger(LOG_LEVEL_INFO, "Mesage non trouvé 4"); + reponse = ERROR_MAILBOX_NOT_FOUND; + resp->size = 0; + resp->header.error_code = ERROR_MAILBOX_NOT_FOUND; + } + + return reponse; +} + +/** + * \fn int getAllMesage (char * callsign) + * \brief return all message from the callsign + * \param callsign + * + * \return SUCCESS else ERROR_MAILBOX_NOT_FOUND, + * + */ + +unsigned char getAllMesage(unsigned char *callsign) { + + int i = 0; + int find = 0; + s_mailbox *pMailbox; + unsigned char reponse = SUCCESS; + s_get_message messagelue; + + t_tc_response resp; + s_ax25_packet ax25Frame; + ax25Frame.header = gv_headerTlm; + + logger(LOG_LEVEL_CRITICAL, " GET_ALL_MESSAGE"); + + memcpy(messagelue.callsign, callsign, 6); + + while ((i < MAX_MAILBOX) & (find == 0)) { + + if (gvMailboxes.mailbox[i].messageNumber != 0) { + + if ((memcmp(gvMailboxes.mailbox[i].callsign, callsign, 6) == 0)) { // retourn message + + pMailbox = &gvMailboxes.mailbox[i]; + + // envoie des messages de la boite + unsigned char j; + resp.header.cmd_id = CMD_MAILBOX_GET_MSG; + resp.header.error_code = SUCCESS; + resp.header.responseType = RESULT_CMD; + resp.header.spare = 0; + resp.header.timeStamp = gv_spino.timestamps; + for (j = 0; j < (unsigned char) MAX_MESSAGE; j++) { + if (pMailbox->messages[j].size != 0) { + messagelue.index = j; + messagelue.timestamps = + pMailbox->messages[j].timestamps; + memcpy(messagelue.message, + pMailbox->messages[j].message, + pMailbox->messages[j].size); + resp.size = pMailbox->messages[j].size + + SIZE_T_GET_MESSAGE; + memcpy(resp.parameter, &messagelue, resp.size); + memcpy(ax25Frame.data, &resp, + TC_REPONSE_HEADER_SIZE + resp.size); + /* envoyer la reponse de la commande */ + writeData(ax25Frame, + TC_REPONSE_HEADER_SIZE + resp.size); + + } + } + + find = 1; + + } + + } + i++; + + } + + if (find == 0) { + + reponse = ERROR_MAILBOX_NOT_FOUND; + + } + + return reponse; +} + +/** + * \fn int dumpMailbox () + * \brief return all message from all mailbox + * \param none + * \return SUCCESS else ERROR_MAILBOX_NOT_FOUND, + * + */ + +static unsigned char dumpMailbox() { + + int i = 0; + unsigned char response = SUCCESS; + for (i = 0; i < MAX_MAILBOX; i++) { + if (gvMailboxes.mailbox[i].messageNumber != 0) { + response = getAllMesage(gvMailboxes.mailbox[i].callsign); + + } + } + + return response; +} + +static t_tc_response interpretMailBoxcommand(s_command cmd, + unsigned char *callsign) { + + t_tc_response resp; + unsigned char reponse = SUCCESS; + + resp.header.responseType = RESULT_CMD; + resp.header.timeStamp = gv_spino.timestamps; + resp.header.cmd_id = cmd.id; + + switch (cmd.id) { + + case CMD_MAILBOX_INIT: + logger(LOG_LEVEL_INFO, "Commande MAILBOX RESET"); + reponse = initialise(); + resp.size = 0; + break; + + case CMD_MAILBOX_ADD_MSG: + logger(LOG_LEVEL_INFO, "Commande MAILBOX ADD MSG"); + if (cmd.size > MAX_LENGHT_MESSAGE) { + reponse = ERROR_ADD_MSG_EXCED_SIZE; + } else { + char message[MAX_LENGHT_MESSAGE]; + logger(LOG_LEVEL_CRITICAL, gvLogMsg); + memcpy(message, cmd.parameter, cmd.size); + reponse = addMessage(callsign, message, cmd.size); + } + resp.size = 0; + break; + + case CMD_MAILBOX_DEL_MSG: + logger(LOG_LEVEL_INFO, "Commande MAILBOX DELETE MSG !!!"); + reponse = deletteMessage(callsign, &resp); + resp.size = 0; + break; + case CMD_MAILBOX_GET_LIST_BOX: + logger(LOG_LEVEL_INFO, "Commande MAILBOX LIST MAILBOXES"); + reponse = getListMailbox(&resp); + break; + case CMD_MAILBOX_DELETTE_BOX: + logger(LOG_LEVEL_INFO, "Commande MAILBOX DELETE MAILBOX"); + reponse = deleteMailBox(callsign, &resp); + resp.size = 0; + break; + case CMD_MAILBOX_GET_LAST_MSG: + logger(LOG_LEVEL_INFO, "Commande MAILBOX GET LAST MESSAGE"); + if (cmd.size == 6) { + unsigned char callsignMailbox[6]; + memcpy(callsignMailbox, cmd.parameter, cmd.size); + reponse = getLastMessage(callsignMailbox, &resp); + } else { + reponse = ERROR_GET_LAST_MSG_CALLSIGN_WRONG_SIZE; + } + + break; + case CMD_MAILBOX_GET_MSG: + + logger(LOG_LEVEL_INFO, "Commande MAILBOX GET MESSAGE INDEX"); + reponse = getMessage((unsigned char*) &cmd.parameter[1], + (unsigned char) cmd.parameter[0], &resp); + break; + + case CMD_MAILBOX_GET_ALL_MSG: + reponse = getAllMesage(callsign); + resp.size = 0; + break; + case CMD_MAILBOX_DUMP_MAILBOX: + reponse = dumpMailbox(); + break; + default: + // generation code erreur + sprintf(gvLogMsg, "erreur mailbox cmd %d \r\n", cmd.id); + logger(LOG_LEVEL_CRITICAL, gvLogMsg); + reponse = ERROR_COMMAND_UNKNOW; + resp.size = 0; + break; + } + + resp.header.error_code = reponse; + return resp; +} + +void processMailbox(s_ax25_packet data_ax25) { + + t_tc_response result; + s_command cmd; + + gvMailboxes.nbMailboxCommandeReceived++; + memcpy(&cmd, data_ax25.data, sizeof(s_command)); + result = interpretMailBoxcommand(cmd, data_ax25.header.sourceAdress); + if (result.header.error_code != SUCCESS) { + gvMailboxes.nbMailboxErrorCommandeReceived++; + } + s_ax25_packet ax25Frame; + + memcpy(ax25Frame.header.sourceAdress, gv_spinoConfig.spinoDesCallsign, 6); + ax25Frame.header.ssidSource = SSID_SPINO_MAILBOX; + memcpy(ax25Frame.header.destinationAdress, data_ax25.header.sourceAdress, + 6); + ax25Frame.header.ssidDestination = SSID_SPINO_MAILBOX; + encodeAX25Header(&ax25Frame.header); + memcpy(ax25Frame.data, &result, TC_REPONSE_HEADER_SIZE + result.size); + /* envoyer la reponse de la commande */ + writeData(ax25Frame, TC_REPONSE_HEADER_SIZE + result.size); + +} diff --git a/EmbededSw/src/mailboxMode/mailbox.h b/EmbededSw/src/mailboxMode/mailbox.h new file mode 100644 index 0000000000000000000000000000000000000000..b2c6ac59532c0e5f28d2e22487b535a00b9bc0b6 --- /dev/null +++ b/EmbededSw/src/mailboxMode/mailbox.h @@ -0,0 +1,96 @@ +#ifndef MAILBOX_H +#define MAILBOX_H + +#include "../ax25/ax25.h" + +#define MAX_MAILBOX 10 +#define MAX_MESSAGE 10 + +#define MAX_LENGHT_MESSAGE 256 +#define CALLSIGN_SIZE 6 + +/* COMMANDE MAILBOX */ + +#define CMD_MAILBOX_INIT 32 +#define CMD_MAILBOX_ADD_MSG 33 +#define CMD_MAILBOX_DEL_MSG 34 +#define CMD_MAILBOX_GET_LIST_BOX 35 +#define CMD_MAILBOX_DELETTE_BOX 36 +#define CMD_MAILBOX_GET_LAST_MSG 37 +#define CMD_MAILBOX_GET_MSG 38 +#define CMD_MAILBOX_GET_ALL_MSG 39 +#define CMD_MAILBOX_DUMP_MAILBOX 40 + +/** + * \struct t_mailbox_message + * \brief define mailbox structure to store message for a dedicated Callsign + * + */ + +typedef struct mailbox_message { + unsigned long long timestamps; /*!< Time Stamps of message creation */ + unsigned short size; /*!< message size. Should <= MAX_LENGHT_MESSAGE*/ + char message[MAX_LENGHT_MESSAGE]; /*!< Message contents */ +} s_mailbox_message; + +/** + * \struct t_mailbox_message + * \brief define mailbox structure to store message for a dedicated Callsign + * + */ + +typedef struct mail_box { + char messageNumber; + unsigned char indexNextMessage; + unsigned char indexFreeMessage; + unsigned char callsign[CALLSIGN_SIZE]; + unsigned long long timestampCreation; + s_mailbox_message messages[MAX_MESSAGE]; + /* data */ +} s_mailbox; + +typedef struct mailboxes { + + s_mailbox mailbox[MAX_MAILBOX]; + int usedMailboxNumber; + int indexfreeMailbox; + long nbMailboxCommandeReceived; + long nbMailboxErrorCommandeReceived; +} s_mailboxes; + +typedef struct listMailbox { + char callsign[6]; + char nb_message; +} s_list_mailbox; + +typedef struct add_message { + char size; + char message[MAX_LENGHT_MESSAGE]; + +} s_add_message; + +#define SIZE_T_GET_MESSAGE 15 +typedef struct get_message { + unsigned long long timestamps; + char callsign[6]; + unsigned char index; + char message[MAX_LENGHT_MESSAGE]; + +} s_get_message; + +typedef struct cmd_get_message { + unsigned char index; + char callsign[6]; + +} s_cmd_get_message; + +extern void processMailbox(s_ax25_packet data_ax25); +extern unsigned char getListMailbox(t_tc_response *resp); +extern unsigned char addMessage(unsigned char *callsign, char *message, + const unsigned short sizemMessage); +extern unsigned char deleteMailBox(unsigned char *callsign, + t_tc_response *resp); +extern unsigned char initialise(); +extern unsigned char getAllMesage(unsigned char *callsign); + +#endif // MAILBOX_H diff --git a/EmbededSw/src/mailboxMode/modeMailbox.c b/EmbededSw/src/mailboxMode/modeMailbox.c new file mode 100644 index 0000000000000000000000000000000000000000..0ea04c21d12ab59330501375f31fb56fe816b024 --- /dev/null +++ b/EmbededSw/src/mailboxMode/modeMailbox.c @@ -0,0 +1,41 @@ +#include +#include +#include "../core/setup.h" +#include "../drivers/modem.h" +#include "../mailboxMode/mailbox.h" +#include "../errorMngt/error.h" + +unsigned short modeMailbox() { + char data[300]; + s_ax25_packet data_ax25; + + int nbc = readData(data); + + if (nbc != 0) { + /* traitement des donnees recues */ + int res = convertDataToAx25(&data_ax25, data, nbc); + if (res != SUCCESS) { + logger(LOG_LEVEL_CRITICAL, "AX25 CONVESTION ISSUE"); + } + + if (memcmp(gv_spinoConfig.spinoDesCallsign, + data_ax25.header.destinationAdress, 6) == 0) { + if (data_ax25.header.ssidDestination + == (unsigned char) SSID_SPINO_TMTC) { + processCommand(data_ax25); + } else if (data_ax25.header.ssidDestination + == (unsigned char) SSID_SPINO_MAILBOX) { + processMailbox(data_ax25); + + } else { + // Message not awaited - message dropped + processDropMessage(data, (unsigned short) nbc); + } + + } else { + // Message not awaited - message dropped + processDropMessage(data, (unsigned short) nbc); + } + } + return gv_spino.currentState; +} diff --git a/EmbededSw/src/mailboxMode/modeMailbox.h b/EmbededSw/src/mailboxMode/modeMailbox.h new file mode 100644 index 0000000000000000000000000000000000000000..43ea5194aefcd39288932eca916b284a47f6218f --- /dev/null +++ b/EmbededSw/src/mailboxMode/modeMailbox.h @@ -0,0 +1,4 @@ +#ifndef MODEMAILBOX +#define MODEMAILBOX + +#endif // MODEMAILBOX diff --git a/EmbededSw/src/main.c b/EmbededSw/src/main.c new file mode 100644 index 0000000000000000000000000000000000000000..b2c6d037707f5b082353f2e1d1327daffd2a058f --- /dev/null +++ b/EmbededSw/src/main.c @@ -0,0 +1,39 @@ +/** + * \file main.c + * \brief launch simulator + * \author Xtophe + * \version 0.2 + * \date 01/08/2022 + * + */ + +#include +#include +#include "./core/setup.h" + +#define STATE_SURVEY 1 +#define STATE_MAILBOX 2 + +extern void control(); +extern void open(); + +/** + * \fn int main (void) + * \brief Entrée du programme. + * + * \return 0 - Arrêt normal du programme. + */ + +int main(void) { + printf("Spino Emulation V0.3\n"); + + setupGlobalVariable(); + + open(); + + control(); + + printf("END \n\r"); + + return 0; +} diff --git a/EmbededSw/src/payloadMode/payloadMode.c b/EmbededSw/src/payloadMode/payloadMode.c new file mode 100644 index 0000000000000000000000000000000000000000..ca46ac8b956f51c81894e716c66b6badd8a31baa --- /dev/null +++ b/EmbededSw/src/payloadMode/payloadMode.c @@ -0,0 +1,153 @@ +/** + * \file experienceMode.c + * \brief manage Expérience mode + * \author Xtophe + * \version 0.2 + * \date 01/08/2022 + * + * \todo gestion de l'I2C + * \todo faire le .h + * \todo download data + */ + +#include"stdio.h" +#include +#include "../core/setup.h" +#include "../drivers/modem.h" +#include "../errorMngt/error.h" +#include "payloadMode.h" + +static unsigned char I2CReadDataStatus; +static unsigned char I2CWriteDataStatus; +static unsigned char I2CReadData[I2CMAXSIZE]; +static unsigned char I2CWriteData[I2CMAXSIZE]; + +s_I2C_data gv_I2C_Write_Data[I2CMAXDATA]; +int gv_nb_I2CMAXDATA; + +void init() { + I2CReadDataStatus = 0; + I2CWriteDataStatus = 0; +} + +unsigned char getAllI2Cdata(t_tc_response *resp) { + s_ax25_packet ax25Frame; + ax25Frame.header = gv_headerTlm; + resp->header.error_code = SUCCESS; + + int i = 0; + + for (i = 0; i < gv_nb_I2CMAXDATA; i++) { + resp->size = sizeof(s_I2C_data); + memcpy(resp->parameter, &gv_I2C_Write_Data[i].data, resp->size); + memcpy(ax25Frame.data, resp, TC_REPONSE_HEADER_SIZE + resp->size); + writeData(ax25Frame, TC_REPONSE_HEADER_SIZE + resp->size); + } + + resp->size = 0; + return SUCCESS; + +} + +t_tc_response interpretcommandPayload(s_command cmd) { + + t_tc_response resp; + + resp.header.responseType = RESULT_CMD; + resp.header.timeStamp = gv_spino.timestamps; + resp.header.cmd_id = cmd.id; + resp.header.error_code = SUCCESS; + + switch (cmd.id) { + case CMD_PAYLOAD_LOAD_DATA: + logger(LOG_LEVEL_INFO, "Commande CMD_PAYLOAD_LOAD_DATA"); + s_I2C_data data; + memcpy(&data, cmd.parameter, cmd.size); + I2CReadDataStatus = data.size; + memcpy(&I2CReadData, data.data, data.size); + resp.header.error_code = SUCCESS; + break; + + case CMD_PAYLOAD_READ_DATA: /* modify configuration value */ + logger(LOG_LEVEL_INFO, "Commande CMD_PAYLOAD_READ_DATA"); + resp.header.error_code = getAllI2Cdata(&resp); + break; + default: + resp.header.error_code = ERROR_COMMAND_UNKNOW; + } + return resp; +} + +/** + * \fn void processCommand(t_ax25_packet data_ax25) + * \brief process command ax25 packet + * \param Ax25 packet + * \return SUCCESS if or Error code + * + */ +void processCommandePayload(s_ax25_packet data_ax25) { + + t_tc_response result; + s_command cmd; + + gv_spino.nbCommandeReceived++; + memcpy(&cmd, data_ax25.data, sizeof(s_command)); + if (cmd.key != gv_spino_cmd_key) { + result.header.responseType = RESULT_CMD; + result.header.timeStamp = gv_spino.timestamps; + result.header.cmd_id = cmd.id; + result.header.error_code = ERROR_COMMAND_WITH_WRONG_KEY; + result.size = 0; + } else { + result = interpretcommandPayload(cmd); + + } + + if (result.header.error_code != SUCCESS) { + gv_spino.nbCommandeWithError++; + } + s_ax25_packet ax25Frame; + ax25Frame.header = gv_headerTlm; + memcpy(ax25Frame.data, &result, TC_REPONSE_HEADER_SIZE + result.size); + /* envoyer la reponse de la commande */ + writeData(ax25Frame, TC_REPONSE_HEADER_SIZE + result.size); + +} + +unsigned short payloadMode() { + char data[300]; + s_ax25_packet data_ax25; + + int nbc = readData(data); + + if (nbc != 0) { + /* traitement des donnees recues */ + int res = convertDataToAx25(&data_ax25, data, nbc); + if (res != SUCCESS) { + logger(LOG_LEVEL_CRITICAL, "AX25 CONVERSION ISSUE"); + } + + if (memcmp(gv_spinoConfig.spinoDesCallsign, + data_ax25.header.destinationAdress, 6) == 0) { + + if (data_ax25.header.ssidDestination + == (unsigned char) SSID_SPINO_TMTC) { + processCommand(data_ax25); + } else if (data_ax25.header.ssidDestination + == (unsigned char) SSID_SPINO_CUBESAT) { + processCommandePayload(data_ax25); + } else { + logger(LOG_LEVEL_CRITICAL, "MESSAGE DROPED"); + processDropMessage(data, (unsigned short) nbc); + + } + + } else { + // Message not awaited - message dropped + processDropMessage(data, (unsigned short) nbc); + logger(LOG_LEVEL_CRITICAL, "MESSAGE DROPED"); + } + + } + return gv_spino.currentState; +} diff --git a/EmbededSw/src/payloadMode/payloadMode.h b/EmbededSw/src/payloadMode/payloadMode.h new file mode 100644 index 0000000000000000000000000000000000000000..05937358ca666b9d0824a606951719fd1ff9ebc7 --- /dev/null +++ b/EmbededSw/src/payloadMode/payloadMode.h @@ -0,0 +1,16 @@ +#ifndef PAYLOG_MODE_H +#define PAYLOG_MODE_H + +#define I2CMAXSIZE 64 +#define I2CMAXDATA 10 + +#define CMD_PAYLOAD_LOAD_DATA 10 +#define CMD_PAYLOAD_READ_DATA 11 + +typedef struct I2C_data { + unsigned char size; + char data[I2CMAXSIZE]; + +} s_I2C_data; + +#endif // PAYLOG_MODE_H diff --git a/EmbededSw/src/simulation/SpinoSimuServerTCP.c b/EmbededSw/src/simulation/SpinoSimuServerTCP.c new file mode 100644 index 0000000000000000000000000000000000000000..fe0de7ec88b490d38d2ccde875d333a1b2d5f275 --- /dev/null +++ b/EmbededSw/src/simulation/SpinoSimuServerTCP.c @@ -0,0 +1,269 @@ +/*********************************************************************************************** + * + * File Name : tcpServer + * + * Description : manage tcp server for testing purpose + * + * Usage : for Spino simulator only + * + * nota : code based on : http://dwise1.net/pgm/sockets/blocking.html + * + * ********************************************************************************************* + * + * Autor : Xtophe + * + * date : 2022 / 08 /01 + * + * Version : 0.1 + * + * todo : + * + * ********************************************************************************************** + * + * You need to link the library: libws2_32.a + * OR + * -lwsock32 + * -lws2_32 + * from c:\TDM-GCC-64\x86_64-w64-mingw32\lib32\ + * OR + * c:\MinGW\lib\ + * if you using GCC on windows + ***********************************************************************************************/ + +/*========= INCLUDES ==========================================================================*/ + +#include +#include +#include +#include +#include "SpinoSimuServerTCP.h" + +/*========= GLOBAL VARIABLES ===================================================================*/ + +char gv_simu_receiveddata[MAX_DATA]; +int gv_simu_nb_data_received = 0; + +SOCKET m_ServerSock; /* server's listening socket */ +SOCKET gv_m_client_list[MAX_CLIENTS]; +int m_iNumclients; +SOCKET gv_AcceptSocket; +SOCKET TCPServerSocket; + +unsigned char test[6] = { 0x0, 0x01, 0x0F, 0x10, 0xF0, 0xFF }; + +/*========= FUNCTIONS ========================================================================*/ + +/*--------------------------------------------------------------------------------------------------------- + * + * HandleClient(SOCKET AcceptSocket) : + * + * description : perform treatment when data are received + * + * + ---------------------------------------------------------------------------------------------------------*/ + +void HandleClient(SOCKET AcceptSocket) { +// STEP-7 Send Message to Client + gv_simu_nb_data_received = 0; + gv_simu_nb_data_received = recv(AcceptSocket, gv_simu_receiveddata, + MAX_DATA, 0); + if (gv_simu_nb_data_received == (int) SOCKET_ERROR) { + printf("SERVER: Receive Failed, Error: %d\n", WSAGetLastError()); + exit(-1); + gv_simu_nb_data_received = 0; + } + +} + +/*--------------------------------------------------------------------------------------------------------- + * + * PerformSelect(SOCKET listeningSock, SOCKET clients[], int iNumClients)) : + * + * description : see http://dwise1.net/pgm/sockets/blocking.html#SELECT + * + * + ---------------------------------------------------------------------------------------------------------*/ + +void PerformSelect(SOCKET listeningSock, SOCKET clients[], int iNumClients) { + fd_set sockSet; /* Set of socket descriptors for select() */ + struct timeval selTimeout; /* Timeout for select() */ + int i; + int iResult; + + /* Zero socket descriptor vector and set for server sockets */ + /* This must be reset every time select() is called */ + FD_ZERO(&sockSet); + FD_SET(listeningSock, &sockSet); + for (i = 0; i < iNumClients; i++) + FD_SET(clients[i], &sockSet); + + /* Timeout specification */ + /* This must be reset every time select() is called */ + selTimeout.tv_sec = 0; /* timeout (secs.) */ + selTimeout.tv_usec = 100000; /* 0 microseconds */ + + iResult = select(0, &sockSet, NULL, NULL, &selTimeout); + + if (iResult == -1) { + /* an error occurred; process it (eg, display error message) */ + } else if (iResult > 0) /* ie, if a socket is ready */ + { + // test this specific socket to see if it was one of the ones that was set + // if (FD_ISSET(listeningSock, &sockSet)) + // { + // AcceptNewClient(listeningSock); + // } + + /* Now test the client sockets */ + for (i = 0; i < iNumClients; i++) + if (FD_ISSET(clients[i], &sockSet)) { + /* do whatever it takes to read the socket and handle the client */ + /* Please note that this will involve reassociating the socket */ + /* with the client record */ + HandleClient(clients[i]); + } + } + + /* else iResult == 0, no socket is ready to be read, */ + /* so ignore them and move on. */ + +} + +/*--------------------------------------------------------------------------------------------------------- + * + * OpenAndWait ( ) : + * + * description : initialise and wait a client + * + * + ---------------------------------------------------------------------------------------------------------*/ + +void TCP_OpenAndWait() { + printf("TCP SERVER\n"); + + WSADATA Winsockdata; + + struct sockaddr_in TCPServerAddr; + struct sockaddr_in TCPClientAddr; + int TCPClientAddrSize = sizeof(TCPClientAddr); + + // STEP-1 WSAStartUp + if (WSAStartup(MAKEWORD(2, 2), &Winsockdata) != 0) { + printf("SERVER: WSAStartUp Failed"); + } + printf("SERVER: WSAStartUp Success\n"); + + // STEP-2 Fill TCPServerAddr Struct + TCPServerAddr.sin_family = AF_INET; + TCPServerAddr.sin_addr.s_addr = inet_addr("127.0.0.1"); + TCPServerAddr.sin_port = htons(8888); + + //STEP-3 Create Socket + if ((TCPServerSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) + == INVALID_SOCKET) { + printf("SERVER: TCP Server: Create Socket Failed, Error: %d\n", + WSAGetLastError()); + } + printf("SERVER: TCP Server: Create Socket Success\n"); + + //STEP-4 bind + if (bind(TCPServerSocket, (SOCKADDR*) &TCPServerAddr, + sizeof(TCPServerAddr)) == SOCKET_ERROR) { + printf("SERVER: Binding Failed, Error: %d", WSAGetLastError()); + } + printf("SERVER: Binding Success\n"); + + //STEP-5 Listen + if (listen(TCPServerSocket, 2) == SOCKET_ERROR) { + printf("SERVER: Listen Failed, Error: %d", WSAGetLastError()); + } + printf("SERVER: Listen Success: Listening for incoming connection...\n"); + + // STEP-6 Accept + if ((gv_AcceptSocket = accept(TCPServerSocket, (SOCKADDR*) &TCPClientAddr, + &TCPClientAddrSize)) == INVALID_SOCKET) { + printf("SERVER: Accept Failed, Error: %d\n", WSAGetLastError()); + } + printf("SERVER: Connection Accepted\n"); + m_ServerSock = 2; + gv_m_client_list[0] = gv_AcceptSocket; + +} + +/*--------------------------------------------------------------------------------------------------------- + * + * TCP_closeALL ( ) : + * + * description : close all open port. + * + * + ---------------------------------------------------------------------------------------------------------*/ +void TCP_closeAll() { + // STEP-9 Close Socket + if (closesocket(TCPServerSocket) == SOCKET_ERROR) { + printf("SERVER: Close Socket Failed, Error: %d\n", WSAGetLastError()); + } + printf("SERVER: Close Socket Success\n"); + + // STEP-10 Clean + if (WSACleanup() == SOCKET_ERROR) { + printf("SERVER: WSACleanup Failed, Error: %d\n", WSAGetLastError()); + } + printf("SERVER: WSACleanup Success\n"); +} + +/*--------------------------------------------------------------------------------------------------------- + * + * TCP_send ( byte data, int nbdata ) : + * + * description : send data + * + * + ---------------------------------------------------------------------------------------------------------*/ + +void TCP_Send(char *data, int nb) { + if (send(gv_AcceptSocket, data, nb, 0) == SOCKET_ERROR) { + printf("SERVER: Send Failed Error: %d\n", WSAGetLastError()); + } + printf("SERVER: Message Sent!\n"); +} + +// int main() { + +// unsigned char test[6]={0x0,0x01,0x0F,0x10,0xF0,0xFF}; +// TCP_OpenAndWait (); +// int i; +// while (1) +// { +// PerformSelect(gv_AcceptSocket, gv_m_client_list, 1); + +// if (gv_simu_nb_data_received!=0) +// { +// printf("data recieved %d \r\n",gv_simu_nb_data_received ); +// gv_simu_nb_data_received=0; +// TCP_Send (test,6); +// +// } else +// { +// printf("wait", i++); +// } +// +// } + +//} + +/* + run: + + TCP SERVER + SERVER: WSAStartUp Success + SERVER: TCP Server: Create Socket Success + SERVER: Binding Success + SERVER: Listen Success: Listening for incoming connection... + SERVER: Connection Accepted + SERVER: Message Sent! + SERVER: Received Message From Client: Hello from Client! + SERVER: Close Socket Success + SERVER: WSACleanup Success + + */ diff --git a/EmbededSw/src/simulation/SpinoSimuServerTCP.h b/EmbededSw/src/simulation/SpinoSimuServerTCP.h new file mode 100644 index 0000000000000000000000000000000000000000..f1953dcc6f48c46d30d7889f396229db72d34e61 --- /dev/null +++ b/EmbededSw/src/simulation/SpinoSimuServerTCP.h @@ -0,0 +1,19 @@ +#ifndef SPINOSIMUSERVER_H +#define SPINOSIMUSERVER_H + +#include + +#define MAX_DATA 512 +#define MAX_CLIENTS 2 + +extern char gv_simu_receiveddata[]; +extern int gv_simu_nb_data_received; +extern SOCKET gv_m_client_list[MAX_CLIENTS]; +extern SOCKET gv_AcceptSocket; + +extern void PerformSelect(SOCKET listeningSock, SOCKET clients[], + int iNumClients); +extern void TCP_OpenAndWait(); +extern void TCP_Send(char *data, int nb); + +#endif //SPINOSIMUSERVER_H diff --git a/EmbededSw/src/simulation/lecfic.c b/EmbededSw/src/simulation/lecfic.c new file mode 100644 index 0000000000000000000000000000000000000000..9b1d6e11c277fc3c86e84159877377a9d19489e6 --- /dev/null +++ b/EmbededSw/src/simulation/lecfic.c @@ -0,0 +1,79 @@ +#include +#include +#include + +#include "../ax25/ax25.h" + +#define TAILLE_BUF 300 /* valeur quelconque (en général, beaucoup plus grande) */ + +FILE *fichier; + +void openfile(char *filename) { + + fichier = fopen(filename, "rb"); + if (fichier == NULL) { + printf("Ouverture du fichier impossible !"); + exit(0); + } + +} + +int lectureData(char *data) { + int nb_val_lues; + + unsigned char taille; + // lecture taille data + nb_val_lues = (int) fread(&taille, sizeof(char), 1, fichier); + if (nb_val_lues != 0) + nb_val_lues = (int) fread(data, sizeof(char), (size_t) taille, fichier); + return nb_val_lues; + +} + +int lectureFile(char *filename, char *data) { + FILE *fic; + + // char [TAILLE_BUF]; /* ce tableau mémorisera les valeurs lues dans le fichier */ + short int nb_val_lues = TAILLE_BUF; + /* Ouverture du fichier (en lecture binaire) : */ + fic = fopen(filename, "rb"); + if (fic == NULL) { + printf("Ouverture du fichier impossible !"); + exit(0); + } + /* Lecture dans le fichier : */ + printf("\n Liste des valeurs lues : \n"); + /*Remplissage du buffer et traitement, autant de fois que nécessaire jusqu'à la fin fichier : */ + while (nb_val_lues == TAILLE_BUF) /* vrai tant que fin du fichier non atteinte */ + { + + nb_val_lues = (short int) fread(data, sizeof(char), TAILLE_BUF, fic); + /* Traitement des valeurs stockées dans le buffer (ici, un simple affichage) : */ + // for (i=0; i +#include "../core/setup.h" +#include "../drivers/modem.h" +#include "../errorMngt/error.h" +#include "../dropMsgMngt/DropMessage.h" + +unsigned short survey() { + char data[300]; + s_ax25_packet data_ax25; + + int nbc = readData(data); + if (nbc != 0) { + /* traitement des donnees recues */ + int res = convertDataToAx25(&data_ax25, data, nbc); + if (res != SUCCESS) { + logger(LOG_LEVEL_CRITICAL, "AX25 CONVESTION ISSUE"); + } + + if (memcmp(gv_spinoConfig.spinoDesCallsign, + data_ax25.header.destinationAdress, 6) == 0) { + + if (data_ax25.header.ssidDestination + == (unsigned char) SSID_SPINO_TMTC) { + processCommand(data_ax25); + } + } else { + // Message not awaited - message dropped + processDropMessage(data, (unsigned short) nbc); + + } + + } + return gv_spino.currentState; +} diff --git a/SPECIFICATIONS/AX25_Usage_on_Spino.md b/SPECIFICATIONS/AX25_Usage_on_Spino.md index 7ded5d4fc2792da32eaec9c8a29d363a39da642a..c2e82b66c7cdea046f58b60b2ff651a2b98740f4 100644 --- a/SPECIFICATIONS/AX25_Usage_on_Spino.md +++ b/SPECIFICATIONS/AX25_Usage_on_Spino.md @@ -59,25 +59,28 @@ Spino allows two usages : A dedicated callsign is defined for Hamradio experimentation. If the associated capability of the spino is not active all packet with the correponding SSID are droped - | SSID | Usage | Comments | link to the description | -|------|-----------------------|---------------------------------------------------------------------|-------------------------| -| 0 | Not used | | | -| 1 | Telemetry | used for Spino telemetry | | -| 2 | Short message mailbox | Used for Short message mailbox capability | | -| 3 | | | | -| 4 | | | | -| 5 | | | | -| 6 | | | | -| 7 | | | | -| 8 | | | | -| 9 | | | | -| 10 | | | | -| 11 | | | | -| 12 | | | | -| 13 | | | | -| 14 | | | | -| 15 | SPINO TM/TC | Reserved to team in charge of Spino experiment (Command & Control) | | + | SSID | Usage | Comments | Mode | link to the description | +|------|-----------------------|---------------------------------------------------------------------|------|-------------------------| +| 0 | Not used | | | | +| 1 | Telemetry | used for Spino telemetry | ALL | | +| 2 | Short message mailbox | Used for Short message mailbox capability | Mailbox | | +| 3 | Digipeater | received a message and broadcast message | Digipeater | | +| 4 | Payload usage | allows data exchange with cubesat OBC | Payload | | +| 5 | Experimental | | Experimental | | +| 6 | Not used | | | | +| 7 | Not used | | | | +| 8 | Not used | | | | +| 9 | Not used | | | | +| 10 | Not used | | | | +| 11 | Not used | | | | +| 12 | Not used | | | | +| 13 | Not used | | | | +| 14 | Not used | | | | +| 15 | SPINO TM/TC | Reserved to team in charge of Spino experiment (Command & Control) | | | + + + #### Telecomand/telemetry management for satellite -TBD +TBD \ No newline at end of file diff --git a/SPECIFICATIONS/Ground station to OBC.plantuml b/SPECIFICATIONS/Ground station to OBC.plantuml new file mode 100644 index 0000000000000000000000000000000000000000..7a8f6475831ab661212c01b1170aa27e30a4776d --- /dev/null +++ b/SPECIFICATIONS/Ground station to OBC.plantuml @@ -0,0 +1,16 @@ +@startuml + +CubesatGroundStation -> SPINO : send data to spino +SPINO -> SPINO : write data to I2CReceivedBuffer +SPINO -> SPINO : write nb data in I2CSatusReceivedBuffer +SPINO -> CubesatGroundStation : send acknolegment + +SPINO -> CubesatGroundStation : Send TLM with value of I2CSatusReceivedBuffer + +UVSQsat_OBC -> SPINO: check if I2CSatusReceivedBuffer not equal 0 +UVSQsat_OBC -> SPINO: read I2CReceivedBuffer +UVSQsat_OBC -> SPINO: set I2CSatusReceivedBuffer to 0 + +SPINO -> CubesatGroundStation : Send TLM with value of I2CSatusReceivedBuffer + +@enduml \ No newline at end of file diff --git a/SPECIFICATIONS/Ground_station_to_OBC.png b/SPECIFICATIONS/Ground_station_to_OBC.png new file mode 100644 index 0000000000000000000000000000000000000000..c187c221fbbb46831fb313b65af0df960da9c27f Binary files /dev/null and b/SPECIFICATIONS/Ground_station_to_OBC.png differ diff --git a/SPECIFICATIONS/I2C register.plantuml b/SPECIFICATIONS/I2C register.plantuml new file mode 100644 index 0000000000000000000000000000000000000000..c0405a976e641459c1f03d0e5ed9025e2166a242 --- /dev/null +++ b/SPECIFICATIONS/I2C register.plantuml @@ -0,0 +1,12 @@ +@startuml + +start +:I2C Communication between OBC and SPINO +<#red>|= action |= name |= size | +<#blue>|Transmit | I2CSatusTransmitBuffer| 1 octet | +<#blue>|Transmit | I2CTransmitBuffer | n(64) octet | +<#yellow>|Receive | I2CSatusReceivedBuffer| 1 octet | +<#yellow>|Receive | I2CReceivedBuffer | n(64) octet |> + + +@enduml \ No newline at end of file diff --git a/SPECIFICATIONS/I2C_register.png b/SPECIFICATIONS/I2C_register.png new file mode 100644 index 0000000000000000000000000000000000000000..1511833b5aaac7ccad3006022da55d9b8f69862b Binary files /dev/null and b/SPECIFICATIONS/I2C_register.png differ diff --git a/SPECIFICATIONS/MailboxMode.md b/SPECIFICATIONS/MailboxMode.md index 3b69cfbf61019f51b66437a56a85d988363d9319..c1032924ed6e31f8721c5359e5af39ce90211188 100644 --- a/SPECIFICATIONS/MailboxMode.md +++ b/SPECIFICATIONS/MailboxMode.md @@ -1,6 +1,6 @@ | Last modification | Status | |-------------------- |--------- | -| 21/02/2022 | Draft | +| 02/03/2022 | Draft | # Short message mailbox mode @@ -19,61 +19,116 @@ Allows to the users to create a temporary dedicated mailbox to a user and allow - Automatic expiration of users as soon as the mailbox is empty - Messages are managed like a FIFO stack -## Usage +## Commands + + + ### Sending a message Scenario to send a message (AX25 header ignored, the considered protocol layer is encapsulated in the payload): -The "ARSxyz" station sends a message to the "ARSuvw" station +The "ARSxyz" station sends a message to the mailbox -> sending "ARSxyz" station identified by its call in the AX25 header --> AX25 payload consisting of : call destination station + reference counter + message (424 bytes max) -<- ACK from SPINO (or NACK : limit of the destination mailbox exceeded, or impossible to create a new mailbox) +-> AX25 payload consisting of : Command add message + message +<- SPINO send an acknowledgment message Success or NACK : limit of the destination mailbox exceeded, or impossible to create a new mailbox +Command : CMD_MAILBOX_ADD_MSG +parameters : message to store +### request last message -### viewing the list of messages of a box +Command : CMD_MAILBOX_GET_LAST_MSG : +parameters : none -- (list of 16 messages identified by sender and number) + +### request all mailbox message -### viewing a message -(identified by its number) +Command : CMD_MAILBOX_GET_ALL_MSG +parameters : none -### delete a message -(identified by its number) +### viewing the list of messages of a box -### viewing the list of active mailboxes +User send request *List all message in a mailbox* to Satellite with Mailbox Callsign +If the mailbox exist, the satellite send following information : +- number of message in the mailbox +- list of message information : Message id & time +If the mailbox does not exist, the satellite send a acknolegment with the error message : Mailbox not available -- viewing the list of active mailboxes (list of max 64 active mailboxes at a given time) +Command : +parameters : -### flush of mailboxes (Service Message) +### read a message +User send request *Read message* to Satellite with Mailbox Callsign and Message ID +If the message in the mailbox exist, the satellite send following information : +- time, +- message id, +- message information -## Activation +If the message in the mailbox does not exist, the satellite send a acknolegment with the error message : Message not available +If the mailbox does not exist, the satellite send a acknolegment with the error message : Mailbox not available -- -- based on AX25 protocol -- Service message (protected by a private key as head of the payload) are read/write of configuration registers allowing : +Command : CMD_MAILBOX_GET_MSG +parameters : message index +parameters : Mailbox Callsign +### delete the first message +User send request *Delette message* to Satellite. +If the message in the mailbox exist, the satellite send a acknolegment with the information : message deleted +If the message in the mailbox does not exist, the satellite send a acknolegment with the error message : Message not available +If the mailbox does not exist, the satellite send a acknolegment with the error message : Mailbox not available +Command : CMD_MAILBOX_DEL_MSG +parameters : none +### viewing the list of active mailboxes + +User send request *List all mailbox* to Satellite +The satellite send following information : + +- list of mailbox callsign +- number of message available +Command : CMD_MAILBOX_GET_LIST_BOX +parameters : none +### delete a mailbox +User send request *Delete mailbox* to Satellite with Mailbox Callsign +If the message in the mailbox exist, the satellite send a acknolegment with the information : mailbox deleted +If the mailbox does not exist, the satellite send a acknolegment with the error message : Mailbox not available +Command : CMD_MAILBOX_DELETTE_BOX +parameters : none + +### flush of mailboxes (Service Message) +User send request *Flush all mailbox* to Satellite +the satellite delette all mailbox and message +the satellite send a acknolegment with the information : mailboxes deleted + +Command : CMD_MAILBOX_INIT +parameters : none +### Dump all Mailbox +Command : CMD_MAILBOX_DUMP_MAILBOX +parameters : none +## Activation +- +- based on AX25 protocol +- Service message (protected by a private key as head of the payload) are read/write of configuration registers allowing : diff --git a/SPECIFICATIONS/OBC to Ground Station.plantuml b/SPECIFICATIONS/OBC to Ground Station.plantuml new file mode 100644 index 0000000000000000000000000000000000000000..f93b0ced3d30013f4312afb4bcbf009a6f715c1b --- /dev/null +++ b/SPECIFICATIONS/OBC to Ground Station.plantuml @@ -0,0 +1,17 @@ +@startuml + +UVSQsat_OBC -> SPINO: check if I2CSatusTransmitBuffer equal 0 +UVSQsat_OBC -> SPINO: write data in the TransmitBufer +UVSQsat_OBC -> SPINO: write nb byte in the I2CSatusTransmitBuffer +SPINO -> SPINO: when I2CSatusTransmitBuffer not Equal to 0 +SPINO -> SPINO: Transfert TransmitBufer in the SpinoDataBuffer +SPINO -> SPINO: write I2CSatusTransmitBuffer to 0 + +SPINO -> CubesatGroundStation : Send TLM with nb UVSQsat_OBC packet available + +CubesatGroundStation -> SPINO : Request data stored in SpinoDataBuffer +SPINO -> CubesatGroundStation : Send data to ground station +CubesatGroundStation -> SPINO : Request delete data stored in SpinoDataBuffer +SPINO -> CubesatGroundStation : erase data and send acknolegment + +@enduml \ No newline at end of file diff --git a/SPECIFICATIONS/OBC_to_Ground_Station.png b/SPECIFICATIONS/OBC_to_Ground_Station.png new file mode 100644 index 0000000000000000000000000000000000000000..342a73dc38197ab4dbe3180fa6ff4e6559b6e045 Binary files /dev/null and b/SPECIFICATIONS/OBC_to_Ground_Station.png differ diff --git a/SPECIFICATIONS/PayloadMode.md b/SPECIFICATIONS/PayloadMode.md new file mode 100644 index 0000000000000000000000000000000000000000..473ba16a8d62b80a0c818bb4a992ba71c8eaf990 --- /dev/null +++ b/SPECIFICATIONS/PayloadMode.md @@ -0,0 +1,45 @@ +# Primary Payload Mode + +## Description + +This mode is dedicated to the cubesat wich host the Spino card. +It's allow + - to send data to from the Cubesat OBC + - received data from the control station and provide data to Cubesat OBC + +## protocol + +### Cubesat OBC to SPINO + + - Cubesat OBC check if dedicated register is free (0) + - Cubesat OBC write data in a dedicated buffer + - Cubesat OBC write nb bytes available in a dedicated register + - SPINO detect data available + - Spino store message in massage list + - Spino set dedicated register to 0 + + - Cubesat Ground Station request data + - SPINO send data + +![OBC to Ground station](OBC_to_Ground_Station.png) + +### Cubesat OBC to SPINO + + - Cubesat Ground Station sent data to SPINO + - SPINO write data iin a dedicated buffer + - SPINO OBC write nb bytes available in a dedicated register + - Cubesat OBC check if dedicated register as data + - Cubesat OBC read data from dedicated buffer + - Cubesat OBC write 0 in a dedicated register + +![Ground station to OBC](./Ground_station_to_OBC.png) + +## interface + + the interface bewteen the OBC Cubesat and Spino is based on I2C communication bus + + + +![I2C register](./I2C_register.png) +## + diff --git a/SPECIFICATIONS/Short_message_mailbox_messages_description.md b/SPECIFICATIONS/Short_message_mailbox_messages_description.md index 400299a83322150446f9a1fa33db70c2e6fb304c..a2aa78f32f556256388b681e13fcc7d2cdb59cbe 100644 --- a/SPECIFICATIONS/Short_message_mailbox_messages_description.md +++ b/SPECIFICATIONS/Short_message_mailbox_messages_description.md @@ -7,12 +7,12 @@ ## Command message -### AX25 UI Frame +### AX25 UI Frame Command | Flag | Destination Calssign | Destination SSID | Source Address | Source SSID | Control Bits | Protocol | Mailbox commandes | Mailbox Parameters | Frame Check Sequence | Flag | |------|----------------------|-------------------|----------------|--------------|-------------|----------|-------------------|-------------------|-----------------------------|------| | 8 | 48 | 8 | 48 | 8 | 8 | 8 | 8 | 0-242 | 16 | 8 | -#### Commands +### Commands @@ -20,11 +20,37 @@ |:-----------------------------:|:--------------:|:--------------------------------------------------------:|:-------:| | Add Message | 0 | Message contents [0-242] bytes | | | Delette message | 1 | Mailbox Name : (Callsign) 6 byte | | -| | | Message ID : 1 byte | | +| | | Message ID : 1 byte | | | Delette mailbox | 2 | Mailbox Name : (Callsign) 6 byte | | | List all mailbox | 3 | | | | List all message in a mailbox | 4 | Mailbox Name : (Callsign) 6 byte | | -| Flush all mailbox | 5 | secure word : 4 bytes | | -| | | | | +| Flush all mailbox | 5 | Secure word : 4 bytes | | +| Read message | 6 | Mailbox Name : (Callsign) 6 byte | | +| | | Message ID : 1 byte | | +## Acknolegment Message + +### AX25 UI Frame Acknolegment + +| Flag | Destination Calssign | Destination SSID | Source Address | Source SSID | Control Bits | Protocol | Mailbox Acknolegment| Parameters | Frame Check Sequence | Flag | +|------|----------------------|-------------------|----------------|--------------|-------------|----------|---------------------|-------------------|-----------------------------|------| +| 8 | 48 | 8 | 48 | 8 | 8 | 8 | 8 | 0-1 | 16 | 8 | + + + +The call sign of the station that sent the message will be put in the destination field of the AX25 frame header. + +### Acknolegment Value + +| Return | Value | parameter | Comments | +|----------------------------------------|:-----:|-----------------------------|-----------------------------------------------| +| Message added | 0 | Message identifier : 1 byte | | +| Mailbox created and message added | 1 | Message identifier : 1 byte | | +| Commande accepted | 2 | Command identifier : 1 byte | | +| Error - Message too long | -1 | | | +| Error - Message empty | -2 | | | +| Error - Mailbox not available | -3 | | Maximum mailbox number reached | +| Error - Mailbox full | -4 | | Maximum message number reached in the mailbox | +| Error - Commande not executed | -5 | Command identifier : 1 byte | | +| Error - Message box mode not available | -127 | | | diff --git a/SPECIFICATIONS/States.md b/SPECIFICATIONS/States.md index 6efb6a911189edde42a453d9bee5243dfd0f1f84..dccbef1a0d320ee0f2ded88ef66db592c2bdc576 100644 --- a/SPECIFICATIONS/States.md +++ b/SPECIFICATIONS/States.md @@ -6,6 +6,25 @@ # States diagram ![State diagram](./States.svg) +* + +- [Survey Mode](./SurveyMode.md) +- [Digipeater Mode] (./DigipeaterMode.md) +- [Mailbox Mode] (./MailboxMode.md) +- [Experimental Mode] (./ExperimentalMode.md) +- [Payload Mode] (./PayloadMode.md) + + +# Capability versus mode + +| Capabilties | Survey | Digipeater | Mailbox | Experimental | Payload | +|:---------------|:------:|:----------:|:-------:|:------------:|:-------:| +| Spino Beacon | X | X | X | X | X | +| Command core | X | X | X | X | X | +| retransmit msg | | X | | | | +| Mailbox | | | X | X (1) | | +| TLE data | | | | X | | +| Expe Beacon | | | | X | | +| Exchange OBC | | | | | X | + -- [Failsafe Mode](./FailsafeMode.md) -- \ No newline at end of file diff --git a/SPECIFICATIONS/States.svg b/SPECIFICATIONS/States.svg index f0eee179b1986bb60099d0c78a8284576e7141f1..24012336173d26d69b48918ac392009777908e19 100644 --- a/SPECIFICATIONS/States.svg +++ b/SPECIFICATIONS/States.svg @@ -1,4 +1,33 @@ - - - -

Failsafe

Failsafe

Short Message Mailbox

Short Message Mailbox

Digital Transponder

Digital Transponder
MailBoxCommande
MailBoxCommande
TransponderCommande
TransponderCommande
TranspondeurCommandeOFF
TranspondeurCommandeOFF
PowerOn
PowerOn
Text is not SVG - cannot display
\ No newline at end of file +InitSurveyDigipeaterMailboxExperimentalPayload \ No newline at end of file diff --git a/SPECIFICATIONS/FailsafeMode.md b/SPECIFICATIONS/SurveyMode.md similarity index 71% rename from SPECIFICATIONS/FailsafeMode.md rename to SPECIFICATIONS/SurveyMode.md index e95b6734aae7adb6dd9ab044a3b32a67484d970c..104bd0ad5995f7a0ff1fd63a0a22373ff4344371 100644 --- a/SPECIFICATIONS/FailsafeMode.md +++ b/SPECIFICATIONS/SurveyMode.md @@ -4,7 +4,7 @@ | 21/02/2022 | Draft | -# Failsafe mode +# Survey mode ## scope @@ -19,8 +19,3 @@ After communications to the community via WEBsite and Twitter, other modulations ## Usage -### system reset (Service Message) - -### setting of modulations used (Service Message) - -### activation / deactivation of a beacon mode and periodicity (Service Message) \ No newline at end of file diff --git a/SPECIFICATIONS/commande.md b/SPECIFICATIONS/commande.md new file mode 100644 index 0000000000000000000000000000000000000000..71fd1140901047e5d39e7a13cb294e96cefb2de2 --- /dev/null +++ b/SPECIFICATIONS/commande.md @@ -0,0 +1,38 @@ + +| Last modification | Status | +|-------------------- |--------- | +| 10/09/2022 | Draft | + + +# Command list + +| Command Name | Commande value | parameters | comment | +|:-----------------------------:|:--------------:|:--------------------------------------------------------:|:-------:| +| Reset | 100 | none | | +| set value | 101 | see set value parameters | | +| get value | 102 | Data Id : 2 byte (see data ID | | +| get config | 103 | Mailbox Name : (Callsign) 6 byte | | +| get last message dropped | 120 | none | | +| get all messages dropped | 121 | none | | +| get last log | 130 | none | | +| get all log | 131 | none | | +| set information message | 132 | | | +| set information message | 133 | | | + + + + + +# set value parameters + +| data name | Id | RW | comment | +| :------------: | :------------: | :------------: | :------------: | +|VALUE_SPINO_VERSION | 128 | R | | +| VALUE_SPINO_DELAY | 1 | R/W | | +| VALUE_CALLSIGN_SRC_SPINO | 2 | R/W | | +|VALUE_CALLSIGN_DES_SPINO | 3| R/W | | +| VALUE_CALLSIGN_PAYLOAD_SPINO | 4 | R/W | | +| VALUE_TIMESTAMP | 5 | R/W | | +| VALUE_LOG_LEVEL | 6 | R/W | | +| VALUE_ACTIVE_INFO_MESSAGE | 7 | R/W | | +| VALUE_DELAY_INFO_MESSAGE | 8 | R/W | | \ No newline at end of file diff --git a/SPECIFICATIONS/state.puml b/SPECIFICATIONS/state.puml new file mode 100644 index 0000000000000000000000000000000000000000..5cee7f573512972d2d7a9ed107884d46a54a1715 --- /dev/null +++ b/SPECIFICATIONS/state.puml @@ -0,0 +1,15 @@ +@startuml + +[*] --> Init +Init --> Survey +Survey --> Digipeater +Survey --> Mailbox +Survey --> Experimental +Survey --> Payload + +Digipeater --> Survey +Mailbox --> Survey +Experimental --> Survey +Payload --> Survey + +@enduml \ No newline at end of file diff --git a/SPECIFICATIONS/todo.md b/SPECIFICATIONS/todo.md new file mode 100644 index 0000000000000000000000000000000000000000..cd901a42b258e36ceff55c90949f3525cdf5429f --- /dev/null +++ b/SPECIFICATIONS/todo.md @@ -0,0 +1,43 @@ + +[X] gestion de l'entête AX25 envoie + +[X] gestion de la version + [X] indication version + [X] get Version + +[X] gestion de la télémesure + [X] trame de TLM + [X] positionnement du niveau de log + + +[X] possibilité de mettre à l'heure + [X] commande Set timeS + +[] gestion message d'information + [X] add info MSG + [X] del info MSG + [X] Active/ not active + [ ] envoie message info + [X] delai info message + +[X] gestion des logs + [X] recupération d'un message de log + [X] recupération de tous les messages de logs + +[X] gestion message dropped + [X] recupération d'un message dropped + [X] recupération de tous les messages dropped + +[X] ajout d'une clée pour la commande + +[X] gestion des size => passage de char a short + +[ ] Gestion du mode EXPERIMENTAL +[ ] Gestion du mode Main Payload + +[ ] Maiblox + [ ] timer de netoyage + +[ ] revisiter l'envoie TLM / + Message info + +[ ] Message info - init