Temp Publish
Diff: Terminal.cpp
- Revision:
- 0:4ccd12e1d789
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Terminal.cpp Tue Jan 08 16:21:39 2019 +0000 @@ -0,0 +1,689 @@ +/*------------------------------------------------------------------------------ +Creator : Jonathan Wheadon +Date : 28/11/2018 +Module : ELEC351 +Project : ELEC351_GroupA +Dependencies : "Terminal.hpp" and "General.hpp" +Purpose : This cpp defines the functions for the terminal class which are used +to control the terminal, it also defines the TerminalThread function which +is ran in its own thread and controls the printing of DATA to the Terminal +------------------------------------------------------------------------------*/ + +#include "Terminal.hpp" +#include "Sample.hpp" + +// queue for Terminal events +EventQueue TerminalQueue(32 * EVENTS_EVENT_SIZE); + +// external eventqueues for sample and display threads +extern EventQueue SampleQueue; +extern EventQueue DisplayQueue; + +// Create Object PC of class Terminal with Set SERIAL_TX and SERIAL_RX pins +Terminal PC(SERIAL_TX, SERIAL_RX); + +extern cyclical_Buffer internalBuffer; + +extern Mail<mail_t, 32>Terminal_mail; + + +/*------------------------------------------------------------------------------ + Thread for handiling the terminal +------------------------------------------------------------------------------*/ +void TerminalThread(void) +{ + PC.init(); + + // Enter Forever loop + while(1) + { + TerminalQueue.dispatch_forever(); + } +} + +/*------------------------------------------------------------------------------ + Gets data from mailbox and displays on Terminal, if terminal is full it + overwrites the oldest displayed sample. +------------------------------------------------------------------------------*/ +void Terminal::addDATA(void) +{ + //open mailbox and print to line in terminal + osEvent evt = Terminal_mail.get(); + if (evt.status == osEventMail) { + mail_t *mail = (mail_t*)evt.value.p; + if(col == 0) + { + Colour(ColourBLUE); + } else { + Colour(ColourPURPLE); + } + // Print time + PrintDATA(mail->MDate, currentIDX); + currentIDX++; + // Print Temp + PrintDATA(mail->MTEMP, currentIDX); + currentIDX++; + // Print Pressure + PrintDATA(mail->MPRESS, currentIDX); + currentIDX++; + // Print Light + PrintDATA(mail->MLIGHT, currentIDX); + currentIDX++; + if(currentIDX >= MaxDATA) + { + currentIDX = 0; + if(col == 0) + { + col = 1; + } else { + col = 0; + } + } + Terminal_mail.free(mail); + } +} + +/*------------------------------------------------------------------------------ + initialize terminal, print table, initialize variables and attach interupts +------------------------------------------------------------------------------*/ +void Terminal::init(void) +{ + // Set baud rate for serial object pc + pc.baud (115200); + + // Hide cursor, move to x 0 y 0 and change print colour to green + pc.printf("\x1b[?25l"); // Hides cursor + //pc.printf("\x1b[3j"); // Clear screen + Cursor(0,0); + Colour(ColourGREEN); + + // Print DATA table to present data + pc.printf("| ELEC351 : Low Power Enviromental Sensor | |\n\r" + "|*******************************************************************************************|\n\r" + "| TIME | TEMP (C) | PRESSURE (mbar) | LIGHT (V) |\n\r" + "|----------------------|----------------------|----------------------|----------------------|\n\r"); + for(BYTE idx = 0; idx < Rows; idx++) + { + pc.printf("| | | | |\n\r"); + } + pc.printf("|*******************************************************************************************|\n\r" + "| Input Command Line : |\n\r" + "|-------------------------------------------------------------------------------------------|\n\r" + "| |\n\r" + "|*******************************************************************************************|\n\r" + "| SD state : | NetWork Conected : |\n\r" + "|*******************************************************************************************|\n\r" + " \n\r" + " "); + + + // InitNetwork indicator + Colour(ColourRED); + Cursor((68),(Rows+10)); + pc.printf("NO"); + + // initialise variables + buffer_pointer = 0; + col = 0; + currentIDX = 0; + + // Attach interupts + Terminal_ticker.attach(this, &Terminal::Ticker_Handler, 1.0f); + pc.attach(this, &Terminal::Input_Handler,pc.RxIrq); +} + +/*------------------------------------------------------------------------------ + Move cursor of pc terminal to co-ordinates 'X' and 'Y' (between 0 and 255) +------------------------------------------------------------------------------*/ +void Terminal::Cursor(BYTE X, BYTE Y) +{ + pc.printf("\x1b[%d;%dH",Y,X); +} + +/*------------------------------------------------------------------------------ + Change pc terminal print colour (8 bit colour) to colour defined by "COLOUR" +------------------------------------------------------------------------------*/ +void Terminal::Colour(BYTE COLOUR) +{ + pc.printf("\x1b[38;5;%dm",COLOUR); +} + +/*------------------------------------------------------------------------------ + Prints data(STRING) to cell in table defined by IDX +------------------------------------------------------------------------------*/ +void Terminal::PrintDATA(BYTE* STRING, BYTE IDX) +{ + BYTE Y = (IDX/4)+5; + BYTE X = ((IDX%4)*23)+3; + Cursor(X,Y); + pc.printf("%s",STRING); +} + +/*------------------------------------------------------------------------------ + function updates displayed SD state to boolean input +------------------------------------------------------------------------------*/ +void Terminal::updateSDstate(bool SDstate) +{ + Cursor((14),(Rows+10)); + switch(SDstate) { + case true : + Colour(ColourGREEN); + pc.printf(" MOUNTED SD "); + break; + + case false : + Colour(ColourRED); + pc.printf("UNMOUNTED SD"); + break; + } +} + +/*------------------------------------------------------------------------------ + function updates displayed NetWork state to boolean input +------------------------------------------------------------------------------*/ +void Terminal::updateNetWorkstate(bool NetWorkstate) +{ + Cursor((68),(Rows+10)); + switch(NetWorkstate) { + case true : + Colour(ColourGREEN); + pc.printf(" YES "); + break; + + case false : + Colour(ColourRED); + pc.printf(" NO "); + break; + } +} + +/*------------------------------------------------------------------------------ + Function checks terminal buffer to see which key has been entered and saves to + internal buffer, if carridge return (0x0D) has been pressed it calls function + to decode the command to the event QUEUE +------------------------------------------------------------------------------*/ +void Terminal::checkKEY(void) +{ + BYTE gotkey; + gotkey=pc.getc(); + if(gotkey == NULL) + { + // do nothing + } else if (gotkey == 0x0D) { + Terminal_buffer[buffer_pointer] = 0x00; + TerminalQueue.call(&PC, &Terminal::HandleCOMMAND); + buffer_pointer = 0; + Cursor((24),(Rows+6)); + pc.printf(" "); + } else if (gotkey == 0x7f) { + if (buffer_pointer > 0) { + buffer_pointer -= 1; + Cursor((24 + buffer_pointer),(Rows+6)); + pc.printf(" "); + } else { + //do nothing + } + } else { + Colour(ColourWHITE); + if(buffer_pointer == 30) + { + // do error thing + } else { + pc.printf("\x1b[4m"); + Cursor((24 + buffer_pointer),(Rows+6)); + Colour(ColourWHITE); + pc.printf("%c",gotkey); + pc.printf("\x1b[24m"); + Terminal_buffer[buffer_pointer] = gotkey; + buffer_pointer++; + } + } + pc.attach(this, &Terminal::Input_Handler,pc.RxIrq); +} + +/*------------------------------------------------------------------------------ + Function decodes command that has been input on input command line and performs + any necasary action +------------------------------------------------------------------------------*/ +void Terminal::HandleCOMMAND(void) +{ + INT_32 commandSize = 0; + INT_32 dataSIZE = 0; + bool searchingCOMMAND = true; + bool searchingDATA = true; + while(searchingCOMMAND) + { + if((Terminal_buffer[commandSize] == ' ') || (Terminal_buffer[commandSize] == 0x00)) + { + searchingCOMMAND = false; + } else { + commandSize++; + } + + // debug break loop if too big + if(commandSize > 8){ + break; + } + } + while(searchingDATA) + { + if((Terminal_buffer[commandSize+dataSIZE+1] == ' ') || (Terminal_buffer[commandSize+dataSIZE+1] == 0x00)) + { + searchingDATA = false; + } else { + dataSIZE++; + } + + // debug break loop if too big + if(dataSIZE > 8){ + break; + } + } + + if(commandSize == 4) + { + + // Action for input of READ command + if((Terminal_buffer[0] == 'R') && (Terminal_buffer[1] == 'E') && (Terminal_buffer[2] == 'A') && (Terminal_buffer[3] == 'D')) { + if(dataSIZE > 3){ + Error msgs; + msgs.ErrorCode = warning; + msgs.ErrorMSGS = "input Value is not valid for command \"READ\""; + ERROR_MSGS(msgs); + } else { + INT_32 inputVAL; + if(dataSIZE == 1) { + BYTE tempARRAY[3] = {'0','0',Terminal_buffer[5]}; + inputVAL = strTOint(tempARRAY); + } else if(dataSIZE == 2) { + BYTE tempARRAY[3] = {'0',Terminal_buffer[5],Terminal_buffer[6]}; + inputVAL = strTOint(tempARRAY); + } else if(dataSIZE == 3) { + BYTE tempARRAY[3] = {Terminal_buffer[5],Terminal_buffer[6],Terminal_buffer[7]}; + inputVAL = strTOint(tempARRAY); + } + if(inputVAL != NULL){ + mail_t bufferedDATA = internalBuffer.ReadNfromBuffer(inputVAL); + if(bufferedDATA.MDate != NULL){ + printBufferedData(bufferedDATA); + } else { + Error msgs; + msgs.ErrorCode = warning; + msgs.ErrorMSGS = "Value is outside the number of stored samples"; + ERROR_MSGS(msgs); + } + } else { + Error msgs; + msgs.ErrorCode = warning; + msgs.ErrorMSGS = "Value input is incorrect format for command \"READ\""; + ERROR_MSGS(msgs); + } + } + + // Action for input of SETT command + } else if((Terminal_buffer[0] == 'S') && (Terminal_buffer[1] == 'E') && (Terminal_buffer[2] == 'T') && (Terminal_buffer[3] == 'T')) { + FLOAT_32 inputVAL; + if(dataSIZE == 3) { + BYTE tempARRAY[4] = {'0',Terminal_buffer[5],Terminal_buffer[6],Terminal_buffer[7]}; + inputVAL = strTOflt(tempARRAY); + } else if(dataSIZE == 4) { + BYTE tempARRAY[4] = {Terminal_buffer[5],Terminal_buffer[6],Terminal_buffer[7],Terminal_buffer[8]}; + inputVAL = strTOflt(tempARRAY); + } else { + inputVAL = NULL; + } + if(inputVAL != NULL){ + // TELL SAMPLE THREAD TO UPDATE SAMPLE RATE + SampleQueue.call(update_sampleRATE, inputVAL); + printDEBUG("New sample rate has been applied!!!"); + } else { + Error msgs; + msgs.ErrorCode = warning; + msgs.ErrorMSGS = "Value input is incorrect format for command \"SETT\""; + ERROR_MSGS(msgs); + } + + // Command not recognised + } else { + Error msgs; + msgs.ErrorCode = warning; + msgs.ErrorMSGS = "Command not recognised"; + ERROR_MSGS(msgs); + } + + } else if(commandSize == 5) { + + // Action for STATE command + if((Terminal_buffer[0] == 'S') && (Terminal_buffer[1] == 'T') && (Terminal_buffer[2] == 'A') && (Terminal_buffer[3] == 'T') && (Terminal_buffer[4] == 'E')) { + if(dataSIZE == 2) { + if((Terminal_buffer[6] == 'O') && (Terminal_buffer[7] == 'N')){ + SampleQueue.call(start_sampling,true); // Tell sample thread to begin sampling + printDEBUG("Sampling has been turned ON"); // Print debug message to show command has been executed + } else { + Error msgs; + msgs.ErrorCode = warning; + msgs.ErrorMSGS = "State cannot be set to parameter given for command \"STATE\""; + ERROR_MSGS(msgs); + } + } else if(dataSIZE == 3) { + if((Terminal_buffer[6] == 'O') && (Terminal_buffer[7] == 'F') && (Terminal_buffer[8] == 'F')){ + SampleQueue.call(start_sampling,false); + printDEBUG("Sampling has been turned OFF"); + } else { + Error msgs; + msgs.ErrorCode = warning; + msgs.ErrorMSGS = "State cannot be set to parameter given for command \"STATE\""; + ERROR_MSGS(msgs); + } + } else { + Error msgs; + msgs.ErrorCode = warning; + msgs.ErrorMSGS = "State cannot be set to parameter given for command \"STATE\""; + ERROR_MSGS(msgs); + } + + // Command not recognised + } else { + Error msgs; + msgs.ErrorCode = warning; + msgs.ErrorMSGS = "Command not recognised"; + ERROR_MSGS(msgs); + } + + } else if(commandSize == 6) { + + // Action for DELETE command + if((Terminal_buffer[0] == 'D') && (Terminal_buffer[1] == 'E') && (Terminal_buffer[2] == 'L') && (Terminal_buffer[3] == 'E') && (Terminal_buffer[4] == 'T') && (Terminal_buffer[5] == 'E')) { + printDEBUG("DELETE command used"); + + // Command not recognised + } else { + Error msgs; + msgs.ErrorCode = warning; + msgs.ErrorMSGS = "Command not recognised"; + ERROR_MSGS(msgs); + } + + } else if(commandSize == 7) { + + // Action for SETTIME command + if((Terminal_buffer[0] == 'S') && (Terminal_buffer[1] == 'E') && (Terminal_buffer[2] == 'T') && (Terminal_buffer[3] == 'T') && (Terminal_buffer[4] == 'I') && (Terminal_buffer[5] == 'M') && (Terminal_buffer[6] == 'E')) { + BYTE tempARRAY[8] = {Terminal_buffer[8],Terminal_buffer[9],Terminal_buffer[10],Terminal_buffer[11],Terminal_buffer[12],Terminal_buffer[13],Terminal_buffer[14],Terminal_buffer[15]}; + if(handleTIME(tempARRAY) == NULL){ + Error msgs; + msgs.ErrorCode = warning; + msgs.ErrorMSGS = "TIME could not be set"; + ERROR_MSGS(msgs); + } else { + printDEBUG("Time set"); + } + + // Action for SETDATE command + } else if((Terminal_buffer[0] == 'S') && (Terminal_buffer[1] == 'E') && (Terminal_buffer[2] == 'T') && (Terminal_buffer[3] == 'D') && (Terminal_buffer[4] == 'A') && (Terminal_buffer[5] == 'T') && (Terminal_buffer[6] == 'E')) { + BYTE tempARRAY[10] = {Terminal_buffer[8],Terminal_buffer[9],Terminal_buffer[10],Terminal_buffer[11],Terminal_buffer[12],Terminal_buffer[13],Terminal_buffer[14],Terminal_buffer[15],Terminal_buffer[16],Terminal_buffer[17]}; + if(handleDATE(tempARRAY) == NULL){ + Error msgs; + msgs.ErrorCode = warning; + msgs.ErrorMSGS = "DATE could not be set"; + ERROR_MSGS(msgs); + } else { + printDEBUG("Date set"); + } + + // Action for LOGGING command + } else if((Terminal_buffer[0] == 'L') && (Terminal_buffer[1] == 'O') && (Terminal_buffer[2] == 'G') && (Terminal_buffer[3] == 'G') && (Terminal_buffer[4] == 'I') && (Terminal_buffer[5] == 'N') && (Terminal_buffer[6] == 'G')) { + if(dataSIZE == 2) { + if((Terminal_buffer[8] == 'O') && (Terminal_buffer[9] == 'N')){ + Logging_STATE = true; + printDEBUG("LOGGING has been enabled"); + } else { + Error msgs; + msgs.ErrorCode = warning; + msgs.ErrorMSGS = "State cannot be set to parameter given"; + ERROR_MSGS(msgs); + } + } else if(dataSIZE == 3) { + if((Terminal_buffer[8] == 'O') && (Terminal_buffer[9] == 'F') && (Terminal_buffer[10] == 'F')){ + printDEBUG("LOGGING has been disabled"); + Logging_STATE = false; + } else { + Error msgs; + msgs.ErrorCode = warning; + msgs.ErrorMSGS = "State cannot be set to parameter given"; + ERROR_MSGS(msgs); + } + } else { + Error msgs; + msgs.ErrorCode = warning; + msgs.ErrorMSGS = "State cannot be set to parameter given"; + ERROR_MSGS(msgs); + } + + // Command not recognised + } else { + Error msgs; + msgs.ErrorCode = warning; + msgs.ErrorMSGS = "Command not recognised"; + ERROR_MSGS(msgs); + } + // Command not recognised + } else { + Error msgs; + msgs.ErrorCode = warning; + msgs.ErrorMSGS = "Command not recognised"; + ERROR_MSGS(msgs); + } +} + +/*------------------------------------------------------------------------------ + ISR for whenever data is in terminal buffer, add function to terminal queue + to check which charecteter has been entered and add it to a buffer. +------------------------------------------------------------------------------*/ +void Terminal::Input_Handler(void) +{ + pc.attach(NULL,pc.RxIrq); + if(pc.readable()!= 0) + { + TerminalQueue.call(&PC, &Terminal::checkKEY); + } +} + +/*------------------------------------------------------------------------------ + Function prints debug messages to screen +------------------------------------------------------------------------------*/ +void Terminal::printDEBUG(BYTE* msgs) +{ + if(Logging_STATE == true){ + Cursor(3,(Rows+8)); + Colour(ColourWHITE); + pc.printf(" "); + Cursor(3,(Rows+8)); + pc.printf(msgs); + } +} + +/*------------------------------------------------------------------------------ + Function prints debug messages to screen +------------------------------------------------------------------------------*/ +void Terminal::printBufferedData(mail_t bufferedDATA) +{ + Cursor(1,(Rows+12)); + Colour(ColourWHITE); + pc.printf(" "); + Cursor(1,(Rows+12)); + pc.printf("%s , %s , %s , %s ; ",bufferedDATA.MDate,bufferedDATA.MTEMP,bufferedDATA.MPRESS,bufferedDATA.MLIGHT); +} + +/*------------------------------------------------------------------------------ + Function prints ERROR messages to screen +------------------------------------------------------------------------------*/ +void Terminal::ERROR_MSGS(Error msgs) +{ + Cursor(3,(Rows+8)); + pc.printf(" "); + Cursor(3,(Rows+8)); + + switch(msgs.ErrorCode) + { + case warning : + Colour(ColourAMBER); + pc.printf("Warning - %s ", msgs.ErrorMSGS); + break; + + case fault : + Colour(ColourAMBER); + pc.printf("Fault - %s ", msgs.ErrorMSGS); + break; + + case criticalERROR : + Colour(ColourRED); + pc.printf("Critical ERROR - %s ", msgs.ErrorMSGS); + break; + + case criticalFAILURE : + Colour(ColourRED); + pc.printf("Critical FAILURE - %s ", msgs.ErrorMSGS); + break; + } +} + +/*------------------------------------------------------------------------------ + Ticker fires once per second and add function to terminal queue to update time +------------------------------------------------------------------------------*/ +void Terminal::Ticker_Handler(void) +{ + TerminalQueue.call(&PC, &Terminal::updateTIME); +} + +/*------------------------------------------------------------------------------ + Function prints current time to top right of terminal +------------------------------------------------------------------------------*/ +void Terminal::updateTIME(void) +{ + Cursor(67,1); + Colour(ColourWHITE); + pc.printf("%s", getSystemDateTime()); +} + +/*------------------------------------------------------------------------------ + Function converts string to FLOAT_32, one decimal place expected must be 4 bytes + long, PAd with '0', example 1.2f would be "01.2" and 12.3f would be "12.3" +------------------------------------------------------------------------------*/ +FLOAT_32 strTOflt(BYTE ary[4]) +{ + //check that values entered are in format "00.0" + for(INT_32 tester = 0; tester < 4; tester++) + { + if(tester != 2){ + INT_32 testing = (INT_32)(ary[tester]-'0'); + if((testing > 9) || (testing < 0)) { + return NULL; + } + } else if(ary[tester] != '.') { + return NULL; + } + } + + FLOAT_32 retFlt; + + retFlt = ((FLOAT_32)(ary[0]-'0'))*10.0f; + retFlt += ((FLOAT_32)(ary[1]-'0')); + retFlt += ((FLOAT_32)(ary[3]-'0'))/10.0f; + + if(retFlt > 60.0f){ + return NULL; + } else { + return retFlt; + } +} + +INT_32 strTOint(BYTE ary[3]) +{ + //check that values entered are in format "000" + for(INT_32 tester = 0; tester < 3; tester++) + { + INT_32 testing = (INT_32)(ary[tester]-'0'); + if((testing > 9) || (testing < 0)) { + return NULL; + } + } + + INT_32 temp_int = (INT_32)(ary[0]-'0')*100; + temp_int += (INT_32)(ary[1]-'0')*10; + temp_int += (INT_32)(ary[2]-'0'); + + return temp_int; +} + +/*------------------------------------------------------------------------------ + Function converts string to S_BYTE, format should be 00;00;00 (HH;MM;SS) +------------------------------------------------------------------------------*/ +BYTE handleTIME(BYTE ary[8]) +{ + //check that values entered are in format "00.0" + for(INT_32 tester = 0; tester < 8; tester++) + { + if((tester == 2 || tester == 5) == false){ + INT_32 testing = (INT_32)(ary[tester]-'0'); + if((testing > 9) || (testing < 0)) { + return NULL; + } + } else if((ary[tester] != ';') && (ary[tester] != '/') && (ary[tester] != ':')) { + return NULL; + } + } + + S_BYTE HH; + S_BYTE MM; + S_BYTE SS; + + HH = ((S_BYTE)(ary[0]-'0'))*10; + HH += ((S_BYTE)(ary[1]-'0')); + + MM = ((S_BYTE)(ary[3]-'0'))*10; + MM += ((S_BYTE)(ary[4]-'0')); + + SS = ((S_BYTE)(ary[6]-'0'))*10; + SS += ((S_BYTE)(ary[7]-'0')); + + DisplayQueue.call(setTime,HH,MM,SS); + + return 1; +} +/*------------------------------------------------------------------------------ + Function converts string to S_BYTE, format should be 00;00;0000 (dd;mm;yyyy) +------------------------------------------------------------------------------*/ +BYTE handleDATE(BYTE ary[10]) +{ + //check that values entered are in format "00.0" + for(INT_32 tester = 0; tester < 10; tester++) + { + if((tester == 2 || tester == 5) == false){ + INT_32 testing = (INT_32)(ary[tester]-'0'); + if((testing > 9) || (testing < 0)) { + return NULL; + } + } else if((ary[tester] != ';') && (ary[tester] != '/') && (ary[tester] != ':')) { + return NULL; + } + } + + S_BYTE dd; + S_BYTE mm; + INT_32 yyyy; + + dd = ((S_BYTE)(ary[0]-'0'))*10; + dd += ((S_BYTE)(ary[1]-'0')); + + mm = ((S_BYTE)(ary[3]-'0'))*10; + mm += ((S_BYTE)(ary[4]-'0')); + + yyyy = ((INT_32)(ary[6]-'0'))*1000; + yyyy += ((INT_32)(ary[7]-'0'))*100; + yyyy += ((INT_32)(ary[8]-'0'))*10; + yyyy += ((INT_32)(ary[9]-'0')); + + DisplayQueue.call(setDate,dd,mm,yyyy); + + return 1; +}