diff --git a/UAV-ControlSystem/inc/Scheduler/scheduler.h b/UAV-ControlSystem/inc/Scheduler/scheduler.h index 5c17864..ce9186c 100644 --- a/UAV-ControlSystem/inc/Scheduler/scheduler.h +++ b/UAV-ControlSystem/inc/Scheduler/scheduler.h @@ -23,7 +23,6 @@ #define SCHEDULER_H_ #include -#include #include "stm32f4xx_revo.h" #define taskAgeCycleCounterSize 16 @@ -92,6 +91,7 @@ typedef enum TASK_ACCELEROMETER, TASK_ATTITUDE, TASK_RX, + TASK_RX_CLI, TASK_SERIAL, TASK_BATTERY, #ifdef BARO diff --git a/UAV-ControlSystem/inc/Scheduler/tasks.h b/UAV-ControlSystem/inc/Scheduler/tasks.h index 9b5ee73..2a6c79c 100644 --- a/UAV-ControlSystem/inc/Scheduler/tasks.h +++ b/UAV-ControlSystem/inc/Scheduler/tasks.h @@ -34,6 +34,8 @@ void systemTaskAccelerometer(void); void systemTaskAttitude(void); void systemTaskRx(void); bool systemTaskRxCheck(uint32_t currentDeltaTime); +void systemTaskRxCli(void); +bool systemTaskRxCliCheck(uint32_t currentDeltaTime); void systemTaskSerial(void); void systemTaskBattery(void); void systemTaskBaro(void); diff --git a/UAV-ControlSystem/inc/config/cli.h b/UAV-ControlSystem/inc/config/cli.h index d510730..c686d3b 100644 --- a/UAV-ControlSystem/inc/config/cli.h +++ b/UAV-ControlSystem/inc/config/cli.h @@ -1,21 +1,59 @@ -/* - * cli.h - * - * Created on: 30 sep. 2016 - * Author: holmis - */ + /********************************************************************** + * NAME: cli.h * + * AUTHOR: Jonas Holmberg * + * PURPOSE: Provide the ability to change some values by use of * + * command line interface. * + * INFORMATION: By some predefined commands values can be changed in * + * the system by writing in a serial communication * + * terminal that runs on usart. It also has the ability * + * to save the value changes to EEPROM and reset all * + * values. The system can also be reseted and rebooted. * + * * + * GLOBAL VARIABLES: * + * Variable Type Description * + * -------- ---- ----------- * + * cliUsart Usart_profile The handler to the usart used by the cli* * + **********************************************************************/ #ifndef CONFIG_CLI_H_ #define CONFIG_CLI_H_ +#include "drivers/usart.h" + +/* The handler to the usart that is used by the CLI */ +extern usart_profile cliUsart; /*********************************************************************** -* BRIEF: Call will start the cli loop * +* BRIEF: Call will start the cli loop * * INFORMATION: Should be invoked if you want to start the cli loop, * * will try to read instructions until told to stop. * * Will not be part of the regular scheduler loop. * ***********************************************************************/ void cliRun(); +/*********************************************************************** +* BRIEF: Initiates the CLI * +* INFORMATION: The function initiates the CLI. To do this it will need * +* a usart that it should receive its commands from. * +***********************************************************************/ +void cliInit(USART_TypeDef* usart); + +/*********************************************************************** +* BRIEF: Function that checks if the CLI asigned usart has a new * +* message that can be read. * +* INFORMATION: If there is a new message in the designated usart the * +* function will return true, otherwise false. * +***********************************************************************/ +bool cliHasMessage(); + +/*********************************************************************** +* BRIEF: Reads a cahracter from the usart and checks if it * +* is the start character for the CLI. * +* INFORMATION: Will read a character from the usart and compare if it * +* is the character that needs to be read to start the CLI * +***********************************************************************/ +bool cliShouldRun(); + + #endif /* CONFIG_CLI_H_ */ diff --git a/UAV-ControlSystem/inc/config/eeprom.h b/UAV-ControlSystem/inc/config/eeprom.h index 1de5ba2..ee5f433 100644 --- a/UAV-ControlSystem/inc/config/eeprom.h +++ b/UAV-ControlSystem/inc/config/eeprom.h @@ -19,6 +19,7 @@ #define CONFIG_EEPROM_H_ #include "stm32f4xx.h" +#include "stm32f4xx_revo.h" /* Macros used to check if a define has no value assigned */ #define DO_EXPAND(VAL) VAL ## 1 @@ -146,6 +147,36 @@ typedef enum { EEPROM_ADC_SCALES, EEPROM_UART1_RX_INV, + /* Period values for tasks */ + EEPROM_PERIOD_SYSTEM, + EEPROM_PERIOD_GYROPID, + EEPROM_PERIOD_ACCELEROMETER, + EEPROM_PERIOD_ATTITUDE, + EEPROM_PERIOD_RX, + EEPROM_PERIOD_RX_CLI, + EEPROM_PERIOD_SERIAL, + EEPROM_PERIOD_BATTERY, +#ifdef BARO + EEPROM_PERIOD_BARO, +#endif +#ifdef COMPASS + EEPROM_PERIOD_COMPASS, +#endif +#ifdef GPS + EEPROM_PERIOD_GPS, +#endif +#ifdef SONAR + EEPROM_PERIOD_SONAR, +#endif +#if defined(BARO) || defined(SONAR) + EEPROM_PERIOD_ALTITUDE, +#endif +#if BEEPER + EEPROM_PERIOD_BEEPER +#endif + + + /* Counts the amount of system settings */ EEPROM_SYS_COUNT } EEPROM_SYS_ID_t; @@ -199,6 +230,13 @@ void setActiveProfile(ACTIVE_PROFILE profile); ***********************************************************************/ void resetEEPROM(void); +/*********************************************************************** +* BRIEF: Erases the eeprom and reboots * +* INFORMATION: Erases the eeprom sector and reboots the system so that * +* the default values set in the code will replace the values. * +***********************************************************************/ +void defaultEEPROM(void); + /*********************************************************************** * BRIEF: Gets the address of a value from an id * * INFORMATION: Gets the address of a dataPtr based on a given ID. @@ -207,4 +245,10 @@ void resetEEPROM(void); ***********************************************************************/ void * getDataAddresFromID(uint16_t id, uint8_t dataType); +/*********************************************************************** +* BRIEF: Gets the current profile value * +* INFORMATION: Will return a simple int value of the active profile * +***********************************************************************/ +int getActiveProfile(); + #endif /* CONFIG_EEPROM_H_ */ diff --git a/UAV-ControlSystem/inc/stm32f4xx_revo.h b/UAV-ControlSystem/inc/stm32f4xx_revo.h index 4b8f061..afca423 100644 --- a/UAV-ControlSystem/inc/stm32f4xx_revo.h +++ b/UAV-ControlSystem/inc/stm32f4xx_revo.h @@ -132,19 +132,21 @@ //#define USE_DEBUG_TASKS //Only to be used when testing scheduler, not when intending to run the whole system #define USE_TASK_AGE_CYCLE_STATISTICS +/* EEPROM */ +//#define USE_DEBUG_EEPROM /* Baro */ -//#define BARO +#define BARO #define MPU6000_NSS_PIN GPIO_PIN_4 #define MPU6000_NSS_PORT GPIOA /* Compass */ -//#define COMPASS +#define COMPASS /* GPS */ -//#define GPS +#define GPS /* Sonar */ diff --git a/UAV-ControlSystem/inc/utilities.h b/UAV-ControlSystem/inc/utilities.h index 266b568..26fdf58 100644 --- a/UAV-ControlSystem/inc/utilities.h +++ b/UAV-ControlSystem/inc/utilities.h @@ -23,6 +23,51 @@ #include #include "stm32f4xx_it.h" +#define maxStringSize_CLI 100 //Max sting size used for the messages in the CLI + +typedef char typeString[maxStringSize_CLI]; +typedef struct typeStringArr { char val[maxStringSize_CLI]; } typeStringArr; + +/*********************************************************************** +* BRIEF: Calculates the length of a string(char[]) +* INFORMATION: Calculates the number of characters in a char arr +***********************************************************************/ +uint16_t calculateStringLength (const char * src, int maxSize); + +/*********************************************************************** +* BRIEF: Gives the length of a typestring * +* INFORMATION: Calculates the number of characters in a typestring. * +* Essentially it calculates the number of strings in an * +* string array. * +***********************************************************************/ +uint32_t calculateTypeStringLength(typeString arr[], int maxSize); + +/*********************************************************************** +* BRIEF: Checks if a string consists of numbers +* INFORMATION: Given a string of numbers it will check if it is a number +* by comparing to the ascii table +***********************************************************************/ +bool isStringNumbers(char * msg); + +/*********************************************************************** +* BRIEF: Parses a string of numbers to int +* INFORMATION: Parses a string of numbers to a 64-bit integer. +***********************************************************************/ +uint64_t parseToInt64(char * msg); + +/*********************************************************************** +* BRIEF: Tries to split a string on whitespace +* INFORMATION: Splits a string on whitespace and places it in dst +***********************************************************************/ +bool splitStringWhitespace(char * src, typeString dst[], uint16_t stringSize, uint16_t arraySize); + +/*********************************************************************** +* BRIEF: Finds previous whitespace in a string +* INFORMATION: Given a string and start index it will try to find +* one whitespace counting downwards. +***********************************************************************/ +int FindPreviousWhiteSpaceIndex(char * msg, int startIndex); + /*********************************************************************** * BRIEF: Sums elements of array until index of second arg * * INFORMATION: Returns the sum * diff --git a/UAV-ControlSystem/src/Scheduler/scheduler.c b/UAV-ControlSystem/src/Scheduler/scheduler.c index ff3b743..c85e195 100644 --- a/UAV-ControlSystem/src/Scheduler/scheduler.c +++ b/UAV-ControlSystem/src/Scheduler/scheduler.c @@ -19,7 +19,6 @@ * * ***************************************************************************/ -#include "stm32f4xx_revo.h" #include "Scheduler/scheduler.h" #include "Scheduler/tasks.h" #include "drivers/system_clock.h" @@ -333,6 +332,8 @@ void initSchedulerTasks(void) enableTask(TASK_RX, true); + enableTask(TASK_RX_CLI, true); + enableTask(TASK_SERIAL, true); enableTask(TASK_BATTERY, true); diff --git a/UAV-ControlSystem/src/Scheduler/tasks.c b/UAV-ControlSystem/src/Scheduler/tasks.c index a08cda0..46c2a42 100644 --- a/UAV-ControlSystem/src/Scheduler/tasks.c +++ b/UAV-ControlSystem/src/Scheduler/tasks.c @@ -75,6 +75,15 @@ task_t SystemTasks[TASK_COUNT] = .staticPriority = PRIORITY_HIGH, }, + [TASK_RX_CLI] = + { + .taskName = "RXCLI", + .taskFunction = systemTaskRxCli, //Event handler function, will check if a message is obtainable + .checkEventTriggered = systemTaskRxCliCheck, + .desiredPeriod = GetUpdateRateHz(50), //Standard scheduling should not be used if event based, used as fail safe + .staticPriority = PRIORITY_HIGH, + }, + [TASK_SERIAL] = { .taskName = "SERIAL", diff --git a/UAV-ControlSystem/src/config/cli.c b/UAV-ControlSystem/src/config/cli.c index 0fc106d..f3c94af 100644 --- a/UAV-ControlSystem/src/config/cli.c +++ b/UAV-ControlSystem/src/config/cli.c @@ -1,40 +1,60 @@ -/* - * cli.c - * - * Created on: 30 sep. 2016 - * Author: holmis - */ + /********************************************************************** + * NAME: cli.c * + * AUTHOR: Jonas Holmberg * + * PURPOSE: Provide the ability to change some values by use of * + * command line interface. * + * INFORMATION: By some predefined commands values can be changed in * + * the system by writing in a serial communication * + * terminal that runs on usart. It also has the ability * + * to save the value changes to EEPROM and reset all * + * values. The system can also be reseted and rebooted. * + * * + * GLOBAL VARIABLES: * + * Variable Type Description * + * -------- ---- ----------- * + * cliUsart Usart_profile The handler to the usart used by the cli* * + **********************************************************************/ #include "config/cli.h" #include "stdint.h" #include "config/eeprom.h" +#include "stm32f4xx_revo.h" #include #include +#include "utilities.h" -#define commandValueError 0xFFFFFFFFFFFFFFFF +#define cliActivateCharacter 35 +#define commandValueError 0xFFFFFFFFFFFFFFFF -#define maxStringSize 80 //Max sting size used for the messages -#define msgArraySize 3 //The number of words that a max command can contain (ex: set looptime 1000) +#define minSimilarCharacters 2 //the minimum amount of characters needed to to a search on a value +#define maxSimilarSearchValues 15 //max amount of values that will be found when doing a search for similar strings based on the written chars +#define CLI_baudRate 115200 //The baudrate used for the CLI usart +#define msgArraySize 3 //The number of words that a max command can contain (ex: set looptime 1000) -#define commandSize_1 1 -#define commandSize_2 2 -#define commandSize_3 3 -#define commandSizeOffset msgArraySize -#define commandSize(x) 1 << (x-1) -#define commandMask(x, y) (commandSize(x) | (1 << (commandSizeOffset + y))) +#define commandSize_1 1 //A command with a size of 1 +#define commandSize_2 2 //A command with a size of 2 +#define commandSize_3 3 //A command with a size of 3 +#define commandSizeOffset msgArraySize +#define commandSize(x) 1 << (x-1) +#define commandMask(x, y) (commandSize(x) | (1 << (commandSizeOffset + y))) //macro used to to mask a size of a command and the command ID +#define arrayPos_Action 0 //Command msg array position values: action +#define arrayPos_Command 1 //Command msg array position values: command +#define arrayPos_Value 2 //Command msg array position values: value -#define arrayPos_Action 0 //Command msg array position values: action -#define arrayPos_Command 1 //Command msg array position values: command -#define arrayPos_Value 2 //Command msg array position values: value -typedef char typeString[maxStringSize]; -typedef struct typeStringArr { char val[maxStringSize]; } typeStringArr; +//the handler to the usart profile +usart_profile cliUsart; bool cliIsRunning = false; //Flag to tell if it is running bool valueChanged = false; //Flag that keeps track on if any value has changed and not been saved + +//ToDo: currently not implemented, fix if needed. Could be used to force reboot if a certain value has changed bool rebootSystemNeeded = false; //Flag that signifies that a value was changed that require the system to reboot +//ToDo: used for testing REMOVE +uint8_t pid_pitch_pk = 0; + /* ID values for the ACTIONS that CLI can perform */ typedef enum { @@ -45,10 +65,13 @@ typedef enum ACTION_HELP, //Get information on how the cli works ACTION_GET_INFORMATION, //Get information in a specific value ACTION_COMMANDS, //Get information on all the specific commands - ACTION_PROFILE, + ACTION_PROFILE, //Set the active eeprom profile + ACTION_EXIT, //Exists the cli + ACTION_REBOOT, //Reboots the entire system + ACTION_RESET, //Resets the entire eeprom //The number of actions - ACTION_COUNT, + ACTION_COUNT, //Count of the number of actions ACTION_NOACTION //Not an legit action }commandAction_t; @@ -62,18 +85,40 @@ const typeString commandAction_Strings[ACTION_COUNT] = { "help", "information", "commands", - "profile" + "profile", + "exit", + "reboot", + "reset" }; +/* String values descrbing information of a certain action */ const typeString commandActionInformation_Strings[ACTION_COUNT] = { - "set - Updates value for given variable.\n\r", - "dump - Gives the current information for all values.\n\r", - "save - Writes all the changes to the EEPROM.\n\r", - "undo - Undo all the unsaved changes by loading the stored values.\n\r", - "help - Gives information on how to use the CLI.\n\r", - "information - Provides information on a given value.\n\r", - "commands - Provides information on the available commands.\n\r", - "profile - Changes the active profile between the values (1-3).\n\r" + "| set - Updates value for given variable.\n\r", + "| dump - Gives the current information for all values.\n\r", + "| save - Writes all the changes to the EEPROM.\n\r", + "| undo - Undo all the unsaved changes by loading the stored values.\n\r", + "| help - Gives information on how to use the CLI.\n\r", + "| information - Provides information on a given value.\n\r", + "| commands - Provides information on the available commands.\n\r", + "| profile - Changes the active profile between the values (1-3).\n\r", + "| exit - Exits the CLI mode.\n\r", + "| reboot - Exit CLI and reboots the system.\n\r", + "| reset - Restore all the values to its default values-\n\r" +}; + +/* String array containing all the signature examples for each action */ +const typeString commandActionSignature_Strings[ACTION_COUNT] = { + " set example_value number", + " dump", + " save", + " undo", + " help", + " information example_value", + " commands", + " profile number", + " exit", + " reboot", + " reset" }; /* Size values for the values a command will require */ @@ -89,16 +134,58 @@ typedef enum VAL_INT_64 }valueTypes_t; +/* ID values for individual command, all commands must have a uniqe ID value */ +typedef enum +{ + COMMAND_ID_ADC_SCALES_VCC, + COMMAND_ID_ADC_SCALES_LEFT, + COMMAND_ID_ADC_SCALES_RIGHT, + COMMAND_ID_PID_ROLL_KP, + /* Period values for tasks */ + COMMAND_ID_PERIOD_SYSTEM , + COMMAND_ID_PERIOD_GYROPID, + COMMAND_ID_PERIOD_ACCELERMETER, + COMMAND_ID_PERIOD_ATTITUDE, + COMMAND_ID_PERIOD_RX, + COMMAND_ID_PERIOD_RX_CLI, + COMMAND_ID_PERIOD_SERIAL, + COMMAND_ID_PERIOD_BATTERY, +#ifdef BARO + COMMAND_ID_PERIOD_BARO, +#endif +#ifdef COMPASS + COMMAND_ID_PERIOD_COMPASS, +#endif +#ifdef GPS + COMMAND_ID_PERIOD_GPS, +#endif +#ifdef SONAR + COMMAND_ID_PERIOD_SONAR, +#endif +#if defined(BARO) || defined(SONAR) + COMMAND_ID_PERIOD_ALTITUDE, +#endif +#if BEEPER + COMMAND_ID_PERIOD_BEEPER, +#endif + + COMMAND_ID_COUNT, + + COMMAND_ID_NO_COMMAND +}command_Ids_t; + +/* Struct used to contain min and max values */ typedef struct { uint32_t min; uint32_t max; }minMaxVal_t; +/* Struct containing all the data needed to create a CLI command */ typedef struct { - const char * name; //The name of the command + const char * name; //The name of the command uint16_t commandId; //The id of the command, must be uniqe uint16_t valueId; //The id of the value to change, given from the enum in EEPROM.h: uint16_t valueIdLoc; //If it is part of system values, profile values, etc... @@ -108,20 +195,8 @@ typedef struct }cliCommandConfig_t; -typedef enum -{ - COMMAND_ID_ADC_SCALES_VCC, - COMMAND_ID_ADC_SCALES_LEFT, - COMMAND_ID_ADC_SCALES_RIGHT, - - COMMAND_ID_COUNT, - - COMMAND_ID_NO_COMMAND -}command_Ids_t; - -//CommandId start at 1, 0 is and error value -/* expected signature of command: (OPERATON DATA VALUE) */ +/* Array containing all the commands that exist in the CLI, every single comand is defined here */ const cliCommandConfig_t commandTable[COMMAND_ID_COUNT] = { [COMMAND_ID_ADC_SCALES_VCC] = @@ -136,27 +211,250 @@ const cliCommandConfig_t commandTable[COMMAND_ID_COUNT] = { { "adc_scales_right", COMMAND_ID_ADC_SCALES_RIGHT, EEPROM_ADC_SCALES, EEPROM_VALUE_TYPE_SYSTEM, 8, VAL_UINT_32, .valueRange = {0, 200} }, + [COMMAND_ID_PID_ROLL_KP] = + { + "pid_roll_kp", COMMAND_ID_PID_ROLL_KP, EEPROM_PID_ROLL_KP, EEPROM_VALUE_TYPE_PROFILE, 0, VAL_UINT_8, .valueRange = {0, 100} + }, + [COMMAND_ID_PERIOD_SYSTEM] = + { + "task_period_system", COMMAND_ID_PERIOD_SYSTEM, EEPROM_PERIOD_SYSTEM, EEPROM_VALUE_TYPE_SYSTEM, 0, VAL_UINT_32, .valueRange = {0, 1000000000} + }, + [COMMAND_ID_PERIOD_GYROPID] = + { + "task_period_gyropid", COMMAND_ID_PERIOD_GYROPID, EEPROM_PERIOD_GYROPID, EEPROM_VALUE_TYPE_SYSTEM, 0, VAL_UINT_32, .valueRange = {0, 1000000000} + }, + [COMMAND_ID_PERIOD_ACCELERMETER] = + { + "task_period_accelerometer", COMMAND_ID_PERIOD_ACCELERMETER, EEPROM_PERIOD_ACCELEROMETER, EEPROM_VALUE_TYPE_SYSTEM, 0, VAL_UINT_32, .valueRange = {0, 1000000000} + }, + [COMMAND_ID_PERIOD_ATTITUDE] = + { + "task_period_attitude", COMMAND_ID_PERIOD_ATTITUDE, EEPROM_PERIOD_ATTITUDE, EEPROM_VALUE_TYPE_SYSTEM, 0, VAL_UINT_32, .valueRange = {0, 1000000000} + }, + [COMMAND_ID_PERIOD_RX] = + { + "task_period_rx", COMMAND_ID_PERIOD_RX, EEPROM_PERIOD_RX, EEPROM_VALUE_TYPE_SYSTEM, 0, VAL_UINT_32, .valueRange = {0, 1000000000} + }, + [COMMAND_ID_PERIOD_RX_CLI] = + { + "task_period_rx_cli", COMMAND_ID_PERIOD_RX_CLI, EEPROM_PERIOD_RX_CLI, EEPROM_VALUE_TYPE_SYSTEM, 0, VAL_UINT_32, .valueRange = {0, 1000000000} + }, + [COMMAND_ID_PERIOD_SERIAL] = + { + "task_period_serial", COMMAND_ID_PERIOD_SERIAL, EEPROM_PERIOD_SERIAL, EEPROM_VALUE_TYPE_SYSTEM, 0, VAL_UINT_32, .valueRange = {0, 1000000000} + }, + [COMMAND_ID_PERIOD_BATTERY] = + { + "task_period_battery", COMMAND_ID_PERIOD_BATTERY, EEPROM_PERIOD_BATTERY, EEPROM_VALUE_TYPE_SYSTEM, 0, VAL_UINT_32, .valueRange = {0, 1000000000} + }, +#ifdef BARO + [COMMAND_ID_PERIOD_BARO] = + { + "task_period_baro", COMMAND_ID_PERIOD_BARO, EEPROM_PERIOD_BARO, EEPROM_VALUE_TYPE_SYSTEM, 0, VAL_UINT_32, .valueRange = {0, 1000000000} + }, +#endif +#ifdef COMPASS + [COMMAND_ID_PERIOD_COMPASS] = + { + "task_period_compass", COMMAND_ID_PERIOD_COMPASS, EEPROM_PERIOD_COMPASS, EEPROM_VALUE_TYPE_SYSTEM, 0, VAL_UINT_32, .valueRange = {0, 1000000000} + }, +#endif +#ifdef GPS + [COMMAND_ID_PERIOD_GPS] = + { + "task_period_gps", COMMAND_ID_PERIOD_GPS, EEPROM_PERIOD_GPS, EEPROM_VALUE_TYPE_SYSTEM, 0, VAL_UINT_32, .valueRange = {0, 1000000000} + }, +#endif +#ifdef SONAR + [COMMAND_ID_PERIOD_SONAR] = + { + "task_period_sonar", COMMAND_ID_PERIOD_SONAR, EEPROM_PERIOD_SONAR, EEPROM_VALUE_TYPE_SYSTEM, 0, VAL_UINT_32, .valueRange = {0, 1000000000} + }, +#endif +#if defined(BARO) || defined(SONAR) + [COMMAND_ID_PERIOD_ALTITUDE] = + { + "task_period_altitude", COMMAND_ID_PERIOD_ALTITUDE, EEPROM_PERIOD_ALTITUDE, EEPROM_VALUE_TYPE_SYSTEM, 0, VAL_UINT_32, .valueRange = {0, 1000000000} + }, +#endif +#if BEEPER + [COMMAND_ID_PERIOD_BEEPER] = + { + "task_period_beeper", COMMAND_ID_PERIOD_BEEPER, EEPROM_PERIOD_BEEPER, EEPROM_VALUE_TYPE_SYSTEM, 0, VAL_UINT_32, .valueRange = {0, 1000000000} + }, +#endif }; -void findSimilarCommands(char * msg) +/*********************************************************************** +* BRIEF: Initiates the CLI * +* INFORMATION: The function initiates the CLI. To do this it will need * +* a usart that it should receive its commands from. * +***********************************************************************/ +void cliInit(USART_TypeDef* usart) { - uint8_t minSimilarChars = 3; //At least 3 characters need to be similar for this to be considered - uint8_t maxSimilarCommands = 16; - uint16_t similarCommands[maxSimilarCommands]; //Max 16 values can be found to be similar - uint8_t similarCommandsCount = 0; - char localChar[32]; + usart_init(usart, &cliUsart, CLI_baudRate, STOP_BITS_1, PARITY_NONE); +} + +/*********************************************************************** +* BRIEF: Function that checks if the CLI asigned usart has a new * +* message that can be read. * +* INFORMATION: If there is a new message in the designated usart the * +* function will return true, otherwise false. * +***********************************************************************/ +bool cliHasMessage() +{ + return usart_poll_data_ready(&cliUsart); +} + +/*********************************************************************** +* BRIEF: Reads a cahracter from the usart and checks if it * +* is the start character for the CLI. * +* INFORMATION: Will read a character from the usart and compare if it * +* is the character that needs to be read to start the CLI * +***********************************************************************/ +bool cliShouldRun() +{ + uint8_t buffer[1] = {0}; + usart_poll(&cliUsart, buffer, 1, 10); + + //since the message to start cli is "#" we should only read two bytes: (#) and (\r) + if (buffer[0] == cliActivateCharacter) + { + return true; + } + else + { + return false; + } +} + +/*********************************************************************** +* BRIEF: Transmits a message on the usart. * +* INFORMATION: Given a string it will try to send it over usart. * +***********************************************************************/ +void TransmitBack(char msg[maxStringSize_CLI]) +{ + //Transmits one character at a time over the usart + for (int i = 0; i < maxStringSize_CLI && msg[i] != 0; i++) + { + uint8_t toSend = msg[i]; + usart_transmit(&cliUsart, &toSend, 1, 100); + } +} + +/*********************************************************************** +* BRIEF: Given a string searches for all ACTIONS that start with * +* the same string. * +* INFORMATION: Given a string it will search through all ACTIONS in * +* to see if any of them match the given message. It will * +* search the from the start of each string to check with * +* the length of the input message. * +***********************************************************************/ +void findSimilarActions(char msg[maxStringSize_CLI], typeString similarCommands[maxSimilarSearchValues]) +{ + uint16_t similarCommandsCount = 0; //Number of similar commands found + uint16_t msgCharLength = calculateStringLength(msg, maxStringSize_CLI); //Length of the message to search on //Loop through the commandTable or until similar commands is full - for (int i = 0; i < COMMAND_ID_COUNT && similarCommandsCount <= maxSimilarCommands; i++) + for (int i = 0; i < ACTION_COUNT && similarCommandsCount <= maxSimilarSearchValues; i++) { + //If the length of the search value is greater than the one we want to compare it cant be that one + if(msgCharLength > calculateStringLength(commandAction_Strings[i], maxStringSize_CLI)) + continue; + //Check if the message has any action that is similar to the message + char tempString[maxStringSize_CLI] = {0}; + strncpy (tempString, commandAction_Strings[i], msgCharLength); + if (strcmp(msg, tempString) == 0) + { + //completely reset the current string in the similarComands array + memset(&similarCommands[i][0], 0, maxStringSize_CLI); + + //Copy the string over to the return array + int tempSize = calculateStringLength(commandAction_Strings[i], maxStringSize_CLI); + strncpy(similarCommands[similarCommandsCount], commandAction_Strings[i], tempSize); + similarCommandsCount++; + } } } -uint8_t getCommandAction(char msg[maxStringSize]) +/*********************************************************************** +* BRIEF: Given a string searches for all COMMANDS that start with* +* the same string. * +* INFORMATION: Given a string it will search through all COMMANDS in * +* to see if any of them match the given message. It will * +* search the from the start of each string to check with * +* the length of the input message. * +***********************************************************************/ +void findSimilarCommands(const char msg[maxStringSize_CLI], typeString similarCommands[maxSimilarSearchValues]) { + uint16_t similarCommandsCount = 0; //Number of similar commands found + uint16_t msgCharLength = calculateStringLength(msg, maxStringSize_CLI); //Length of the message to search on + if (msgCharLength < minSimilarCharacters) + return; + + //Loop through the commandTable or until similar commands is full + for (int i = 0; i < COMMAND_ID_COUNT && similarCommandsCount < maxSimilarSearchValues; i++) + { + //If the length of the search value is greater than the one we want to compare it cant be that one + if(msgCharLength > calculateStringLength(commandTable[i].name, maxStringSize_CLI)) + continue; + + //Check if the message has any action that is similar to the message + char tempString[maxStringSize_CLI] = {0}; + strncpy (tempString, commandTable[i].name, msgCharLength); + if (strcmp(msg, tempString) == 0) + { + //completely reset the current string in the similarComands array + memset(&similarCommands[similarCommandsCount][0], 0, maxStringSize_CLI); + + //Copy the string over to the return array + int tempSize = calculateStringLength(commandTable[i].name, maxStringSize_CLI); + strncpy(similarCommands[similarCommandsCount], commandTable[i].name, tempSize); + similarCommandsCount++; + } + } + +} + +/*********************************************************************** +* BRIEF: Finds possible commands given a message and transmits * +* them over usart. * +* INFORMATION: Given a certain message similar commands will be found. * +* If any are found they will be transmitted over the usart* +***********************************************************************/ +void TransmitPossibleSimilarCommands(char * msg, int minCharAmount) +{ + char msgToCheck[maxStringSize_CLI]; + typeString similarCommands[maxSimilarSearchValues]; + int msgLength = calculateStringLength(msg, maxStringSize_CLI); //Calculate the length of the message + + if (msgLength < minCharAmount) //Check if the given message is longer than the amount of characters we want ot compare with + return; + + strncpy (msgToCheck, msg, minCharAmount); //Copy the characters we want to compare with + findSimilarCommands(msgToCheck, similarCommands); //get all the similar commands based on the text we send in + int similarCount = calculateTypeStringLength(similarCommands, maxSimilarSearchValues); //Get the count of the amount of similar values + + TransmitBack("- Possible commands: \n\r"); + for (int i = 0; i < similarCount; i++) //loop through all the values + { + char buffer[maxStringSize_CLI]; + sprintf(buffer,"-- %s \n\r", similarCommands[i]); + TransmitBack(buffer); + } + TransmitBack("---------------------------------\n\n\r"); +} + +/*********************************************************************** +* BRIEF: Tries to get the ID of the action. +* INFORMATION: Given a string of an action it tries to match it to an +* action ID. +***********************************************************************/ +uint8_t getCommandAction(char msg[maxStringSize_CLI]) +{ for (int i = 0; i < ACTION_COUNT; i++) { if (strcmp(msg, commandAction_Strings[i]) == 0) @@ -164,11 +462,14 @@ uint8_t getCommandAction(char msg[maxStringSize]) return i; } } - - return ACTION_NOACTION; } +/*********************************************************************** +* BRIEF: Tries to get the id of a command * +* INFORMATION: Given a string of an command it tries to match it to a * +* command id * +***********************************************************************/ uint16_t getCommandId(char * msg) { for (int i = 0; i < COMMAND_ID_COUNT; i++) @@ -178,77 +479,13 @@ uint16_t getCommandId(char * msg) return commandTable[i].commandId; } } - return COMMAND_ID_NO_COMMAND; } -bool isStringNumbers(char * msg) -{ - char c; - int i = 0; - while(c = msg[i], c != 0) - { - if (c >= 48 && c <= 57) - i++; - else - return false; - } - - return true; -} - -uint64_t parseToInt64(char * msg) -{ - uint64_t toReturn = 0; - uint64_t multiplier = 1; - int i; - - //Count the number of values in the char - for(i = 0; msg[i+1] != 0; i++); - - //iter each value from the back - for (;i >= 0; i--) - { - //switch each number value - switch((uint8_t)msg[i]) - { - case 48: //0 - toReturn = toReturn + 0 * multiplier; - break; - case 49: //1 - toReturn = toReturn + 1 * multiplier; - break; - case 50: //2 - toReturn = toReturn + 2 * multiplier; - break; - case 51: //3 - toReturn = toReturn + 3 * multiplier; - break; - case 52: //4 - toReturn = toReturn + 4 * multiplier; - break; - case 53: //5 - toReturn = toReturn + 5 * multiplier; - break; - case 54: //6 - toReturn = toReturn + 6 * multiplier; - break; - case 55: //7 - toReturn = toReturn + 7 * multiplier; - break; - case 56: //8 - toReturn = toReturn + 8 * multiplier; - break; - case 57: //9 - toReturn = toReturn + 9 * multiplier; - break; - } - multiplier = multiplier * 10; - } - - return toReturn; -} - +/*********************************************************************** +* BRIEF: Parses a string into a value. +* INFORMATION: Parses a string into a value and returns it +***********************************************************************/ uint64_t getCommanValue(char * msg) { //Check if the msg are only valid numbers (0-9). If they are not retun max value of 64 bit int that will serve as an error @@ -256,17 +493,24 @@ uint64_t getCommanValue(char * msg) { return commandValueError; } - return parseToInt64(msg); } - +/*********************************************************************** +* BRIEF: Tries to process a command to set a value +* INFORMATION: Tries to set the process a set command. Given and +* action and command ID and a numerical value. It will +* check what value the action wants to change checks if it +* is within the given range and if it is it will change it +***********************************************************************/ bool processCommand(uint8_t action, uint16_t id, uint64_t value) { //check if value is within the allowed area, if not return if ( !(value >= commandTable[id].valueRange.min && value <= commandTable[id].valueRange.max) ) { - //usart_send("Value not within ranges: %d - %d", commandTable[id].valueRange.min, commandTable[id].valueRange.max); + char buffer[maxStringSize_CLI]; + sprintf(buffer,"Value not within ranges: %d - %d", (int)commandTable[id].valueRange.min, (int)commandTable[id].valueRange.max); + TransmitBack(buffer); return false; } @@ -305,110 +549,227 @@ bool processCommand(uint8_t action, uint16_t id, uint64_t value) break; } - return true; } -uint16_t calculateStringLength (char * src, int maxSize) +/*********************************************************************** +* BRIEF: Will loop and read input from serial. +* INFORMATION: Will read input for the serial in a loop and will add +* everything read into a string and also display it in +* terminal by transmitting what is read back. The loop +* will break when a enter has been read, this equals the +* end of a command. This string will be saved in msg and +* can be used afterwards to identify if a valid command +* has been received. +***********************************************************************/ +void ReceiveCommand(char msg[maxStringSize_CLI], int msgSize) { - uint16_t toReturn = 0; - for(int i = 0; src[i] != 0 ; i++) + //loop until enter or end of msgsize + uint8_t c = 0; + uint8_t c_blank = 32; + char esteticString[3] = "#: "; + uint8_t c_backspace= 8; + uint32_t readBytes = 0; + typeString suggestionsArr[maxSimilarSearchValues] = {0}; //Maximum of 10 suggestions can be stored + int suggestionAmount = 0; + int suggestedCounter = 0; + int lastSpaceIndex = 0; + bool suggestNew = true; + int counter = 0; + + //The last char in the final message must always be and \r + msg[msgSize-1] = '\r'; + + //add estetic part to the write + TransmitBack(esteticString); + + //Loop untill we are done or our max message have been received + while(counter < msgSize-1) { - toReturn ++; - } - return toReturn; -} + //Will loop and try to read something until it has read something + while(readBytes = usart_poll(&cliUsart, &c, 1, 10000), readBytes <= 0); -uint32_t calculateArrayArrayLength(typeString arr[], int maxSize) -{ - int i = 0; - - for(i = 0; i < maxSize && arr[i][0] != 0; i++); - - return i; -} - -bool splitStringWhitespace(char * src, typeString dst[], uint16_t stringSize, uint16_t arraySize) -{ - - char currentChar; - uint32_t iterator = 0; //iterates through the string - uint32_t arrayIterator = 0; //iterates through the array positioning - uint32_t arrayStringIterator = 0; //iterates through the string inside the array - //Loop through the values in src, until we find \r(enter) or null - while(currentChar = src[iterator], currentChar != '\r' && currentChar != 0 ) - { - //check if whitespace - if (currentChar == ' ') + //if an enter(\r) has been read the message is considered complete + if (c == '\r') { - //increase the array iterator - arrayIterator ++; - if (arrayIterator >= arraySize) //check that its not to large + msg[counter] = c; //Add the read value to the out value + TransmitBack("\r>>>"); //Show in terminal that was written was a previous command and it is marked by this transmit + break; + } + if (c == '\b') //backspace + { + if (counter <= 0) + continue; + + //Decrease the counter since we remove + counter --; + + //If we use suggest new it needs to check again next time + suggestNew = true; + + //Check if a blank space is being erased and the find the last one + if (msg[counter] == ' ') { - //usart_send("To many words in the command"); - return false; + int tempVal = FindPreviousWhiteSpaceIndex(msg,counter-1); + lastSpaceIndex = (tempVal == 0) ? 0 : tempVal+1; } - arrayStringIterator = 0; - goto increment; //continue to the next iteration, with a goto the increment - } + //set the value for this counter to null since it should be nothing, meaning we erase it + msg[counter] = 0; - dst[arrayIterator][arrayStringIterator] = src[iterator]; //set the char to the correct array position - arrayStringIterator ++; - if (arrayStringIterator >=stringSize) + //special transmit back that removes one displayed character so it looks correct + usart_transmit(&cliUsart, &c, 1, 1000000000); + usart_transmit(&cliUsart, &c_blank, 1, 100000000); + usart_transmit(&cliUsart, &c, 1, 1000000000); + } + else if (c == 9) //Tabb was pressed, should try and find a value for the imputed text { - return false; + //This part works, next fucks it up + if (suggestNew == true) + { + //Reset suggestion array with 0 at the start + for (int i = 0; i < maxSimilarSearchValues; i++) + suggestionsArr[i][0] = 0; + + //if we are at the start and have not written anything switch on the possible actions + if (lastSpaceIndex == 0) + { + //find similar actions + findSimilarActions(msg, suggestionsArr); + } + else + { + //find similar commands + findSimilarCommands(msg+lastSpaceIndex, suggestionsArr); + } + suggestionAmount = calculateTypeStringLength(suggestionsArr,maxSimilarSearchValues); + suggestNew = false; + suggestedCounter = 0; + } + if (suggestNew == false && suggestionAmount > 0) + { + //Get the length of the current message shown in the terminal + int tempMsgSize = calculateStringLength(msg+lastSpaceIndex, maxStringSize_CLI); + int totMsgSize = calculateStringLength(msg, maxStringSize_CLI); + int i_stop = totMsgSize - tempMsgSize; + + //Erase what is shown in the terminal right now + for (int i = totMsgSize; i > 0; i--) + { + usart_transmit(&cliUsart, &c_backspace, 1, 1000000000); + usart_transmit(&cliUsart, &c_blank, 1, 100000000); + usart_transmit(&cliUsart, &c_backspace, 1, 1000000000); + + if (i > i_stop) + msg[i-1] = 0; + } + + //Get the length of the suggested string + int suggestionStringLength = calculateStringLength(suggestionsArr[suggestedCounter], maxStringSize_CLI); + + //Add the suggested string to the end of the read message, also increase the counter + strncpy (msg+lastSpaceIndex, suggestionsArr[suggestedCounter], suggestionStringLength); + counter = calculateStringLength(msg, maxStringSize_CLI); + + //Show the updated message + TransmitBack(msg); + suggestedCounter = (suggestedCounter+1 < suggestionAmount) ? suggestedCounter + 1 : 0; + + } + } + else //standard, just some key was sent + { + //check if it is a apace then set last space counter + if (c == ' ') + lastSpaceIndex = counter+1; + + //If we use suggest new it needs to check again next time + suggestNew = true; + + msg[counter] = c; //Add the read value to the out value + usart_transmit(&cliUsart, &c, 1, 100); //Send the read message back to display in the terminal + counter ++; //Increment counter } - //Goto statement to jump to the incrementation -increment: - iterator ++; //increment iterator + HAL_Delay(1); } - return true; + //add a new line every time + TransmitBack("\n\n\r"); } +/*********************************************************************** +* BRIEF: Get a binary decision from serial +* INFORMATION: Will perform a binary decision based on the on and off +* input parameters. If on is read true will be returned if +* off is read false will be returned. This values are +* numbers in the ascii table. The function will read from +* serial until one of the values for on or off has been +* read. +***********************************************************************/ +bool ReceiveBinaryDecision(uint8_t on, uint8_t off) +{ + uint8_t c; + uint32_t readBytes = 0; + + while(true) + { + //Read until either on or off have been read from the serial + while(readBytes = usart_poll(&cliUsart, &c, 1, 10000), readBytes <= 0); + + if (c == on) + return true; + else if (c == off) + return false; + } +} + +/*********************************************************************** +* BRIEF: Transmits the signature of a command +* INFORMATION: Transmits over usart the signature how to write a +* specific command id. +***********************************************************************/ +void TransmitCommandInstruction(uint8_t id) +{ + TransmitBack("- The signature for "); + TransmitBack(commandAction_Strings[id]); + TransmitBack(" is: '"); + TransmitBack(commandActionSignature_Strings[id]); + TransmitBack("'...\n\r"); +} + +/*********************************************************************** +* BRIEF: Writes the value of a that a command is associated with. +* INFORMATION: Given a command id it will display information about +* the values that the command manipulates. +***********************************************************************/ void writeTaskInformation(uint16_t id) { - /* + //buffer + char buffer[maxStringSize_CLI]; + //Get the correct pointer to the data void * valuePointer = getDataAddresFromID(commandTable[id].valueId, commandTable[id].valueIdLoc); //adjust to the correct addres with the offset valuePointer += commandTable[id].addressValueOffset; - switch(commandTable[id].valueType) - { - case VAL_UINT_8: - usart_send("%s - Value: %d, allowed range: %d - %d\n\r", commandTable[id].name, *((uint8_t *)valuePointer), commandTable[id].valueRange.min, commandTable[id].valueRange.min); - break; - case VAL_INT_8: - usart_send("%s - Value: %d, allowed range: %d - %d\n\r", commandTable[id].name, *((int8_t *)valuePointer), commandTable[id].valueRange.min, commandTable[id].valueRange.min); - break; - case VAL_UINT_16: - usart_send("%s - Value: %d, allowed range: %d - %d\n\r", commandTable[id].name, *((uint16_t *)valuePointer), commandTable[id].valueRange.min, commandTable[id].valueRange.min); - break; - case VAL_INT_16: - usart_send("%s - Value: %d, allowed range: %d - %d\n\r", commandTable[id].name, *((int16_t *)valuePointer), commandTable[id].valueRange.min, commandTable[id].valueRange.min); - break; - case VAL_UINT_32: - usart_send("%s - Value: %d, allowed range: %d - %d\n\r", commandTable[id].name, *((uint32_t *)valuePointer), commandTable[id].valueRange.min, commandTable[id].valueRange.min); - break; - case VAL_INT_32: - usart_send("%s - Value: %d, allowed range: %d - %d\n\r", commandTable[id].name, *((int32_t *)valuePointer), commandTable[id].valueRange.min, commandTable[id].valueRange.min); - break; - case VAL_UINT_64: - usart_send("%s - Value: %d, allowed range: %d - %d\n\r", commandTable[id].name, *((uint64_t *)valuePointer), commandTable[id].valueRange.min, commandTable[id].valueRange.min); - break; - case VAL_INT_64: - usart_send("%s - Value: %d, allowed range: %d - %d\n\r", commandTable[id].name, *((int64_t *)valuePointer), commandTable[id].valueRange.min, commandTable[id].valueRange.min); - break; - } - */ + //Formats the string so that it will be printed nicely + sprintf(buffer,"- %-35s Value: %-20d allowed range: %d - %d\n\r", commandTable[id].name, *((int *)valuePointer), (int)commandTable[id].valueRange.min, (int)commandTable[id].valueRange.max); + TransmitBack(buffer); } +/*********************************************************************** +* BRIEF: Will print informations of all the the commands +* INFORMATION: Will loop through all the commands in the system and +* display all their information by calling +* writeTaskInformation. +***********************************************************************/ void dumpTaskInformation() { + char buffer[maxStringSize_CLI]; + sprintf(buffer, "Active profile: %d\n\n\r", getActiveProfile()); + TransmitBack(buffer); for (int i = 0; i < COMMAND_ID_COUNT; i++) { writeTaskInformation(commandTable[i].commandId); @@ -416,44 +777,50 @@ void dumpTaskInformation() //usart_send("----------------------\n\r"); } + +/*********************************************************************** +* BRIEF: The main loop of the cli +* INFORMATION: The main loop of the cli that will read a message and +* thereafter handle it accordingly. +***********************************************************************/ void cliRun() { //set running flag to true, when it should stop it should be set to false cliIsRunning = true; - char * msg; //msg to be read from the usart - //temporary values assigned for testing - //msg = "set adc_scales_left 134\r"; - msg = "commands\r"; + //start message to send that tells we have started CLI + TransmitBack("\n\r- Entered CLI MODE...\n\n\r"); //Will run until it is decided to stop while(cliIsRunning) { - cliIsRunning = false; - //ToDo: add usart reading for the commands - //ToDo: instead of sending the text send id numbers, need to make a custom program that can run on a standard computer for this - //msg = ProcessUsart(); + /* Poll reading of a message until we receive and enter, or message size overflow */ + char msg[maxStringSize_CLI] = {0}; //msg to be read from the usart + ReceiveCommand(msg, maxStringSize_CLI); //split string, first item should be and action, if second item should be id, last if used should be value - /**/ - //typeStringArr msgArr[msgArraySize] = {0}; typeString msgArr[msgArraySize] = {0}; - if (!splitStringWhitespace(msg, msgArr, maxStringSize, msgArraySize)) + if (!splitStringWhitespace(msg, msgArr, maxStringSize_CLI, msgArraySize)) { - //usart_send("Wrong command format"); + TransmitBack("- Wrong command format... \n\n\r"); //Message was invalid do not try to process it continue; } //Get the amount of words in the command - uint32_t msgArrLength = calculateArrayArrayLength(msgArr, msgArraySize); + uint32_t msgArrLength = calculateTypeStringLength(msgArr, msgArraySize); + if(msgArrLength <= 0) + { + TransmitBack("- No command sent... \n\n\r"); + continue; + } uint8_t actionId = getCommandAction(msgArr[arrayPos_Action]); //First check what type of action the command is, gives an id value for the action - uint16_t commandId; //Id for the command - uint64_t commandValue; - bool processSuccessfull; //Bool for if the command was processed successfully + uint16_t commandId; //Id for the command + uint64_t commandValue; //Value of a command + bool processSuccessfull; //Bool for if the command was processed successfully switch (commandMask(msgArrLength, actionId)) { @@ -461,15 +828,17 @@ void cliRun() //Obtain the command id if it is exsits, otherwise produce an error if ((commandId = getCommandId(msgArr[arrayPos_Command])) == COMMAND_ID_NO_COMMAND ) { - //ToDo: add so that suggestions of what could be written instead is sent back - //usart_send("ERROR: No valid command given...\n\r"); + TransmitBack("- ERROR: No valid variable given...\n\n\r"); + + //If the command is close to any other command those will be written back over usart + TransmitPossibleSimilarCommands(msgArr[arrayPos_Command], 3); break; } //Get the value of the command if ((commandValue = getCommanValue(msgArr[arrayPos_Value])) == commandValueError) { - //usart_send("ERROR: The value provided are not numerical...\n\r"); + TransmitBack("- ERROR: The value provided are not numerical...\n\n\r"); break; } @@ -478,72 +847,129 @@ void cliRun() if (processSuccessfull) { //Updated value correctly - //......usart_send("Updated value correctly...\n\r") + TransmitBack("- Updated value correctly...\n\r"); + writeTaskInformation(commandId); + TransmitBack("\n\r"); + valueChanged = true; } else { //could not update value - //......usart_send("Value not updated...\n\r") + TransmitBack("- Value not updated...\n\n\r"); } break; case commandMask(commandSize_1, ACTION_DUMP): //dump informaton for all values that can be accessed in the commandTable + TransmitBack("Value of variables: \n\n\r"); dumpTaskInformation(); + TransmitBack("\n-------------------------------------------------- \n\r"); break; case commandMask(commandSize_1, ACTION_SAVE): //Write all the values that have been changed to the eprom - //writeEEPROM(); + valueChanged = false; + saveEEPROM(); + TransmitBack("- Values successfully saved to EEPROM... \n\n\r"); break; case commandMask(commandSize_1, ACTION_UNDO): //Undp all things that have not been saved by reading the current saved values in the eeprom + valueChanged = false; readEEPROM(); + TransmitBack("- All unsaved values discarded... \n\n\r"); break; case commandMask(commandSize_1, ACTION_HELP): - //usart_send("Updates the values for variables in the system. To get a list of the commands write: commands.\n\r"); + TransmitBack("- Updates the values for variables in the system. To get a list of the commands write: commands.\n\n\r"); break; case commandMask(commandSize_2, ACTION_GET_INFORMATION): if ((commandId = getCommandId(msgArr[arrayPos_Command])) == COMMAND_ID_NO_COMMAND ) { //ToDo: add so that suggestions of what could be written instead is sent back - //usart_send("ERROR: No valid command given...\n\r"); + TransmitBack("- ERROR: No valid variable given...\n\n\r"); break; } writeTaskInformation(commandId); break; case commandMask(commandSize_1, ACTION_COMMANDS): //Gives information on all the tasks - //usart_send("All the commands that can be used: \n\r"); + TransmitBack("- All the commands that can be used: \n\r"); for(int i=0; i < ACTION_COUNT; i++) { - //usart_send(commandActionInformation_Strings[i]); + TransmitBack(commandActionInformation_Strings[i]); } + TransmitBack("------------------------------------ \n\n\r"); break; case commandMask(commandSize_2, ACTION_PROFILE): - //Get the value of the command + //Get the value of the command if ((commandValue = getCommanValue(msgArr[arrayPos_Value-1])) == commandValueError) { - //usart_send("ERROR: The value provided are not numerical...\n\r"); + TransmitBack("- ERROR: The value provided are not numerical...\n\n\r"); break; } //check if the value is within the ranges for possible profiles if (!(commandValue >= 1 && commandValue <=3)) { - //usart_send("ERROR: A profile value must be between 1-3...\n\r"); + TransmitBack("- ERROR: A profile value must be between 1-3...\n\n\r"); } - + valueChanged = false; + setActiveProfile(commandValue); + TransmitBack("- Changed profile... \n\n\r"); break; + case commandMask(commandSize_1, ACTION_EXIT): + + if (valueChanged == true) + { + TransmitBack("- Changes not saved, Want to save changes? (y/n)... \n\n\r"); + + //read until a y or n is found + if (ReceiveBinaryDecision(121, 110)) + { + saveEEPROM(); + TransmitBack("- Values successfully saved to EEPROM... \n\n\r"); + } + } + TransmitBack("- Exiting CLI... \n\n\r"); + cliIsRunning = false; + valueChanged = false; + break; + case commandMask(commandSize_1, ACTION_REBOOT): + if (valueChanged == true) + { + TransmitBack("- Changes not saved, Want to save changes? (y/n)... \n\n\r"); + + //read until a y or n is found + if (ReceiveBinaryDecision(121, 110)) + { + saveEEPROM(); + TransmitBack("- Values successfully saved to EEPROM... \n\n\r"); + } + } + + TransmitBack("- Exiting CLI and Rebooting system...\n\n\r"); + cliIsRunning = false; + HAL_NVIC_SystemReset(); + break; + case commandMask(commandSize_1, ACTION_RESET): + //resets all the values in the eeprom to the default values + TransmitBack("- All values will be deleted and system rebooted. Continue? (y/n)... \n\n\r"); + + //read until a y or n is found + if (ReceiveBinaryDecision(121, 110)) + { + defaultEEPROM(); + } + else + { + TransmitBack("- Values unchanged...\n\n\r"); + } + break; default: - //usart_send("No valid command was provided to the system. \n Type "commands" for information on all the possible commands... \n \n ") - break; + if (actionId != ACTION_NOACTION) + TransmitCommandInstruction(actionId); + TransmitBack("- For valid commands type: 'commands'\n\n\r"); + break; } - - - - } - } diff --git a/UAV-ControlSystem/src/config/eeprom.c b/UAV-ControlSystem/src/config/eeprom.c index 7d92a30..96ec2af 100644 --- a/UAV-ControlSystem/src/config/eeprom.c +++ b/UAV-ControlSystem/src/config/eeprom.c @@ -19,6 +19,8 @@ #include "drivers/uart1_inverter.h" #include "system_variables.h" #include "utilities.h" +#include "stm32f4xx_revo.h" +#include "Scheduler/scheduler.h" /* Reads the EEPROM version from EEPROM - Is compared to EEPROM_SYS_VERSION */ uint8_t stored_eeprom_identifier; @@ -87,9 +89,106 @@ EEPROM_DATA_t eeprom_sys_Arr[EEPROM_SYS_COUNT] = { }, [EEPROM_UART1_RX_INV] = { - .size = sizeof(bool), - .dataPtr = &uart1_rx_inverter, - } + .size = sizeof(bool), + .dataPtr = &uart1_rx_inverter, + }, + + [EEPROM_PERIOD_SYSTEM] = + { + .size = sizeof(SystemTasks[TASK_SYSTEM].desiredPeriod), + .dataPtr = &(SystemTasks[TASK_SYSTEM].desiredPeriod), + }, + + [EEPROM_PERIOD_GYROPID] = + { + .size = sizeof(SystemTasks[TASK_GYROPID].desiredPeriod), + .dataPtr = &(SystemTasks[TASK_GYROPID].desiredPeriod), + }, + + [EEPROM_PERIOD_ACCELEROMETER] = + { + .size = sizeof(SystemTasks[TASK_ACCELEROMETER].desiredPeriod), + .dataPtr = &(SystemTasks[TASK_ACCELEROMETER].desiredPeriod), + }, + + [EEPROM_PERIOD_ATTITUDE] = + { + .size = sizeof(SystemTasks[TASK_ATTITUDE].desiredPeriod), + .dataPtr = &(SystemTasks[TASK_ATTITUDE].desiredPeriod), + }, + + [EEPROM_PERIOD_RX] = + { + .size = sizeof(SystemTasks[TASK_RX].desiredPeriod), + .dataPtr = &(SystemTasks[TASK_RX].desiredPeriod), + }, + + [EEPROM_PERIOD_RX_CLI] = + { + .size = sizeof(SystemTasks[TASK_RX_CLI].desiredPeriod), + .dataPtr = &(SystemTasks[TASK_RX_CLI].desiredPeriod), + }, + + [EEPROM_PERIOD_SERIAL] = + { + .size = sizeof(SystemTasks[TASK_SERIAL].desiredPeriod), + .dataPtr = &(SystemTasks[TASK_SERIAL].desiredPeriod), + }, + + [EEPROM_PERIOD_BATTERY] = + { + .size = sizeof(SystemTasks[TASK_BATTERY].desiredPeriod), + .dataPtr = &(SystemTasks[TASK_BATTERY].desiredPeriod), + }, + +#ifdef BARO + [EEPROM_PERIOD_BARO] = + { + .size = sizeof(SystemTasks[TASK_BARO].desiredPeriod), + .dataPtr = &(SystemTasks[TASK_BARO].desiredPeriod), + }, +#endif +#ifdef COMPASS + [EEPROM_PERIOD_COMPASS] = + { + .size = sizeof(SystemTasks[TASK_COMPASS].desiredPeriod), + .dataPtr = &(SystemTasks[TASK_COMPASS].desiredPeriod), + }, +#endif +#ifdef GPS + [EEPROM_PERIOD_GPS] = + { + .size = sizeof(SystemTasks[TASK_GPS].desiredPeriod), + .dataPtr = &(SystemTasks[TASK_GPS].desiredPeriod), + }, +#endif +#ifdef SONAR + [EEPROM_PERIOD_SONAR] = + { + .size = sizeof(SystemTasks[TASK_SONAR].desiredPeriod), + .dataPtr = &(SystemTasks[TASK_SONAR].desiredPeriod), + }, +#endif +#if defined(BARO) || defined(SONAR) + [EEPROM_PERIOD_ALTITUDE] = + { + .size = sizeof(SystemTasks[TASK_ALTITUDE].desiredPeriod), + .dataPtr = &(SystemTasks[TASK_ALTITUDE].desiredPeriod), + }, +#endif +#if BEEPER + [EEPROM_PERIOD_BEEPER] = + { + .size = sizeof(SystemTasks[TASK_BEEPER].desiredPeriod), + .dataPtr = &(SystemTasks[TASK_BEEPER].desiredPeriod), + }, +#endif + + + + + + }; /* Data pointers and sizes for profile content */ @@ -301,7 +400,11 @@ bool scanEEPROM(void) // ERROR!!! CORRUPT EEPROM, RESETTING calculated_crc = old_crc; + +#ifdef USE_DEBUG_EEPROM Error_Handler(); +#endif + resetEEPROM(); // Reinitialize eeprom with default values. return true /* false */; @@ -443,3 +546,20 @@ void * getDataAddresFromID(uint16_t id, uint8_t dataType) } return toReturn; } + +void defaultEEPROM(void) +{ + //Erase the secotr + HAL_FLASH_Unlock(); + __HAL_FLASH_CLEAR_FLAG(FLASH_FLAG_EOP | FLASH_FLAG_OPERR | FLASH_FLAG_WRPERR | FLASH_FLAG_PGAERR | FLASH_FLAG_PGSERR ); + FLASH_Erase_Sector(EEPROM_SECTOR_ERASE, VOLTAGE_RANGE_3); + HAL_FLASH_Lock(); + + //Reboot the system + HAL_NVIC_SystemReset(); +} + +int getActiveProfile() +{ + return active_profile; +} diff --git a/UAV-ControlSystem/src/main.c b/UAV-ControlSystem/src/main.c index bbc3485..9a35ede 100644 --- a/UAV-ControlSystem/src/main.c +++ b/UAV-ControlSystem/src/main.c @@ -40,6 +40,11 @@ void init_system() //Configure the clock system_clock_config(); + /* read saved variables from eeprom */ + readEEPROM(); + + //initialize the CLI + cliInit(USART1); #ifdef USE_LEDS //Initialize the on board leds @@ -91,6 +96,7 @@ int main(void) //Initialize the scheduler, add all the tasks that should run to the ready queue of the scheduler initScheduler(); + while (1) { //Run the scheduler, responsible for distributing all the work of the running system diff --git a/UAV-ControlSystem/src/tasks_main.c b/UAV-ControlSystem/src/tasks_main.c index b7c7dab..bd21e6e 100644 --- a/UAV-ControlSystem/src/tasks_main.c +++ b/UAV-ControlSystem/src/tasks_main.c @@ -33,6 +33,8 @@ #include "drivers/motors.h" #include "drivers/pwm.h" #include "drivers/system_clock.h" +#include "config/eeprom.h" +#include "config/cli.h" #include "drivers/sbus.h" @@ -45,6 +47,8 @@ void systemTaskGyroPid(void) void systemTaskAccelerometer(void) { //update the accelerometer data + uint8_t c = 97; + usart_transmit(&cliUsart, &c, 1, 1000000000); } void systemTaskAttitude(void) @@ -64,18 +68,38 @@ bool systemTaskRxCheck(uint32_t currentDeltaTime) //This task is what is controlling the event activation of the systemTaskRx //check if there is anything that has be received. - return sbus_frame_available(); } +void systemTaskRxCli(void) +{ + /* Check if CLI should be activated */ + if (cliShouldRun() == true) + cliRun(); +} + +bool systemTaskRxCliCheck(uint32_t currentDeltaTime) +{ + /* First check if any value has been sent to the cli usart. + * We dont care about the delta time for this since if this + * has received something we should always check we dont care about + * the loop times. */ + return cliHasMessage(); + + return false; +} + void systemTaskSerial(void) { - + uint8_t c = 115; + usart_transmit(&cliUsart, &c, 1, 1000000000); } void systemTaskBattery(void) { //Keep track of the battery level of the system + uint8_t c = 98; + usart_transmit(&cliUsart, &c, 1, 1000000000); } void systemTaskBaro(void) diff --git a/UAV-ControlSystem/src/utilities.c b/UAV-ControlSystem/src/utilities.c index 8173165..2e22185 100644 --- a/UAV-ControlSystem/src/utilities.c +++ b/UAV-ControlSystem/src/utilities.c @@ -13,6 +13,173 @@ #include "utilities.h" +/*********************************************************************** +* BRIEF: Calculates the length of a string(char[]) +* INFORMATION: Calculates the number of characters in a char arr +***********************************************************************/ +uint16_t calculateStringLength (const char * src, int maxSize) +{ + uint16_t toReturn = 0; + for(int i = 0; src[i] != 0 ; i++) + { + toReturn ++; + } + return toReturn; +} + +/*********************************************************************** +* BRIEF: Gives the length of a typestring * +* INFORMATION: Calculates the number of characters in a typestring. * +* Essentially it calculates the number of strings in an * +* string array. * +***********************************************************************/ +uint32_t calculateTypeStringLength(typeString arr[], int maxSize) +{ + int i = 0; + + for(i = 0; i < maxSize && arr[i][0] != 0; i++); + + return i; +} + +/*********************************************************************** +* BRIEF: Checks if a string consists of numbers +* INFORMATION: Given a string of numbers it will check if it is a number +* by comparing to the ascii table +***********************************************************************/ +bool isStringNumbers(char * msg) +{ + char c; + int i = 0; + while(c = msg[i], c != 0) + { + if (c >= 48 && c <= 57) + i++; + else + return false; + } + + return true; +} + +/*********************************************************************** +* BRIEF: Parses a string of numbers to int +* INFORMATION: Parses a string of numbers to a 64-bit integer. +***********************************************************************/ +uint64_t parseToInt64(char * msg) +{ + uint64_t toReturn = 0; + uint64_t multiplier = 1; + int i; + + //Count the number of values in the char + for(i = 0; msg[i+1] != 0; i++); + + //iter each value from the back + for (;i >= 0; i--) + { + //switch each number value + switch((uint8_t)msg[i]) + { + case 48: //0 + toReturn = toReturn + 0 * multiplier; + break; + case 49: //1 + toReturn = toReturn + 1 * multiplier; + break; + case 50: //2 + toReturn = toReturn + 2 * multiplier; + break; + case 51: //3 + toReturn = toReturn + 3 * multiplier; + break; + case 52: //4 + toReturn = toReturn + 4 * multiplier; + break; + case 53: //5 + toReturn = toReturn + 5 * multiplier; + break; + case 54: //6 + toReturn = toReturn + 6 * multiplier; + break; + case 55: //7 + toReturn = toReturn + 7 * multiplier; + break; + case 56: //8 + toReturn = toReturn + 8 * multiplier; + break; + case 57: //9 + toReturn = toReturn + 9 * multiplier; + break; + } + multiplier = multiplier * 10; + } + + return toReturn; +} + +/*********************************************************************** +* BRIEF: Tries to split a string on whitespace +* INFORMATION: Splits a string on whitespace and places it in dst +***********************************************************************/ +bool splitStringWhitespace(char * src, typeString dst[], uint16_t stringSize, uint16_t arraySize) +{ + char currentChar; + uint32_t iterator = 0; //iterates through the string + uint32_t arrayIterator = 0; //iterates through the array positioning + uint32_t arrayStringIterator = 0; //iterates through the string inside the array + //Loop through the values in src, until we find \r(enter) or null + while(currentChar = src[iterator], currentChar != '\r' && currentChar != 0 ) + { + //check if whitespace + if (currentChar == ' ') + { + //increase the array iterator + arrayIterator ++; + if (arrayIterator >= arraySize) //check that its not to large + { + //usart_send("To many words in the command"); + return false; + } + + arrayStringIterator = 0; + goto increment; //continue to the next iteration, with a goto the increment + } + + dst[arrayIterator][arrayStringIterator] = src[iterator]; //set the char to the correct array position + arrayStringIterator ++; + if (arrayStringIterator >=stringSize) + { + return false; + } + + //Goto statement to jump to the incrementation +increment: + iterator ++; //increment iterator + } + + return true; +} + +/*********************************************************************** +* BRIEF: Finds previous whitespace in a string +* INFORMATION: Given a string and start index it will try to find +* one whitespace counting downwards. +***********************************************************************/ +int FindPreviousWhiteSpaceIndex(char * msg, int startIndex) +{ + int toReturn = 0; + for (int i = startIndex; i >= 0; i--) + { + if(msg[i] == ' ') + { + toReturn = i; + break; + } + } + return toReturn; +} + /*********************************************************************** * BRIEF: Sums elements of array until index of second arg * * INFORMATION: Returns the sum *