![](/media/cache/profiles/ba5be68d3d541f2ca043d77fc54fe702.jpg.50x50_q85.jpg)
3rd Repo, trying to figure this out.
Fork of SOFT253_Template_Weather_OS_54 by
main.cpp
- Committer:
- niallfrancis
- Date:
- 2017-05-13
- Revision:
- 85:422d0a1b95cf
- Parent:
- 83:0d3572a8a851
File content as of revision 85:422d0a1b95cf:
#include "mbed.h" #include "rtos.h" #include "hts221.h" #include "LPS25H.h" #include "MessageLogger.h" #include "CircularArray.h" #include "FakeSensor.h" #include <string.h> #include <stdio.h> #include <ctype.h> #include <iostream> #include <sstream> #define SIGNAL_doMeasure 1 #define SIGNAL_printMessage 2 #define SIGNAL_terminate 3 #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 // DigitalOut myled(LED1); DigitalIn onBoardSwitch(USER_BUTTON); I2C i2c2(I2C_SDA, I2C_SCL); // // 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); // Fake sensor // FakeBarometer barometer(1029.0, 1031.0); // FakeMeasurer measurer(20.0, 25.0, 30.0, 50.0); // // THREADS DECLARATION // osThreadId mainThreadId; Thread *producerThread; Thread *measurementThread; Thread *consumerThread; Thread *loggingThread; Ticker timer; Ticker realTimeDate; // // GLOBAL VARIABLES // Mail<Measure, 16> mail_box; LocalDate *localDate; bool logging = false; bool measuring = true; double sampleRate = 15; char temp[256]; // Logging objects MessageLogger logger; CircularArray buffer(BUFFER_SIZE, &logger); // // Called by a ticker // Adds 1 second every second to the clock // void RealTimeDate() { localDate->TickSecond(); } // // Ticker that signals the measureThread to do a measure // void SendSignalDoMeasure() { measurementThread->signal_set(SIGNAL_doMeasure); } // // Called by ticker every T seconds // Reads values from sensor board, sends between threads using a mail queue // void MeasurementThread() { float temperature , humidity, pressure; while(true) { temperature = 0; humidity = 0; pressure = 0; Thread::signal_wait(SIGNAL_doMeasure); Measure *measure = mail_box.alloc(); if (measure == NULL) { logger.SendError("Out of memory\r\n"); return; } //Read data from measurer, puts data into a measure object. measurer.ReadTempHumi(&temperature,&humidity); barometer.get(); pressure = barometer.pressure(); measure->temperature = temperature; measure->humidity = humidity; measure->pressure = pressure; measure->date.setValues(localDate); osStatus stat = mail_box.put(measure); // 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); logger.SendMessage(temp); } } } // // Receives data through mail queue, then adds it to the circular array buffer. // void ProducerThread() { while (true) { osEvent evt = mail_box.get(); // 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); buffer.pushValue(msr); mail_box.free(measure); } else { snprintf(temp, 256, "ERROR: %x\r\n", evt.status); logger.SendError(temp); } } } int i; /** 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; } } return true; } /** Reads commands from the terminal and 'consumes' the data accordingly. */ void ConsumerThread() { char charCmd; //Char array that stores the chars entered when user presses enter. char command[40]; //Current Command Size int crtSize = 0; logger.SendMessage("\r\nAwaiting Command: \r\n"); while(1) { charCmd = NULL; charCmd = getchar(); if(logging) { logging = false; 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 && crtSize > 0 ) { command[--crtSize] = '\0'; } //If NOT enter AND NOT Backspace is pressed, SAVE the char else if(charCmd != 13 && charCmd != 127) { command[crtSize++] = charCmd; } // If enter is pressed, process the command. else if(charCmd == 13) { logger.SendMessage("\n"); // Get first word of command. char *charPos; charPos = strtok(command," -,"); // Check if it's a "read" command if(CompareCommands(charPos, "read",4)) { charPos = strtok(NULL," -,"); // 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 "read n" command else if(strtol(charPos,NULL,10) != 0) { int num = atoi(charPos); buffer.readN(num); logger.SendMessage("D O N E ! \r\n"); } else { logger.SendMessage("Expected parameters: \"all\" | \"n\", where n is a number.\r\n"); } } // Check if it's a "delete" command else if (CompareCommands(charPos,"delete",6)) { charPos = strtok(NULL," -,"); // Check if it's a "delete all" command if(CompareCommands(charPos,"all",3)) { logger.SendMessage("Deleting all measures performed so far: \r\n"); buffer.deleteAll(); } // 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.deleteN(atoi(charPos)); logger.SendMessage("Elements deleted!\r\n"); } else { logger.SendMessage("Expected parameters: \"all\" | \"n\", where n is a number."); } } // Check if it's a "status" command else if (CompareCommands(charPos,"status",6)) { char *ptr = localDate->ToString(); snprintf(temp, 256, "\nStatus: \r\n"); logger.SendMessage(temp); snprintf(temp, 256, " # of measures: %i \r\n", buffer.getSize()); logger.SendMessage(temp); snprintf(temp, 256, " Sampling: %s \r\n", measuring ? "On" : "Off"); logger.SendMessage(temp); snprintf(temp, 256, " Logging: %s \r\n", logging ? "On" : "Off"); logger.SendMessage(temp); snprintf(temp, 256, " Current Date: %s \r\n", ptr); logger.SendMessage(temp); snprintf(temp, 256, " Sample Rate(s): %2.2f \r\n", sampleRate); logger.SendMessage(temp); } //Check if it's a "settime" command else if (CompareCommands(charPos,"settime",7)) { int h,m,s; charPos = strtok(NULL," -,"); if(strtol(charPos,NULL,10) != 0) { h = atoi(charPos); } charPos = strtok(NULL," -,"); if(strtol(charPos,NULL,10) != 0) { m = atoi(charPos); } charPos = strtok(NULL," -,"); if(strtol(charPos,NULL,10) != 0) { s = atoi(charPos); } if((h>=0 && h < 24) && (m>=0 && m<60) && (s>=0 && s<60)) { localDate->hour = h; localDate->min = m; localDate->sec = s; char *ptr = localDate->ToString(); snprintf(temp, 256, "Updated Date to: %s \r\n", ptr); logger.SendMessage(temp); } else { logger.SendMessage("\r\nWrong format! please use HH-MM-SS. \r\n"); } } //Check if it's a "setdate" command else if (CompareCommands(charPos,"setdate",7)) { int d,m,y; charPos = strtok(NULL," ,-"); if(strtol(charPos,NULL,10) != 0) { d = atoi(charPos); } charPos = strtok(NULL," ,-"); if(strtol(charPos,NULL,10) != 0) { m = atoi(charPos); } charPos = strtok(NULL," ,-"); if(strtol(charPos,NULL,10) != 0) { y = atoi(charPos); } if((d>=0 && d < 31) && (m>=0 && m<13)) { localDate->day = d; localDate->month = m; localDate->year = y; char *ptr = localDate->ToString(); snprintf(temp, 256, "Updated Date to: %s \r\n", ptr); logger.SendMessage(temp); } else { logger.SendMessage("Wrong format! please use DD-MM-YYYY. \r\n"); } } // Check if it's a "state" command else if(CompareCommands(charPos,"state",5)) { charPos = strtok(NULL," ,"); // Check if it should be turned on / off if(CompareCommands(charPos,"on",2)) { 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"); timer.detach(); measuring = false; } else { logger.SendMessage("Expected parameters: \"on\" | \"off\"\r\n"); } } // Check if it's a "logging" command else if(CompareCommands(charPos,"logging",7)) { charPos = strtok(NULL," ,"); //Check if it should be turned ON / OFF if(CompareCommands(charPos,"on",2)) { logging = true; logger.SendMessage("Debug logging turned on!\r\n"); logger.SendMessage("Press any key to deactivate\r\n"); } else if (CompareCommands(charPos,"off",3)) { logger.SendMessage("Logging is already turned off.\r\n"); } else { logger.SendMessage("Expected parameters: \"on\" | \"off\"\r\n"); } } // Check if it's a "sett" command else if(CompareCommands(charPos,"sett",4)) { charPos = strtok(NULL," ,"); double auxRate = atof(charPos); // Validate rate if(auxRate >= 0.1 && auxRate <= 60) { sampleRate = auxRate; timer.detach(); timer.attach(&SendSignalDoMeasure, sampleRate); snprintf(temp, 256, "Successfully updated sample rate to: %2.2f .\r\n",sampleRate); logger.SendMessage(temp); } else { logger.SendMessage("Sample rate must be between 0.1 and 60.\r\n"); } } // Check if it's a "help" command else if (CompareCommands(charPos,"help",4) || CompareCommands(charPos,"?",1)) { logger.SendMessage("\nAvailable Commands:\r\n"); logger.SendMessage(" read <all|n> - Read all or n first measures.\r\n"); logger.SendMessage(" delete <all|n> - Delete all or n first measures.\r\n"); logger.SendMessage(" setdate <DD> <MM> <YYYY> Set current date.\r\n"); logger.SendMessage(" settime <HH> <MM> <SS> Set current time.\r\n"); logger.SendMessage(" sett <T> Set sample rate (in seconds).\r\n"); 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 "reset" command else if (CompareCommands(charPos,"reset",5)) { logger.SendError("Program Terminating...\r\n"); } // If command is not recognized else { logger.SendMessage("Command not recognized. Type \"help\" for more info.\r\n"); } if(!logging) { logger.SendMessage("\r\nAwaiting Command:\r\n"); } // Clear currently stored command int i = 0; for(i =0 ; i < crtSize; i++) command[i] = ' '; command[0] = 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() { while(true) { Thread::signal_wait(SIGNAL_printMessage); while(true) { if(logger.GetError()) { osSignalSet(mainThreadId, SIGNAL_terminate); } else if(!logger.GetMessage()) { break; } } } } /** Main Thread: Entry point to program. */ int main() { mainThreadId = osThreadGetId(); measurer.init(); measurer.calib(); localDate = new LocalDate(); // Timer initialised for measurements to be collected every sampleRate seconds. timer.attach(&SendSignalDoMeasure, sampleRate); realTimeDate.attach(&RealTimeDate,1.0); // Start Threads loggingThread = new Thread(); loggingThread->start(LoggingThread); logger.SetThread(loggingThread); 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"); SendSignalDoMeasure(); while(true) { // Waits for temination signal from logging thread when an error is received. osSignalWait(SIGNAL_terminate, osWaitForever); 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(); } }