Mbed Clock application using an NTP connection to get internet time and a terminal interface to send commands

Dependencies:   4DGL-uLCD-SE EthernetInterface NTPClient mbed-rtos mbed SDFileSystem wavfile

Files at this revision

API Documentation at this revision

Comitter:
dudanian
Date:
Tue Dec 02 17:22:43 2014 +0000
Child:
1:c47a2f0816bb
Commit message:
initial draft

Changed in this revision

4DGL-uLCD-SE.lib Show annotated file Show diff for this revision Revisions of this file
Clock.cpp Show annotated file Show diff for this revision Revisions of this file
Clock.h Show annotated file Show diff for this revision Revisions of this file
EthernetInterface.lib Show annotated file Show diff for this revision Revisions of this file
NTPClient.lib Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed-rtos.lib Show annotated file Show diff for this revision Revisions of this file
mbed.bld Show annotated file Show diff for this revision Revisions of this file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/4DGL-uLCD-SE.lib	Tue Dec 02 17:22:43 2014 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/4180_1/code/4DGL-uLCD-SE/#e39a44de229a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Clock.cpp	Tue Dec 02 17:22:43 2014 +0000
@@ -0,0 +1,55 @@
+#include "Clock.h"
+
+bool Clock::isSet = false;
+
+Clock::Clock() : timezone(UTC) {
+    if (!isSet) {
+        isSet = true;
+        set_time(1388534400);
+    }
+}
+
+/**
+ * Sets the time and stores it in UTC time
+ */
+void Clock::setTime(int hour, int minute, int period) {
+    time_t rawtime = time(NULL);
+    struct tm *timeinfo = localtime(&rawtime);
+    if (hour == 12)
+        hour = 0;
+    timeinfo->tm_hour = (((period == AM) ? hour : (hour + 12)) - timezone) % 24;
+    timeinfo->tm_min = minute;
+    timeinfo->tm_sec = 0;
+    set_time(mktime(timeinfo));
+}
+
+/**
+ * Sets the timezone. Since the time is stored in UTC, the system time 
+ * is not modified
+ */
+void Clock::setTimezone(int timezone) {
+    
+    this->timezone = timezone;
+}
+
+/**
+ * Uses an NTP Client to set the time to UTC
+ */
+int Clock::syncTime() {
+    NTPClient ntp;
+    return ntp.setTime("0.pool.ntp.org");
+}
+
+/**
+ * Gets the system time in UTC and converts it according to the given timezone
+ */
+time_t Clock::getTime() {
+    time_t rawtime = time(NULL);
+    struct tm *timeinfo = localtime(&rawtime);
+    timeinfo->tm_hour = (timeinfo->tm_hour + timezone) % 24;
+    return mktime(timeinfo);
+}
+
+int Clock::getTimezone() {
+    return timezone;
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/Clock.h	Tue Dec 02 17:22:43 2014 +0000
@@ -0,0 +1,30 @@
+#include "mbed.h"
+#include "NTPClient.h"
+
+// AM/PM
+const int AM = 0;
+const int PM = 12;
+
+// Timezones
+const int PST = -8;
+const int MST = -7;
+const int CST = -6;
+const int EST = -5;
+const int UTC = 0;
+
+class Clock {
+public:
+    Clock();
+    
+    void setTime(int hour, int minute, int period);
+    void setTimezone(int timezone);
+    
+    int syncTime();
+    
+    time_t getTime();
+    int getTimezone();
+private:
+    int timezone;    
+    
+    static bool isSet;
+};
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EthernetInterface.lib	Tue Dec 02 17:22:43 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/EthernetInterface/#de796e2a5e98
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NTPClient.lib	Tue Dec 02 17:22:43 2014 +0000
@@ -0,0 +1,1 @@
+http://developer.mbed.org/users/donatien/code/NTPClient/#881559865a93
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Dec 02 17:22:43 2014 +0000
@@ -0,0 +1,176 @@
+#include "mbed.h"
+#include "rtos.h"
+#include "EthernetInterface.h"
+#include "uLCD_4DGL.h"
+#include "Clock.h"
+#include <string>
+#include <sstream>
+#include <vector>
+
+uLCD_4DGL uLCD(p28,p27,p30);
+Serial pc(USBTX, USBRX);
+Mutex cMutex;
+Mutex sMutex;
+Clock clk;
+EthernetInterface eth;
+
+/**
+ * Function to get a command from the virtual serial connection.
+ * Will prompt the serial port for a command and read a command
+ * into a buffer and convert that buffer to a string object. This
+ * function should only be used while testing without a connection.
+ */
+string getCommand() {
+    char buffer[100];
+    char next = 0;
+    int i = 0;
+    sMutex.lock();
+    pc.printf("Enter a command: \n\r");
+    sMutex.unlock();
+    do {
+        sMutex.lock();
+        if (pc.readable()) {
+            next = pc.getc();
+            buffer[i++] = next;
+        }
+        sMutex.unlock();
+        Thread::wait(0.1);
+    } while (next != '\r');
+    
+    buffer[i] = '\0';
+    sMutex.lock();
+    pc.printf("Command entered: %s\n\r", buffer);
+    sMutex.unlock();
+    return string(buffer);
+}
+
+/**
+ * Function to take a string command and break it into tokens of words/numbers.
+ * These tokens will be added to the vector given as an argument and can then be 
+ * parsed to execute a command.
+ */
+vector<string>& splitCommand(const string &command, vector<string> &tokens) {
+    string buf;
+    stringstream ss(command);
+
+    while (ss >> buf)
+        tokens.push_back(buf);
+
+    return tokens;
+}
+
+/**
+ * Function to actually parse and execute a given command. If the command is not
+ * supported, an error function will be called to give feedback.
+ */
+void parseCommand(const vector<string> &tokens) {
+    sMutex.lock();
+    pc.printf("number of tokens: %d\n\r", tokens.size());
+    sMutex.unlock();
+
+    if (tokens.size() < 2) {
+        // error message
+        return;
+    }
+    
+    string operation = tokens[0];
+    string destination = tokens[1];
+    
+    if (operation == "set") {
+        if (destination == "time") {
+            int hour = atoi(tokens[2].c_str());
+            int minute = atoi(tokens[3].c_str());
+            int period = tokens.at(4) == "am" ? AM : PM;
+            cMutex.lock();
+            clk.setTime(hour, minute, period);
+            cMutex.unlock();
+        } else if (destination == "alarm") {
+            int hours = atoi(tokens[2].c_str());
+            int minutes = atoi(tokens[3].c_str());
+        } else if (destination == "timezone") {
+            int timezone = atoi(tokens[2].c_str());
+            cMutex.lock();
+            clk.setTimezone(timezone);
+            cMutex.unlock();
+        } else {
+            //return error message
+        }
+    } else if (operation == "sync") {
+        if (destination == "time") {
+
+            cMutex.lock();            
+            if (clk.syncTime() == 0) {
+                sMutex.lock();
+                pc.printf("Set time successfully\r\n");
+            } else {
+                sMutex.lock();
+                pc.printf("Error\r\n");
+            }
+            sMutex.unlock();
+            cMutex.unlock();
+        }
+        // return error message
+    }
+}
+
+/**
+ * Thread which updates the clock on the lcd while the main thread is waiting for 
+ * or executing a command.
+ */
+void lcdUpdateThread(void const *args) {
+    time_t time;
+    struct tm *timeinfo;
+    char buffer[20];
+    
+    // set initial time
+    cMutex.lock();
+    clk.syncTime();
+    clk.setTimezone(-5);
+    cMutex.unlock();
+    
+    // set lcd format
+    sMutex.lock();
+    uLCD.text_width(2);
+    uLCD.text_height(2);
+    uLCD.color(BLUE);
+    sMutex.unlock();
+    
+    while (1) {
+        cMutex.lock();
+        time = clk.getTime();
+        cMutex.unlock();
+        
+        timeinfo = localtime(&time);
+        strftime(buffer, 20, "%I:%M:%S        %p", timeinfo);
+        
+        sMutex.lock();
+        uLCD.locate(0,3);
+        uLCD.printf("%s", buffer);
+        sMutex.unlock();
+        Thread::wait(0.25);
+    }
+}
+
+/**
+ * main function which loops getting a command, parsing that command, and executing
+ * that command. It also starts a thread which updates the clock separate from the
+ * command execution.
+ */
+int main() {
+    vector<string> tokens;
+
+    eth.init();
+    eth.connect();
+    wait(5); // I don't know why you have to wait...
+
+    pc.printf("%s\n\r", eth.getIPAddress());
+    
+    Thread updateThread(lcdUpdateThread);
+
+    while (1) {
+        tokens.clear();
+        string command = getCommand();
+        splitCommand(command, tokens);
+        parseCommand(tokens);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-rtos.lib	Tue Dec 02 17:22:43 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed-rtos/#318e02f48146
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Tue Dec 02 17:22:43 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/031413cf7a89
\ No newline at end of file