SMS message display on LED Matrix board with printer option

Dependencies:   AdafruitThermalPrinter HT1632_LedMatrix VodafoneUSBModem mbed-rtos mbed

Files at this revision

API Documentation at this revision

Comitter:
SomeRandomBloke
Date:
Fri Jan 18 08:41:20 2013 +0000
Child:
1:243371cb92c8
Commit message:
Library updates

Changed in this revision

AdafruitThermalPrinter.lib Show annotated file Show diff for this revision Revisions of this file
HT1632_LedMatrix.lib Show annotated file Show diff for this revision Revisions of this file
VodafoneUSBModem.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/AdafruitThermalPrinter.lib	Fri Jan 18 08:41:20 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/SomeRandomBloke/code/AdafruitThermalPrinter/#871ca02007be
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/HT1632_LedMatrix.lib	Fri Jan 18 08:41:20 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/SomeRandomBloke/code/HT1632_LedMatrix/#0fac71b7ec1d
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/VodafoneUSBModem.lib	Fri Jan 18 08:41:20 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/VodafoneUSBModem/#07ac4e1ea5b0
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Fri Jan 18 08:41:20 2013 +0000
@@ -0,0 +1,468 @@
+/**
+ * Mbed SMS to Printer and LED Matrix Displays
+ * Based on SMS example from VodafoneUSBModem library and
+ * 3GReceiptPrinter app from Ashley Mills.
+ *
+ * Requires libraries:
+ * AdafruitThermalPrinter - Port of Arduino library by Ashley Mills
+ * VodafoneUSBModem - Driver for Vodafone K3370 Mobile Broadband dongle
+ * HT1632_LedMatrix - LED Matrix library by Andrew Lindsay, port of Arduino library by Andrew Lindsay
+ *
+ * @author Andrew Lindsay
+ *
+ * @section LICENSE
+ *
+ * Copyright (c) 2012 Andrew Lindsay (andrew [at] thiseldo [dot] co [dot] uk)
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ *
+ * @section DESCRIPTION
+ *  Display received SMS on scrolling LED matrix with optional output to thermal printer.
+ *
+ * TODO: Still have issue with restarts when using printer.
+ * mbed-rtos and serial problem?
+ *
+ */
+
+#define USE_LED
+#define USE_PRINTER
+
+#include <ctype.h>
+
+#include "mbed.h"
+#include "VodafoneUSBModem.h"
+//#include <LinkMonitor.h>
+
+#ifdef USE_LED
+#include "HT1632_LedMatrix.h"
+#endif
+#ifdef USE_PRINTER
+#include "AdafruitThermal.h"
+//#include "test.h"
+#endif
+
+#define DEBUG 1
+
+#ifdef USE_LED
+// Cound try to get own number usine USSD request
+#define INFO_MSG "       Send a message to 07765946942        "
+#endif
+
+// Vodafone USSD commands
+#define USSD_COMMAND_OWN_NUMBER "*#100#"
+#define USSD_COMMAND_BALANCE "*#134#"
+#define USSD_COMMAND_TIME "*#103#"
+
+
+#ifdef DEBUG
+//Serial pc(USBTX, USBRX); // tx, rx
+//Serial debug_pc(p13,p14); // tx, rx
+Serial debug_pc(USBTX, USBRX); // tx, rx
+#endif
+
+#ifdef USE_PRINTER
+AdafruitThermal printer(p28,p27);   // setup printer
+#endif
+// Define a maximum size for storage arrays, is 160 (SMS size) + a bit more.
+#define MAX_MSG_LENGTH 192
+
+// Month list used in converting to integer for set_time
+char months[12][4] = {"JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
+
+#ifdef USE_LED
+
+#define LED_MAX_DISPLAY_X 4
+#define LED_MAX_DISPLAY_Y 1
+
+// create object to control the LED Matrix
+HT1632_LedMatrix led = HT1632_LedMatrix();
+#define DISPDELAY 90
+#endif
+
+// Message buffers. New message waiting to be displayed and current message being displayed
+static char cmdBuf[12];
+static char newMsgBuf[MAX_MSG_LENGTH];
+static char msgBuf[MAX_MSG_LENGTH];
+
+#ifdef USE_LED
+int crtPos = 0;
+int msgx = 1;    // position on message screen of current character, set to 1 to allow for first scroll
+bool resetMessage = false;
+
+void matrixDemo( void );
+#endif
+
+// Define the onboard LEDs to use as status indicators
+DigitalOut led1(LED1);      // Activity
+DigitalOut led2(LED2);      // Activity, alternates with led2
+DigitalOut led3(LED3);      // SMS received, turns off after processed
+DigitalOut led4(LED4);      // USSD requested
+
+int threadRestartCount = 0;
+
+// Convert string buffer to upper case, is destructive. Buffer will be changed.
+char* stoupper( char* s )
+{
+    char* p = s;
+    while (*p = toupper( *p )) p++;
+    return s;
+}
+
+
+#ifdef USE_PRINTER
+void timestampMessage( char *msg )
+{
+    char timebuf[50];
+    // Print date/time, then message
+    time_t seconds = time(NULL);
+    strftime(timebuf, 50, "%d/%m/%Y %X\n", localtime(&seconds));
+    printer.print(timebuf);
+    printer.print(msg);
+    // linefeed a couple of times
+    printer.feed(3);
+}
+#endif
+
+#ifdef USE_LED
+// Load a new message
+void setNewMessage( char *newMsgStart )
+{
+    strncpy( newMsgBuf, newMsgStart, MAX_MSG_LENGTH );
+    resetMessage = true;
+}
+#endif
+
+void sendUSSDCommand( VodafoneUSBModem *_modem, char *ussdCommand, bool setScrolling )
+{
+    led4 = 1;
+#ifdef DEBUG
+    debug_pc.printf("Sending %s on USSD channel\n", ussdCommand);
+#endif
+    int ret = _modem->sendUSSD(ussdCommand, newMsgBuf, MAX_MSG_LENGTH);
+    // Check for correct response
+    if(ret) {
+        // Non 0 value indicates an error??
+#ifdef DEBUG
+        debug_pc.printf("Send USSD command returned %d\n", ret);
+#endif
+        led4 = 0;
+        return;
+    }
+
+    // Should only display message if one has been received.
+#ifdef DEBUG
+    debug_pc.printf("Result of command: %s\n", newMsgBuf);
+#endif
+
+    led4 = 0;
+
+#ifdef USE_LED
+    resetMessage = setScrolling;
+#endif
+}
+
+void setTime(VodafoneUSBModem *_modem )
+{
+    char numBuf[10];
+    // Set RTC using received message, format is DD-MMM-YYYY HH:MM
+    // Month is in text name, e.g. NOV, time is using 24 hour clock.
+    struct tm t;
+    int retryCount = 3;
+
+    while( retryCount ) {
+        sendUSSDCommand( _modem, USSD_COMMAND_TIME, false );
+
+#ifdef DEBUG
+        debug_pc.printf("Time received is %s\n", newMsgBuf);
+#endif
+
+        t.tm_sec = 0;    // 0-59
+        strncpy(numBuf, &newMsgBuf[15], 2 );
+        t.tm_min = atoi(numBuf);    // 0-59
+        strncpy(numBuf, &newMsgBuf[12], 2 );
+        t.tm_hour = atoi(numBuf);   // 0-23
+        strncpy(numBuf, &newMsgBuf[0], 2 );
+        t.tm_mday = atoi(numBuf);   // 1-31
+        strncpy(numBuf, &newMsgBuf[3], 3 );
+        t.tm_mon = 0;     // 0-11
+        for( int i=0; i<12; i++ ) {
+            if( strncmp( months[i], numBuf, 3 ) == 0 ) {
+                t.tm_mon = i;     // 0-11
+                break;
+            }
+        }
+        strncpy(numBuf, &newMsgBuf[9], 2 );
+        t.tm_year = 100 + atoi( numBuf );  // year since 1900
+
+        if( t.tm_year >110 ) {
+            // convert to timestamp and display
+            time_t seconds = mktime(&t);
+            set_time( seconds );
+            retryCount = 0;     // No more retries, terminate while
+        } else {
+            // Failed to set time, decrement tries
+            retryCount--;
+        }
+    }
+}
+
+
+void receiveSMS(void const*)
+{
+    VodafoneUSBModem modem;
+    time_t seconds = time(NULL);
+
+    threadRestartCount++;
+
+//    int pRssi = 0;
+//    setNewMessage( "Starting" );
+
+
+//    LinkMonitor::REGISTRATION_STATE pRegistrationState;
+//    LinkMonitor::BEARER pBearer;
+
+//    modem.getLinkState( &pRssi,&pRegistrationState, &pBearer);
+#ifdef DEBUG
+//    debug_pc.printf("Link state Rssi: %d, Registration state %x Bearer %x\n",pRssi,pRegistrationState, pBearer);
+#endif
+
+//    sprintf(msgBuf, "Link state Rssi: %d, Registration state %x Bearer %x      ",pRssi,pRegistrationState, pBearer);
+#ifdef USE_PRINTER
+    // Check if time already set, if not then get it. Use year = 0 as test
+    struct tm *t = localtime(&seconds);
+    if( t->tm_year == 0 ) {
+        setTime( &modem );
+    }
+
+    sprintf(newMsgBuf, "Thread Start %d\r\n", threadRestartCount );
+    timestampMessage( newMsgBuf );
+#endif
+#ifdef USE_LED
+    //strcpy( msgBuf, INFO_MSG );
+    setNewMessage( INFO_MSG );
+    
+    led.displayOn();
+#endif
+    char num[17];
+    size_t smsCount;
+
+    while(true) {
+        if( modem.getSMCount(&smsCount) ==OK ) {
+            if( smsCount > 0) {
+                led3 = 1;
+#ifdef DEBUG
+                debug_pc.printf("%d SMS to read\n", smsCount);
+#endif
+                if( modem.getSM(num, newMsgBuf, MAX_MSG_LENGTH) == OK ) {
+
+#ifdef DEBUG
+                    debug_pc.printf("%s : %s\n", num, newMsgBuf);
+#endif
+#ifdef USE_PRINTER
+// Print date/time, then message
+                    timestampMessage( newMsgBuf );
+#endif
+#ifdef USE_LED
+                    resetMessage = true;
+#endif
+                    strncpy( cmdBuf, newMsgBuf, 10 );
+                    stoupper( cmdBuf );  // This is a destructive function, original characters are uppercased
+                    if( strncmp( cmdBuf, "BALANCE", 7 ) == 0 ) {
+                        sendUSSDCommand( &modem, USSD_COMMAND_BALANCE, true );
+#ifdef USE_PRINTER
+                        timestampMessage( newMsgBuf );
+#endif
+#ifdef USE_LED
+                        resetMessage = true;
+                    } else if ( strncmp( cmdBuf, "INFO", 4 ) == 0 ) {
+                        setNewMessage( INFO_MSG );
+#endif
+//                  } else if ( strncmp( cmdBuf, "DEMO", 4 ) == 0 ) {
+//                      matrixDemo();
+//                      setNewMessage( INFO_MSG );
+#ifdef USE_LED
+                    } else if ( strncmp( cmdBuf, "CLEAR", 5 ) == 0 ) {
+                        setNewMessage( "      " );
+#endif
+                    }
+                }
+            }
+        }
+        Thread::wait(3000);
+        led3 = 0;
+    }
+}
+
+#ifdef USE_LED
+void displayScrollingLine(void const*)
+{
+    int y,xmax,ymax;
+    led.getXYMax(&xmax,&ymax);
+
+    while(true) {
+        // shift the whole screen 6 times, one column at a time; making 1 character
+        if( strlen( msgBuf ) > 10 ) {
+            for (int x=0; x < 6; x++) {
+                led.scrollLeft(1, 1);
+                msgx--;
+                // fit as much as we can on the available display space
+
+                while (!led.putChar(msgx,0,msgBuf[crtPos]))  { // zero return if it all fitted
+                    led.getXY(&msgx,&y);
+                    crtPos++; // we got all of the character on!!
+                    if (crtPos >= strlen(msgBuf)) {
+                        crtPos = 0;
+                    }
+                }
+                led.putShadowRam();
+                Thread::wait(DISPDELAY);
+            }
+        }
+        // Look for a new message being available
+        // TODO add minimum interval between message changes, e.g. 60s
+        if( resetMessage ) {
+            led.clear();
+            crtPos = 0;
+            msgx = 1;
+            strncpy( msgBuf, newMsgBuf, MAX_MSG_LENGTH );
+            if( strlen( msgBuf ) > 10 ) {
+                strcat( msgBuf, "          ");
+            } else {
+                led.putString(0,0, msgBuf);
+            }
+            resetMessage = false;
+        }
+    }
+}
+
+
+void matrixDemo( void )
+{
+    int xmax,ymax;
+    led.getXYMax(&xmax,&ymax);
+    led.clear();
+    for( int n=0; n<3; n++ ) {
+        for( int i=0; i<8; i++ ) {
+            led.drawRectangle(i,i,xmax-i,ymax-i, 1);
+            wait(0.05);
+        }
+        for( int i=7; i>=0; i-- ) {
+            led.drawRectangle(i,i,xmax-i,ymax-i, 0);
+            wait(0.05);
+        }
+    }
+    led.clear();
+    for( int n=0; n<3; n++ ) {
+        for(int i=0; i<(xmax/2); i++) {
+            led.drawCircle((xmax/2), 7, i, 1 );
+            wait( 0.05 );
+        }
+        for(int i=(xmax/2); i>=0; i--) {
+            led.drawCircle((xmax/2), 7, i, 0 );
+            wait( 0.05 );
+        }
+    }
+    wait(2);
+
+    led.clear();
+    led.init(2,1);    // Use displays 1 and 2 as 64x8 display
+}
+
+
+void showTime()
+{
+    time_t seconds = time(NULL);
+    char timebuf[20];
+    strftime(timebuf, 20, "%X   ", localtime(&seconds));
+    led.putString(12,8, timebuf );
+}
+
+void showDate()
+{
+    time_t seconds = time(NULL);
+    char timebuf[20];
+    strftime(timebuf, 20, "%d/%m/%Y   ", localtime(&seconds));
+    led.putString(4,8, timebuf );
+}
+#endif
+
+
+int main()
+{
+#ifdef DEBUG
+    debug_pc.baud(57600);
+#ifdef USE_LED
+    debug_pc.printf("SMS to LED Matrix display\n");
+#endif
+#ifdef USE_PRINTER
+    printer.begin();
+    debug_pc.printf("SMS To Printer\n");
+    timestampMessage("SMS To Printer Starting");
+#endif
+#endif
+#ifdef USE_LED
+    int displayCount = 10;
+    bool displayTime = true;
+
+    led.init(LED_MAX_DISPLAY_X,LED_MAX_DISPLAY_Y);    // Use displays 1 and 2 as 64x8 display
+    led.clear();
+    led.setBrightness(2);
+    //led.displayOff(); // Turn off display for now until receiver tast has started
+    bool twoLineDisplay = (LED_MAX_DISPLAY_X > 1);
+    led.putString( 0, 0, "SMS to LED Display" );
+
+    Thread::wait(3000);   // Wait for display to initialise after power up
+#endif
+
+    // Set initial blank message
+    strcpy( msgBuf, "          " );
+
+    Thread receiveTask(receiveSMS, NULL, osPriorityNormal, 1024 * 8);   // try 6 next
+#ifdef USE_LED
+    Thread displayTask(displayScrollingLine, NULL, osPriorityNormal, 1024 * 4);
+#endif
+
+    // Show we are still working by alternitively flashing LED1 adn LED2, once a second
+    led1 = 0;       // Working
+    led2 = 1;       // Alternate with led1
+    led3 = 0;       // Received and processign SMS
+    led4 = 0;       // Processing USSD message queue
+    while(1) {
+#ifdef USE_LED
+        // Only display date/time is we have a 2 row display
+        if( twoLineDisplay ) {
+            if( --displayCount <= 0 ) {
+                displayTime = !displayTime;
+                displayCount = 10;
+                led.putString(0,8, "            " );
+            }
+            if( displayTime ) {
+                showTime();
+            } else {
+                showDate();
+            }
+        }
+#endif
+        led1=!led1;
+        led2=!led2;
+        Thread::wait(1000);
+    }
+
+    return 0;
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-rtos.lib	Fri Jan 18 08:41:20 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed-rtos/#88a1a9c26ae3
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Fri Jan 18 08:41:20 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/3753e96f3c8b
\ No newline at end of file