3rd Repo, trying to figure this out.
Fork of SOFT253_Template_Weather_OS_54 by
Diff: main.cpp
- Revision:
- 83:0d3572a8a851
- Parent:
- 82:668b51a39148
- Child:
- 85:422d0a1b95cf
--- a/main.cpp Thu May 11 15:53:15 2017 +0000 +++ b/main.cpp Thu May 11 19:23:55 2017 +0000 @@ -1,4 +1,3 @@ - #include "mbed.h" #include "rtos.h" #include "hts221.h" @@ -20,6 +19,31 @@ #define SWITCH1_RELEASE 90 #define BUFFER_SIZE 120 +/** + @file : main.cpp + @authors : Radu Marcu, Jacob Williams, Niall Francis, Arron Burch + + @section DESCRIPTION + + This is the main class where the program runs on startup, this is + a multi-threaded application that will that make the ST F401 Nucleo Target board + take periodic measurements of senor data, including temperature, + pressure and humidity, at a fixed set sample rate. A max of 120 measurements are stored + within RAM at any one time, available to be printed to a termial output via a serial port + connection. + Once 120 measurements are stored, the oldest measurements are overwritten using a circular + buffer, so that the most recent 120 measurements can always be stored on the device. + The application can provide logging data when measurements are taken if logging is turned + on using the logging command (See readme.md). + The application has been written to reduce power consumption where possible by utilising + Thread signals and sleeping when not in use. + Serial Communications are handled within a sepearate thread to ensure that no action will + block or interrupt the CPU when measuring samples. + The serial communications use a priority system, allowing errors to be printed with a higher + priority than logging messages and the application to be terminated and reset by user input + if required. +*/ + // // MBED DECLARATIONS // @@ -31,19 +55,19 @@ // SENSOR DECLARATIONS // MAKE SURE ONE OF THESE IS COMMENTED OUT // Real sensor -// LPS25H barometer(i2c2, LPS25H_V_CHIP_ADDR); -// HTS221 measurer(I2C_SDA, I2C_SCL); +LPS25H barometer(i2c2, LPS25H_V_CHIP_ADDR); +HTS221 measurer(I2C_SDA, I2C_SCL); // Fake sensor -FakeBarometer barometer(1029.0, 1031.0); -FakeMeasurer measurer(20.0, 25.0, 30.0, 50.0); +// FakeBarometer barometer(1029.0, 1031.0); +// FakeMeasurer measurer(20.0, 25.0, 30.0, 50.0); // // THREADS DECLARATION // osThreadId mainThreadId; -Thread *produceThread; -Thread *measureThread; -Thread *consumeThread; +Thread *producerThread; +Thread *measurementThread; +Thread *consumerThread; Thread *loggingThread; Ticker timer; Ticker realTimeDate; @@ -52,7 +76,6 @@ // Mail<Measure, 16> mail_box; LocalDate *localDate; -//Mail<> bool logging = false; bool measuring = true; double sampleRate = 15; @@ -63,8 +86,9 @@ CircularArray buffer(BUFFER_SIZE, &logger); // -// Called by a TICKER +// Called by a ticker // Adds 1 second every second to the clock +// void RealTimeDate() { localDate->TickSecond(); @@ -75,13 +99,14 @@ // void SendSignalDoMeasure() { - measureThread->signal_set(SIGNAL_doMeasure); + measurementThread->signal_set(SIGNAL_doMeasure); } // -// SIGNALED BY Ticker at a frequency of <T> Hz -// Reads values from sensor board, sends over through mail queue -void MeasureThread() +// Called by ticker every T seconds +// Reads values from sensor board, sends between threads using a mail queue +// +void MeasurementThread() { float temperature , humidity, pressure; @@ -90,7 +115,7 @@ temperature = 0; humidity = 0; pressure = 0; - //Await signal from ticker + Thread::signal_wait(SIGNAL_doMeasure); Measure *measure = mail_box.alloc(); @@ -100,7 +125,7 @@ return; } - //Read and fill in data + //Read data from measurer, puts data into a measure object. measurer.ReadTempHumi(&temperature,&humidity); barometer.get(); pressure = barometer.pressure(); @@ -112,80 +137,83 @@ osStatus stat = mail_box.put(measure); - //Check if succesful - if (stat == osErrorResource) { + // Check if mailbox allocation was unsuccessful + if (stat == osErrorResource) + { snprintf(temp, 256, "queue->put() Error code: %4Xh, Resource not available\r\n", stat); logger.SendError(temp); mail_box.free(measure); return; } + // Print measurement taken if logging is enabled if(logging) { logger.SendMessage("Measurement Taken:\r\n"); char *ptr = localDate->ToString(); - snprintf(temp, 256, " %s T: %f | H: %f | P: %f |\n\r",ptr, temperature, humidity, pressure); + snprintf(temp, 256, " %s T: %f, H: %f, P: %f\n\r",ptr, temperature, humidity, pressure); logger.SendMessage(temp); } } } // -// Receives data through mail queue, then adds it to the global declared list -// A.K.A. Producer Thread +// Receives data through mail queue, then adds it to the circular array buffer. +// void ProducerThread() { while (true) { - //Block on the queue osEvent evt = mail_box.get(); - //Check status - if (evt.status == osEventMail) { - + // Check if mailbox retrieval was successful + if (evt.status == osEventMail) + { Measure *measure = (Measure*)evt.value.p; Measure msr(measure->date,measure->temperature, measure->humidity,measure->pressure); - // Changed to use circlar buffer rather than list buffer buffer.pushValue(msr); mail_box.free(measure); - } else { + } + else + { snprintf(temp, 256, "ERROR: %x\r\n", evt.status); logger.SendError(temp); - } + } } } + int i; -// -// Compares two char arrays and returns result -// Param1: First char Array / pointer -// Param2: Second char Array / pointer -// Param3. Size of the smallest char arrays (between param1 and param2) -// Return: "-1" IF NOT EQUAL -// "1 " IF EQUAL -bool CompareCommands(char command[],char targetcommand[], int size) +/** + Compares two char arrays and returns result + + @param command : First char Array / pointer + @param targetCommand : Second char Array / pointer + @param size : Size of the smallest char arrays (between param1 and param2) + @return : TRUE if equal, FALSE if not equal +*/ +bool CompareCommands(char command[],char targetCommand[], int size) { - for(i = 0; i < size; i ++) - { - if(command[i] != targetcommand[i]) - { - return false; - } + for(i = 0; i < size; i ++) + { + if(command[i] != targetCommand[i]) + { + return false; } - return true; -} + } + return true; +} -// -// Reads commands through PUTTY and 'consumes the data' accordingly -// A.K.A. Consumer Thread -void ConsumeThread() +/** + Reads commands from the terminal and 'consumes' the data accordingly. +*/ +void ConsumerThread() { - //Last character pressed read (last key input) char charCmd; - //Char array that stores the command after user presses ENTER + //Char array that stores the chars entered when user presses enter. char command[40]; //Current Command Size - int crtChar = 0; + int crtSize = 0; logger.SendMessage("\r\nAwaiting Command: \r\n"); while(1) { @@ -194,49 +222,47 @@ if(logging) { logging = false; - logger.SendMessage("\r\033[1AKey Pressed. Debug logging disabled.\r\n"); + logger.SendMessage("\rKey Pressed. Debug logging disabled.\r\n"); charCmd = NULL; } if(charCmd != NULL) { //If BACKSPACE is pressed, Print "DEL" so it deletes last character typed. - if (charCmd == 127 && crtChar > 0 ) + if (charCmd == 127 && crtSize > 0 ) { - command[--crtChar] = '\0'; + command[--crtSize] = '\0'; } //If NOT enter AND NOT Backspace is pressed, SAVE the char else if(charCmd != 13 && charCmd != 127) { - command[crtChar++] = charCmd; + command[crtSize++] = charCmd; } - //If ENTER is pressed, PROCESS it - else if(charCmd == 13) // If Enter is pressed + // If enter is pressed, process the command. + else if(charCmd == 13) { - //Get first word of command: + logger.SendMessage("\n"); + // Get first word of command. char *charPos; charPos = strtok(command," -,"); - //Check if it's a "LIST" command + // Check if it's a "read" command if(CompareCommands(charPos, "read",4)) { charPos = strtok(NULL," -,"); - //Check if it's a "LIST ALL" command + // Check if it's a "read all" command if(CompareCommands(charPos, "all",3)) { // Changed to use circular buffer rather than list buffer buffer.readAll(); logger.SendMessage("D O N E ! \r\n"); } - //Check if it's a "LIST X" command + // Check if it's a "read n" command else if(strtol(charPos,NULL,10) != 0) { int num = atoi(charPos); - logger.SendMessage(temp); - - // Changed to use circular buffer rather than list buffer - buffer.readX(num); + buffer.readN(num); logger.SendMessage("D O N E ! \r\n"); } else @@ -244,23 +270,22 @@ logger.SendMessage("Expected parameters: \"all\" | \"n\", where n is a number.\r\n"); } } - //Check if it's a "DELETE" command + // Check if it's a "delete" command else if (CompareCommands(charPos,"delete",6)) { charPos = strtok(NULL," -,"); - //Check if it's a "DELETE ALL" command + // Check if it's a "delete all" command if(CompareCommands(charPos,"all",3)) { logger.SendMessage("Deleting all measures performed so far: \r\n"); - // Changed to use circular buffer rather than list buffer buffer.deleteAll(); } - //Check if it's a "DELETE X" command + // Check if it's a "delete n" command else if (strtol(charPos,NULL,10) != 0) { // Changed to use circular buffer rather than list buffer - buffer.deleteX(atoi(charPos)); + buffer.deleteN(atoi(charPos)); logger.SendMessage("Elements deleted!\r\n"); } else @@ -268,12 +293,11 @@ logger.SendMessage("Expected parameters: \"all\" | \"n\", where n is a number."); } } - //Check if it's a "STATUS" command + // Check if it's a "status" command else if (CompareCommands(charPos,"status",6)) { char *ptr = localDate->ToString(); - // Changed to use circular buffer rather than list buffer snprintf(temp, 256, "\nStatus: \r\n"); logger.SendMessage(temp); snprintf(temp, 256, " # of measures: %i \r\n", buffer.getSize()); @@ -287,29 +311,26 @@ snprintf(temp, 256, " Sample Rate(s): %2.2f \r\n", sampleRate); logger.SendMessage(temp); } - //Check if it's a "SETTIME" command + //Check if it's a "settime" command else if (CompareCommands(charPos,"settime",7)) { int h,m,s; - //Fetch 1st Param + charPos = strtok(NULL," -,"); if(strtol(charPos,NULL,10) != 0) { h = atoi(charPos); } - //Fech 2nd Param charPos = strtok(NULL," -,"); if(strtol(charPos,NULL,10) != 0) { m = atoi(charPos); } - //Fetch 3rd Param charPos = strtok(NULL," -,"); if(strtol(charPos,NULL,10) != 0) { s = atoi(charPos); } - //Check if parameters are valid if((h>=0 && h < 24) && (m>=0 && m<60) && (s>=0 && s<60)) { localDate->hour = h; @@ -319,35 +340,34 @@ snprintf(temp, 256, "Updated Date to: %s \r\n", ptr); logger.SendMessage(temp); } - //If not valid, prompt user else { logger.SendMessage("\r\nWrong format! please use HH-MM-SS. \r\n"); } } - //Check if it's a "SETDATE" command + //Check if it's a "setdate" command else if (CompareCommands(charPos,"setdate",7)) { int d,m,y; - //Fetch 1st Parameter + charPos = strtok(NULL," ,-"); if(strtol(charPos,NULL,10) != 0) { d = atoi(charPos); } - //Fetch 2nd Parameter + charPos = strtok(NULL," ,-"); if(strtol(charPos,NULL,10) != 0) { m = atoi(charPos); } - //Fetch 3rd Parameter + charPos = strtok(NULL," ,-"); if(strtol(charPos,NULL,10) != 0) { y = atoi(charPos); } - //Check if parameters are valid + if((d>=0 && d < 31) && (m>=0 && m<13)) { localDate->day = d; @@ -357,27 +377,27 @@ snprintf(temp, 256, "Updated Date to: %s \r\n", ptr); logger.SendMessage(temp); } - // Prompt user if they are not. else { logger.SendMessage("Wrong format! please use DD-MM-YYYY. \r\n"); } } - // Check if it's a "STATE" command + // Check if it's a "state" command else if(CompareCommands(charPos,"state",5)) { charPos = strtok(NULL," ,"); - //Check if it should be turned ON / OFF + + // Check if it should be turned on / off if(CompareCommands(charPos,"on",2)) { - logger.SendMessage("Sampling turned ON!\r\n"); + logger.SendMessage("Sampling turned on!\r\n"); timer.attach(&SendSignalDoMeasure, sampleRate); SendSignalDoMeasure(); measuring = true; } else if (CompareCommands(charPos,"off",3)) { - logger.SendMessage("Sampling turned OFF!\r\n"); + logger.SendMessage("Sampling turned off!\r\n"); timer.detach(); measuring = false; } @@ -386,7 +406,7 @@ logger.SendMessage("Expected parameters: \"on\" | \"off\"\r\n"); } } - // Check if it's a "LOGGING" command + // Check if it's a "logging" command else if(CompareCommands(charPos,"logging",7)) { charPos = strtok(NULL," ,"); @@ -394,7 +414,7 @@ if(CompareCommands(charPos,"on",2)) { logging = true; - logger.SendMessage("Debug logging turned ON!\r\n"); + logger.SendMessage("Debug logging turned on!\r\n"); logger.SendMessage("Press any key to deactivate\r\n"); } else if (CompareCommands(charPos,"off",3)) @@ -406,7 +426,7 @@ logger.SendMessage("Expected parameters: \"on\" | \"off\"\r\n"); } } - // Check if it's a "SETT" command + // Check if it's a "sett" command else if(CompareCommands(charPos,"sett",4)) { charPos = strtok(NULL," ,"); @@ -421,13 +441,12 @@ snprintf(temp, 256, "Successfully updated sample rate to: %2.2f .\r\n",sampleRate); logger.SendMessage(temp); } - // if rate is not valid, prompt: else { logger.SendMessage("Sample rate must be between 0.1 and 60.\r\n"); } } - // Check if it's a "HELP" command + // Check if it's a "help" command else if (CompareCommands(charPos,"help",4) || CompareCommands(charPos,"?",1)) { logger.SendMessage("\nAvailable Commands:\r\n"); @@ -439,46 +458,44 @@ logger.SendMessage(" status - Status report of device.\r\n"); logger.SendMessage(" state - <on|off> - Turn sampling on or off.\r\n"); logger.SendMessage(" logging <on|off> - Turn logging on or off.\r\n"); + logger.SendMessage(" reset - Resets the current session of the application.\r\n"); } - // Check if it's a "HELP" command + // Check if it's a "reset" command else if (CompareCommands(charPos,"reset",5)) { logger.SendError("Program Terminating...\r\n"); } - // If command not recognized + // If command is not recognized else { logger.SendMessage("Command not recognized. Type \"help\" for more info.\r\n"); } - if(!logging) + + if(!logging) { logger.SendMessage("\r\nAwaiting Command:\r\n"); } - //Clear command! - //* NOTE * Setting first char in array to '\0' WILL NOT RESET IT...for some reason. + + // Clear currently stored command int i = 0; - for(i =0 ; i < crtChar; i++) + for(i =0 ; i < crtSize; i++) command[i] = ' '; command[0] = 0; - crtChar = 0; + crtSize = 0; } } } } +/** + Waits for a signal from the MessageLogger before confirming a message is to be printed, + ensuring messages are displayed in the correct order. + + If an error is recieved, error is prioritised and signal is sent to the main thread for the + program to be terminated, waiting for user input to reset. +*/ void LoggingThread() -{ - //Thread::wait(300000); - // ARRON: TODO - - // - Printing messages - // - Out of memory - // - Current status - // - Display time every X seconds/minutes - - // Some queue system holding lines to print - // If the queue has something to print, print it. - +{ while(true) { Thread::signal_wait(SIGNAL_printMessage); @@ -497,32 +514,37 @@ } } -// Main thread +/** + Main Thread: Entry point to program. +*/ int main() { - mainThreadId = osThreadGetId(); - //Initialize all stuff you need here: + + mainThreadId = osThreadGetId(); + measurer.init(); measurer.calib(); - localDate = new LocalDate(); - //Start message + localDate = new LocalDate(); - //Hook up timer interrupt + // Timer initialised for measurements to be collected every sampleRate seconds. timer.attach(&SendSignalDoMeasure, sampleRate); realTimeDate.attach(&RealTimeDate,1.0); - //Run Threads + // Start Threads + loggingThread = new Thread(); loggingThread->start(LoggingThread); logger.SetThread(loggingThread); - produceThread = new Thread(); - produceThread->start(ProducerThread); - measureThread = new Thread(); - measureThread->start(MeasureThread); - consumeThread = new Thread(); - consumeThread->start(ConsumeThread); + producerThread = new Thread(); + producerThread->start(ProducerThread); + + measurementThread = new Thread(); + measurementThread->start(MeasurementThread); + + consumerThread = new Thread(); + consumerThread->start(ConsumerThread); logger.SendMessage("\r\n--- W E L C O M E ---\r\n"); @@ -530,16 +552,18 @@ while(true) { + // Waits for temination signal from logging thread when an error is received. osSignalWait(SIGNAL_terminate, osWaitForever); - produceThread->terminate(); - measureThread->terminate(); - consumeThread->terminate(); + producerThread->terminate(); + measurementThread->terminate(); + consumerThread->terminate(); loggingThread->terminate(); + // Waits for user input before resetting the system. printf("Press any key to restart..."); char c = getchar(); - + printf("===============================\n\n\n"); NVIC_SystemReset(); } } \ No newline at end of file