Gerrod Ubben / Mbed 2 deprecated ECE4180_Final_Project

Dependencies:   mbed mbed-rtos 4DGL-uLCD-SE RPCInterface

Committer:
robo1340
Date:
Wed Dec 04 19:09:11 2019 +0000
Revision:
15:5120c88a7a87
Parent:
14:5b3f49d7bf19
Child:
16:d4b686118853
added comments to the code. Also added a chime that sounds whenever a notification is received

Who changed what in which revision?

UserRevisionLine numberNew contents of line
emilmont 1:491820ee784d 1 #include "mbed.h"
mbed_official 11:0309bef74ba8 2 #include "rtos.h"
robo1340 12:f1856a0b8ced 3
robo1340 12:f1856a0b8ced 4 #include "mbed_rpc.h"
robo1340 12:f1856a0b8ced 5 #include "uLCD_4DGL.h"
robo1340 14:5b3f49d7bf19 6 #include <time.h>
robo1340 14:5b3f49d7bf19 7 #include <math.h>
robo1340 15:5120c88a7a87 8 #include "chime.h"
robo1340 12:f1856a0b8ced 9
robo1340 13:f1649dc31b04 10 /* Example RPC commands that have currently been implemented
robo1340 13:f1649dc31b04 11
robo1340 15:5120c88a7a87 12 /notify/run This_is_a_notification_message_that_should_be_displayed_on_the_lcd
robo1340 14:5b3f49d7bf19 13 /setTime/run <unix time> <UTC offset (-5 for Atlanta)>
robo1340 14:5b3f49d7bf19 14 /setTime/run 1256729737 -5
robo1340 13:f1649dc31b04 15
robo1340 13:f1649dc31b04 16 */
robo1340 13:f1649dc31b04 17
robo1340 14:5b3f49d7bf19 18 volatile bool display_notification = false;
robo1340 14:5b3f49d7bf19 19 volatile bool display_time = true;
robo1340 14:5b3f49d7bf19 20
robo1340 14:5b3f49d7bf19 21 volatile int utc_offset; //keeps track of the current timezone of the watch
robo1340 14:5b3f49d7bf19 22
robo1340 12:f1856a0b8ced 23 uLCD_4DGL uLCD(p9,p10,p11); // serial tx, serial rx, reset pin;
robo1340 14:5b3f49d7bf19 24 //Serial bluetooth(p13,p14);
robo1340 12:f1856a0b8ced 25 Serial pc(USBTX, USBRX);
robo1340 12:f1856a0b8ced 26
robo1340 14:5b3f49d7bf19 27 InterruptIn view_button(p12);
robo1340 14:5b3f49d7bf19 28
robo1340 13:f1649dc31b04 29 Mutex stdio_mutex; //mutex used when accessing stdio functions
robo1340 14:5b3f49d7bf19 30 Mutex lcd_mutex; //mutex used when accessing the lcd object
robo1340 12:f1856a0b8ced 31
robo1340 13:f1649dc31b04 32 Thread bluetooth_thread; //thread responsible for receiving rpc commands over bluetooth
robo1340 13:f1649dc31b04 33 Thread time_thread; //thread responsible for updating the lcd with the current time
robo1340 12:f1856a0b8ced 34
robo1340 13:f1649dc31b04 35 //rpc function prototypes
robo1340 15:5120c88a7a87 36 void display_notification_rpc_func(Arguments *in, Reply *out);
robo1340 15:5120c88a7a87 37 void set_time_rpc_func (Arguments *in, Reply *out);
robo1340 15:5120c88a7a87 38 RPCFunction rpcWriteLCD(&display_notification_rpc_func, "notify");
robo1340 15:5120c88a7a87 39 RPCFunction rpcset_time_rpc_func(&set_time_rpc_func, "setTime");
robo1340 15:5120c88a7a87 40
robo1340 15:5120c88a7a87 41 #define sample_freq 16000.0
robo1340 15:5120c88a7a87 42 AnalogOut speaker(p18);
robo1340 15:5120c88a7a87 43 Ticker notification_chime_ticker;
robo1340 15:5120c88a7a87 44
robo1340 15:5120c88a7a87 45 //interrupt routine to play next audio sample from array in flash
robo1340 15:5120c88a7a87 46 void audio_sample () {
robo1340 15:5120c88a7a87 47 static int i=0;
robo1340 15:5120c88a7a87 48 speaker.write_u16(((uint16_t)data[i]<<7));
robo1340 15:5120c88a7a87 49 i++;
robo1340 15:5120c88a7a87 50 if (i>= sizeof(data)) {
robo1340 15:5120c88a7a87 51 i = 0;
robo1340 15:5120c88a7a87 52 notification_chime_ticker.detach();
robo1340 15:5120c88a7a87 53 }
robo1340 15:5120c88a7a87 54 }
robo1340 12:f1856a0b8ced 55
robo1340 14:5b3f49d7bf19 56 //interrupt routine for when the input button is pressed
robo1340 15:5120c88a7a87 57 //when the view button is pressed, dismiss the currently shown notification and display the current time
robo1340 14:5b3f49d7bf19 58 void view_button_pressed(void){
robo1340 14:5b3f49d7bf19 59 display_notification = false;
robo1340 14:5b3f49d7bf19 60 display_time = true;
robo1340 14:5b3f49d7bf19 61 }
robo1340 14:5b3f49d7bf19 62
robo1340 14:5b3f49d7bf19 63 //flip the y coordinate around so that standard cartesian coordinates can be used
robo1340 14:5b3f49d7bf19 64 int flipy(int y_coord){
robo1340 14:5b3f49d7bf19 65 return (128-y_coord);
robo1340 14:5b3f49d7bf19 66 }
robo1340 14:5b3f49d7bf19 67
robo1340 14:5b3f49d7bf19 68 #define C_X 64
robo1340 14:5b3f49d7bf19 69 #define C_Y 64
robo1340 14:5b3f49d7bf19 70 #define M_PI 3.141592
robo1340 14:5b3f49d7bf19 71 //create the tick marks for an analog clock on the lcd display
robo1340 14:5b3f49d7bf19 72 void setup_analog_clock(uint32_t color){
robo1340 14:5b3f49d7bf19 73
robo1340 14:5b3f49d7bf19 74 lcd_mutex.lock();
robo1340 14:5b3f49d7bf19 75 uLCD.filled_circle(64, 64, 5, color); //centercircle
robo1340 14:5b3f49d7bf19 76 double angle;
robo1340 14:5b3f49d7bf19 77 //start from 3 oclock and draw all the clock tick marks counter-clockwise
robo1340 14:5b3f49d7bf19 78 for(angle = 0; angle < (2*M_PI)-(M_PI/12); angle += M_PI/6){
robo1340 14:5b3f49d7bf19 79 uLCD.line(54*cos(angle)+C_X,flipy(54*sin(angle)+C_Y), 64*cos(angle)+C_X,flipy(64*sin(angle)+C_Y), color); //3 oclock tick mark
robo1340 14:5b3f49d7bf19 80 }
robo1340 14:5b3f49d7bf19 81 lcd_mutex.unlock();
robo1340 14:5b3f49d7bf19 82
robo1340 14:5b3f49d7bf19 83 }
robo1340 14:5b3f49d7bf19 84
robo1340 14:5b3f49d7bf19 85 #define RAD_PER_SEC (2*M_PI)/60
robo1340 14:5b3f49d7bf19 86 #define RAD_PER_MIN (2*M_PI)/60
robo1340 14:5b3f49d7bf19 87 #define RAD_PER_HOUR (2*M_PI)/12
robo1340 15:5120c88a7a87 88 //function to handle the display of the time on the lcd screen
robo1340 14:5b3f49d7bf19 89 void show_time_analog(int sec, int minute, int hour, int day, int month, int year, uint32_t sec_color, uint32_t min_color, uint32_t hour_color, uint32_t back_color) {
robo1340 14:5b3f49d7bf19 90 static double angle;
robo1340 14:5b3f49d7bf19 91 static int prev_sec;
robo1340 14:5b3f49d7bf19 92 static int prev_minute;
robo1340 14:5b3f49d7bf19 93 static int prev_hour;
robo1340 14:5b3f49d7bf19 94
robo1340 14:5b3f49d7bf19 95 lcd_mutex.lock();
robo1340 14:5b3f49d7bf19 96
robo1340 14:5b3f49d7bf19 97 //tear down the previous hands that were drawn
robo1340 14:5b3f49d7bf19 98 angle = -(RAD_PER_SEC*prev_sec) + M_PI/2;
robo1340 14:5b3f49d7bf19 99 uLCD.line(C_X,C_Y,64*cos(angle)+C_X, flipy(64*sin(angle)+C_Y),back_color);
robo1340 14:5b3f49d7bf19 100
robo1340 14:5b3f49d7bf19 101 angle = -(RAD_PER_MIN*prev_minute) + M_PI/2;
robo1340 14:5b3f49d7bf19 102 uLCD.line(C_X,C_Y,52*cos(angle)+C_X, flipy(52*sin(angle)+C_Y),back_color);
robo1340 14:5b3f49d7bf19 103
robo1340 14:5b3f49d7bf19 104 angle = -(RAD_PER_HOUR*prev_hour) + M_PI/2;
robo1340 14:5b3f49d7bf19 105 uLCD.line(C_X,C_Y,40*cos(angle)+C_X, flipy(40*sin(angle)+C_Y),back_color);
robo1340 14:5b3f49d7bf19 106
robo1340 14:5b3f49d7bf19 107 //draw the new hands
robo1340 14:5b3f49d7bf19 108 angle = -(RAD_PER_SEC*sec) + M_PI/2;
robo1340 14:5b3f49d7bf19 109 uLCD.line(C_X,C_Y,64*cos(angle)+C_X, flipy(64*sin(angle)+C_Y),sec_color);
robo1340 14:5b3f49d7bf19 110
robo1340 14:5b3f49d7bf19 111 angle = -(RAD_PER_MIN*minute) + M_PI/2;
robo1340 14:5b3f49d7bf19 112 uLCD.line(C_X,C_Y,52*cos(angle)+C_X, flipy(52*sin(angle)+C_Y),min_color);
robo1340 14:5b3f49d7bf19 113
robo1340 14:5b3f49d7bf19 114 angle = -(RAD_PER_HOUR*hour) + M_PI/2;
robo1340 14:5b3f49d7bf19 115 uLCD.line(C_X,C_Y,40*cos(angle)+C_X, flipy(40*sin(angle)+C_Y),hour_color);
robo1340 14:5b3f49d7bf19 116
robo1340 14:5b3f49d7bf19 117 stdio_mutex.lock();
robo1340 14:5b3f49d7bf19 118
robo1340 14:5b3f49d7bf19 119 //print the current date in a month/day/year format
robo1340 14:5b3f49d7bf19 120 uLCD.locate(4,10);
robo1340 14:5b3f49d7bf19 121 uLCD.printf("%2d/%2d/%4d",month, day, year);
robo1340 14:5b3f49d7bf19 122 uLCD.locate(8,11);
robo1340 14:5b3f49d7bf19 123 if (hour < 12) {uLCD.printf("AM");}
robo1340 14:5b3f49d7bf19 124 else {uLCD.printf("PM");}
robo1340 14:5b3f49d7bf19 125
robo1340 14:5b3f49d7bf19 126 stdio_mutex.unlock();
robo1340 14:5b3f49d7bf19 127 lcd_mutex.unlock();
robo1340 14:5b3f49d7bf19 128
robo1340 14:5b3f49d7bf19 129 //store the location of the current hands
robo1340 14:5b3f49d7bf19 130 prev_sec = sec;
robo1340 14:5b3f49d7bf19 131 prev_minute = minute;
robo1340 14:5b3f49d7bf19 132 prev_hour = hour;
robo1340 14:5b3f49d7bf19 133 }
robo1340 12:f1856a0b8ced 134
robo1340 15:5120c88a7a87 135 //function to update the time displayed on the lcd approximately every second
robo1340 12:f1856a0b8ced 136 void time_thread_func() {
robo1340 14:5b3f49d7bf19 137 struct tm * t; //time struct defined in time.h
robo1340 15:5120c88a7a87 138 static time_t unix_time; //the time in unix time
robo1340 15:5120c88a7a87 139 static bool prev_display_time; //indicates whether time was being displayed the last time the thread ran
robo1340 14:5b3f49d7bf19 140
robo1340 12:f1856a0b8ced 141 while (true) {
robo1340 14:5b3f49d7bf19 142 if (display_time == true) {
robo1340 14:5b3f49d7bf19 143 if (prev_display_time == false){ //clear whatever was previously on the screen
robo1340 14:5b3f49d7bf19 144 lcd_mutex.lock();
robo1340 14:5b3f49d7bf19 145 uLCD.cls();
robo1340 14:5b3f49d7bf19 146 lcd_mutex.unlock();
robo1340 14:5b3f49d7bf19 147 }
robo1340 14:5b3f49d7bf19 148 unix_time = time(NULL);
robo1340 14:5b3f49d7bf19 149 t = localtime(&unix_time);
robo1340 14:5b3f49d7bf19 150
robo1340 14:5b3f49d7bf19 151 setup_analog_clock(WHITE);
robo1340 14:5b3f49d7bf19 152 int hour = (t->tm_hour + utc_offset);
robo1340 14:5b3f49d7bf19 153 if (hour < 0){ hour += 24;}
robo1340 15:5120c88a7a87 154 else if (hour >= 24) {hour -= 24;}
robo1340 14:5b3f49d7bf19 155 show_time_analog(t->tm_sec,t->tm_min,hour,t->tm_mday,t->tm_mon+1,t->tm_year+1900,RED+BLUE,WHITE,BLUE,BLACK);
robo1340 14:5b3f49d7bf19 156 }
robo1340 14:5b3f49d7bf19 157 prev_display_time = display_time;
robo1340 12:f1856a0b8ced 158
robo1340 12:f1856a0b8ced 159 Thread::wait(1000); //only update every second
robo1340 12:f1856a0b8ced 160 }
robo1340 12:f1856a0b8ced 161
robo1340 12:f1856a0b8ced 162 }
robo1340 12:f1856a0b8ced 163
robo1340 15:5120c88a7a87 164 //function to continuously take in characters over bluetooth serial and parse them as RPC commands
robo1340 12:f1856a0b8ced 165 void bluetooth_thread_func() {
robo1340 12:f1856a0b8ced 166 char buf[256], outbuf[256];
robo1340 12:f1856a0b8ced 167 uint16_t buf_pos = 0;
robo1340 12:f1856a0b8ced 168
robo1340 12:f1856a0b8ced 169 while(true) {
robo1340 12:f1856a0b8ced 170
robo1340 13:f1649dc31b04 171 if (pc.readable() == true) { //comment out when using bluetooth to receive rpc commands
robo1340 12:f1856a0b8ced 172 //if (bluetooth.readable() == true) {
robo1340 12:f1856a0b8ced 173
robo1340 12:f1856a0b8ced 174 stdio_mutex.lock();
robo1340 12:f1856a0b8ced 175
robo1340 13:f1649dc31b04 176 buf[buf_pos] = pc.getc(); //comment out when using bluetooth to receive rpc commands
robo1340 12:f1856a0b8ced 177 //buf[buf_pos] = bluetooth.getc();
robo1340 12:f1856a0b8ced 178
robo1340 12:f1856a0b8ced 179 stdio_mutex.unlock();
robo1340 12:f1856a0b8ced 180
robo1340 12:f1856a0b8ced 181 if (buf[buf_pos] == '\n') { //the end of the RPC command has been received
robo1340 15:5120c88a7a87 182 buf[buf_pos] = '\0'; //replace the newline character with a null character
robo1340 12:f1856a0b8ced 183 buf_pos = 0;
robo1340 12:f1856a0b8ced 184 RPC::call(buf, outbuf); //make an RPC call
robo1340 12:f1856a0b8ced 185
robo1340 12:f1856a0b8ced 186 stdio_mutex.lock();
robo1340 12:f1856a0b8ced 187 pc.printf("%s\n", outbuf); //send the response
robo1340 12:f1856a0b8ced 188 stdio_mutex.unlock();
robo1340 12:f1856a0b8ced 189 }
robo1340 12:f1856a0b8ced 190 else {
robo1340 12:f1856a0b8ced 191 buf_pos++;
robo1340 12:f1856a0b8ced 192 }
robo1340 12:f1856a0b8ced 193
robo1340 12:f1856a0b8ced 194 } else {
robo1340 12:f1856a0b8ced 195 Thread::yield();
robo1340 12:f1856a0b8ced 196 }
robo1340 12:f1856a0b8ced 197
emilmont 1:491820ee784d 198 }
emilmont 1:491820ee784d 199 }
robo1340 12:f1856a0b8ced 200
robo1340 15:5120c88a7a87 201 //RPC function to receive the current time
robo1340 15:5120c88a7a87 202 //the first argument is unix time and the second argument is the offset from UTC time
robo1340 15:5120c88a7a87 203 void set_time_rpc_func (Arguments *in, Reply *out) {
robo1340 12:f1856a0b8ced 204 static const char * unix_time_str;
robo1340 12:f1856a0b8ced 205 uint32_t unix_time;
robo1340 14:5b3f49d7bf19 206 int offset;
robo1340 12:f1856a0b8ced 207 unix_time_str = in->getArg<const char*>(); //get a pointer to the location where the argument string is stored
robo1340 15:5120c88a7a87 208 offset = in->getArg<int>(); //get the second argument which indicates the offeset (in hours) from UTC time
robo1340 12:f1856a0b8ced 209 unix_time = atoll(unix_time_str);
robo1340 14:5b3f49d7bf19 210 utc_offset = offset;
robo1340 12:f1856a0b8ced 211
robo1340 12:f1856a0b8ced 212 set_time(unix_time); // Set RTC time to Wed, 28 Oct 2009 11:35:37
emilmont 1:491820ee784d 213
emilmont 1:491820ee784d 214 }
robo1340 12:f1856a0b8ced 215
robo1340 12:f1856a0b8ced 216
robo1340 15:5120c88a7a87 217 //RPC function to receive notification strings
robo1340 15:5120c88a7a87 218 //note notification strings should not contain the character ' ', in lieu
robo1340 15:5120c88a7a87 219 //they should contain '_' to indicate spaces
robo1340 15:5120c88a7a87 220 void display_notification_rpc_func (Arguments *in, Reply *out) {
robo1340 14:5b3f49d7bf19 221 static char display_str[18];
robo1340 12:f1856a0b8ced 222 static const char * msg_str;
robo1340 14:5b3f49d7bf19 223 int i,j;
robo1340 14:5b3f49d7bf19 224 bool break_out = false;
robo1340 14:5b3f49d7bf19 225
robo1340 14:5b3f49d7bf19 226 display_notification = true;
robo1340 14:5b3f49d7bf19 227 display_time = false;
robo1340 12:f1856a0b8ced 228
robo1340 12:f1856a0b8ced 229 msg_str = in->getArg<const char*>(); //get a pointer to the location where the argument string is stored
robo1340 12:f1856a0b8ced 230
robo1340 12:f1856a0b8ced 231 stdio_mutex.lock();
robo1340 12:f1856a0b8ced 232 lcd_mutex.lock();
robo1340 12:f1856a0b8ced 233
robo1340 14:5b3f49d7bf19 234 uLCD.cls();
robo1340 14:5b3f49d7bf19 235 uLCD.locate(0,0);
robo1340 14:5b3f49d7bf19 236 i = 0;
robo1340 14:5b3f49d7bf19 237 while(true){
robo1340 14:5b3f49d7bf19 238 for(j=0; j<18; j++){
robo1340 14:5b3f49d7bf19 239 if (msg_str[i+j] == '_'){
robo1340 14:5b3f49d7bf19 240 display_str[j] = ' ';
robo1340 14:5b3f49d7bf19 241 } else {
robo1340 14:5b3f49d7bf19 242 display_str[j] = msg_str[i+j];
robo1340 14:5b3f49d7bf19 243 }
robo1340 14:5b3f49d7bf19 244 if (msg_str[i+j] == '\0') {break_out = true; break;}
robo1340 14:5b3f49d7bf19 245 }
robo1340 14:5b3f49d7bf19 246 i+= 18;
robo1340 14:5b3f49d7bf19 247 uLCD.printf("%s\r\n",display_str);
robo1340 14:5b3f49d7bf19 248 if (break_out){break;}
robo1340 14:5b3f49d7bf19 249 }
robo1340 12:f1856a0b8ced 250
robo1340 12:f1856a0b8ced 251 stdio_mutex.unlock();
robo1340 12:f1856a0b8ced 252 lcd_mutex.unlock();
robo1340 12:f1856a0b8ced 253
robo1340 15:5120c88a7a87 254 notification_chime_ticker.attach(&audio_sample, 1.0/sample_freq);
robo1340 15:5120c88a7a87 255
robo1340 12:f1856a0b8ced 256 }
robo1340 15:5120c88a7a87 257
robo1340 15:5120c88a7a87 258 int main() {
robo1340 15:5120c88a7a87 259
robo1340 15:5120c88a7a87 260 uLCD.baudrate(3000000); //increase the lcd baud rate
robo1340 15:5120c88a7a87 261
robo1340 15:5120c88a7a87 262 //configure the input button and attach an interrupt routine to it
robo1340 15:5120c88a7a87 263 view_button.mode(PullUp);
robo1340 15:5120c88a7a87 264 view_button.fall(&view_button_pressed);
robo1340 15:5120c88a7a87 265
robo1340 15:5120c88a7a87 266
robo1340 15:5120c88a7a87 267 bluetooth_thread.start(bluetooth_thread_func); //start the thread that takes in characters to construct RPC commands
robo1340 15:5120c88a7a87 268 time_thread.start(time_thread_func); //start the thread that updates the displayed time
robo1340 15:5120c88a7a87 269
robo1340 15:5120c88a7a87 270 }