Example showing the ublox Cellular GPS/GNSS module with the online PubNub service on an LPC4088 Experiment Base Board. This example uses an RTOS.

Dependencies:   C027_Support EALib LM75B PubNub mbed-rtos mbed picojson

Files at this revision

API Documentation at this revision

Comitter:
embeddedartists
Date:
Wed Oct 01 11:39:10 2014 +0000
Commit message:
First version

Changed in this revision

C027_Support.lib Show annotated file Show diff for this revision Revisions of this file
EALib.lib Show annotated file Show diff for this revision Revisions of this file
LM75B.lib Show annotated file Show diff for this revision Revisions of this file
PubNub.lib Show annotated file Show diff for this revision Revisions of this file
PubNubDemo.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
picojson.lib Show annotated file Show diff for this revision Revisions of this file
pubnub_acc.html Show annotated file Show diff for this revision Revisions of this file
diff -r 000000000000 -r 713518ea5028 C027_Support.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/C027_Support.lib	Wed Oct 01 11:39:10 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/teams/ublox/code/C027_Support/#f524fd9aa13d
diff -r 000000000000 -r 713518ea5028 EALib.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/EALib.lib	Wed Oct 01 11:39:10 2014 +0000
@@ -0,0 +1,1 @@
+https://mbed.org/users/embeddedartists/code/EALib/#b3a179cc3d88
diff -r 000000000000 -r 713518ea5028 LM75B.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/LM75B.lib	Wed Oct 01 11:39:10 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/neilt6/code/LM75B/#7ac462ba84ac
diff -r 000000000000 -r 713518ea5028 PubNub.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PubNub.lib	Wed Oct 01 11:39:10 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/embeddedartists/code/PubNub/#55eb53c78b47
diff -r 000000000000 -r 713518ea5028 PubNubDemo.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/PubNubDemo.cpp	Wed Oct 01 11:39:10 2014 +0000
@@ -0,0 +1,313 @@
+#include <cstring>
+
+#include "mbed.h"
+#include "rtos.h"
+//#include "C12832.h"
+//#include "MMA7660.h"
+#include "MMA7455.h"
+#include "LM75B.h"
+
+#include "picojson.h"
+#include "PubNub.h"
+
+#include "sdram.h"
+
+//------------------------------------------------------------------------------------
+// You need to configure these cellular modem / SIM parameters.
+// These parameters are ignored for LISA-C200 variants and can be left NULL.
+//------------------------------------------------------------------------------------
+#include "MDM.h"
+//! Set your secret SIM pin here (e.g. "1234"). Check your SIM manual.
+#define SIMPIN      NULL
+/*! The APN of your network operator SIM, sometimes it is "internet" check your 
+    contract with the network operator. You can also try to look-up your settings in 
+    google: https://www.google.de/search?q=APN+list */
+#define APN         "online.telia.se"
+//! Set the user name for your APN, or NULL if not needed
+#define USERNAME    NULL
+//! Set the password for your APN, or NULL if not needed
+#define PASSWORD    NULL 
+//------------------------------------------------------------------------------------
+
+/* Demo of PubNub + the mbed application board. */
+
+/* How to get things set up: */
+/* 1. Tune in at the PubNub Developer Console, with the following
+ * keys (press Subscribe afterwards): */
+const char pubkey[] = "demo";
+const char subkey[] = "demo";
+//const char channel[] = "mbed";
+const char channel_pub[] = "mbed_data";
+const char channel_sub[] = "mbed_cmd";
+/* 2. Attach your mbed board to your computer. A folder should pop up like
+ * if you plug in a USB memory stick. */
+/* 3. Open this example in the mbed web IDE and hit the Compile button. */
+/* 4. A download popup with a .bin file will appear; save it in the USB
+ * mbed folder. */
+/* 5. Press reset button on the mbed to start things up. */
+
+/* You will see the board publish a "status" message that shows its
+ * current temperature and physical tilt.  The board's LCD should
+ * print some progress messages regarding that. */
+/* You can make the board do things too, by sending messages like:
+ * { "send_status": true }
+ * { "lcd": "Hi there!" }
+ * { "beep": true }
+ * { "led": {"r": 0.5, "g": 1, "b": 0} }
+ * Try it out! Paste these in the Message window and press the send icon.
+ */
+
+Serial pc(USBTX, USBRX); // tx, rx
+//MMA7660 MMA(P0_27, P0_28);
+MMA7455 MMA(P0_27, P0_28);
+LM75B tmp(P0_27, P0_28, LM75B::ADDRESS_1);
+//C12832 lcd(D11, D13, D12, D7, D10);
+
+PwmOut led_r(p25); // RGB LED with 3 PWM outputs for dimmer control
+PwmOut led_g(p28);
+PwmOut led_b(p26);
+//PwmOut speaker(D6); // Speaker with PWM driver
+
+DigitalOut led1(LED1);
+DigitalOut led2(LED2);
+DigitalOut led3(LED3);
+DigitalOut led4(LED4);
+
+
+bool forceStatusUpdate = true;
+
+Mutex stdio_mutex; 
+
+#define safe_printf(...) do { \
+        stdio_mutex.lock(); \
+        pc.printf(__VA_ARGS__); \
+        stdio_mutex.unlock(); \
+    } while(0)
+
+#define safe_print_pnub_err(__prefix) do { \
+        stdio_mutex.lock(); \
+        if (pnub_err) { \
+            pc.printf("%s: ERR, code = %d, line = %d\n", (__prefix), pnub_code, pnub_line); \
+            pnub_err = false; \
+        } \
+        stdio_mutex.unlock(); \
+    } while(0)
+
+void pnub_err_handler(PubNubRes code, int line) {
+    stdio_mutex.lock();
+    if (code != PNR_OK) {
+        pc.printf("PbuNub:%d  ERROR %d\n", line, code);
+    }
+    stdio_mutex.unlock();
+}
+
+void process_msg(PubNub &pn, const char *jsonmsg)
+{
+    /* Use the picojson parser since we want to deal with complex messages.
+     * If you are short on memory, you can find an example for parsing simple
+     * JSON messages in the PubNub::subscribe() API docs. */
+    picojson::value msg;
+    std::string err = picojson::parse(msg, jsonmsg, jsonmsg + strlen(jsonmsg));
+    do {
+        if (!err.empty()) {
+            safe_printf("JSON parse: %s  \n", err.c_str());
+            break;
+        }
+    
+        if (msg.get("send_status").get<bool>()) {
+            //status_msg(pn);
+            forceStatusUpdate = true;
+            safe_printf("force_update\n");
+            break;
+        }
+        if (msg.get("lcd").is<std::string>()) {
+            safe_printf("in: %s  \n", msg.get("lcd").get<std::string>().c_str());
+            break;
+        }
+        if (msg.get("beep").is<bool>()) {
+            //speaker = msg.get("beep").get<bool>() ? 0.5 : 0;
+            break;
+        }
+        if (msg.get("led").is<picojson::object>()) {
+            picojson::value led = msg.get("led");
+            safe_printf("Old RGB { %.3f, %.3f, %.3f }\n", led_r.read(), led_g.read(), led_b.read());
+            if (led.get("r").is<double>()) led_r = 1.0 - led.get("r").get<double>();
+            if (led.get("g").is<double>()) led_g = 1.0 - led.get("g").get<double>();
+            if (led.get("b").is<double>()) led_b = 1.0 - led.get("b").get<double>();
+            safe_printf("New RGB { %.3f, %.3f, %.3f }\n", led_r.read(), led_g.read(), led_b.read());
+            break;
+        }
+    } while(0);
+}
+
+void publish_thread(void const *args)
+{
+    PubNub pn(pubkey, subkey);
+    Timer t;
+    t.start();
+    Timer tDbg;
+    int nDbg = 0;
+    float lastTemp = -3.75f;
+    while (true) {
+            
+        /* Read sensors. */
+        int m[3];
+        MMA.read(m[0], m[1], m[2]);
+        float temp = (float)tmp;
+    
+        /* Print on LCD. */
+        safe_printf("cur: mx=%3d, my=%3d, mz=%3d, t=%.2f  \n", m[0], m[1], m[2], temp);
+    
+        if (forceStatusUpdate || (temp != lastTemp)) {
+            lastTemp = temp;
+            forceStatusUpdate = false;
+            
+            /* Prepare JSON message. */
+            char jsonmsg[128];
+//            snprintf(jsonmsg, sizeof(jsonmsg),
+//                    "{\"status\":{\"mx\":%3d,\"my\":%3d,\"mz\":%3d,\"temp\":%.2f}}",
+//                    m[0], m[1], m[2], temp);
+            snprintf(jsonmsg, sizeof(jsonmsg),
+                    "%%7B%%22status%%22:%%7B%%22mx%%22:%3d,%%22my%%22:%3d,%%22mz%%22:%3d,%%22temp%%22:%.2f%%7D%%7D",
+                    m[0], m[1], m[2], temp);
+
+            /* Publish on PubNub. */
+            safe_printf("before publishing\n");
+            led_r = 0;
+            tDbg.start();
+//            PubNubRes ret = pn.publish(channel_pub, jsonmsg);
+            PubNubRes ret = pn.publish_urlenc(channel_pub, jsonmsg);
+            tDbg.stop();
+            if (++nDbg == 10) {
+                safe_printf("10 requests took %d ms, i.e %d ms/req\n", tDbg.read_ms(), tDbg.read_ms()/10);
+                tDbg.reset();
+                nDbg = 0;
+            }
+
+            if (ret != PNR_OK) {
+                safe_printf("puberr: %d  \n", ret);
+                //safe_print_pnub_err("pub");
+                forceStatusUpdate = true; // so that we can try again
+            }
+            led_r = 1;
+            safe_printf("after publishing\n");
+        }
+        
+        wait_ms(100);
+    }
+}
+
+void subscribe_thread(void const *args)
+{
+    PubNub pn(pubkey, subkey);
+    while(true) {
+        char *reply = NULL;
+        PubNubRes ret = pn.subscribe(channel_sub, &reply);
+        if (ret != PNR_OK) {
+            safe_printf("suberr: %d  \n", ret);
+            //safe_print_pnub_err("sub");
+            wait(1.0);
+            continue;
+        }
+
+        if (reply) {
+            safe_printf("recv(%s)\n", reply);
+            process_msg(pn, reply);
+        }
+
+        wait(0.5); // avoid busy loop in bad situations
+    }
+}
+
+/** Cause the mbed to flash the BLOD (Blue LEDs Of Death) sequence
+ */
+void mbed_die(void)
+{
+    led1 = led2 = 1; led3 = led4 = 0;  // lights out
+    while(1) {
+        led1 = 1;
+        led3 = 1;
+        wait_ms(100);
+        led2 = 1;
+        led1 = 0;
+        wait_ms(100);
+        led4 = 0;
+        led2 = 0;
+        wait_ms(100);
+        led3 = 0;
+        led4 = 1;
+        wait_ms(100);
+    }
+}
+
+int main()
+{
+    if (sdram_init()) {
+        pc.printf("Failed to initialize SDRAM\n");
+    }
+    
+    /* For debugging, you may find it useful to print memory usage
+     * stats. AvailableMemory may be flaky, but the following is nice.
+     * It will get printed to the USB serial port interface. */
+    //printf("%d: ", __LINE__); __heapstats((__heapprt)fprintf, stdout);
+
+    /* Generate a 800Hz tone using PWM hardware output */
+    //speaker.period(1.0/800.0); // 800hz period
+    led_r = led_g = led_b = 1.0; // lights out
+    led1 = led2 = 1; led3 = led4 = 0;  // lights out
+
+    //lcd.cls();
+    //lcd.locate(0,0);
+    
+    if (!tmp.open()) {
+        pc.printf("Failed to open LM75 temperature sensor\n");
+    }
+
+//    if (!MMA.testConnection())
+//        pc.printf("MMA error  \n");
+
+    // Initialize the accelerometer
+    if (!MMA.setMode(MMA7455::ModeMeasurement)) {
+        printf("Unable to set mode for MMA7455!\n");
+    }
+
+    // Calibrate it. It does not matter if it is on a level surface
+    // as this test is only interested in relative values.
+    if (!MMA.calibrate()) {
+        printf("Failed to calibrate MMA7455!\n");
+    }
+
+    MDMRtos<MDMSerial> mdm;
+    //mdm.setDebug(4); // enable this for debugging issues 
+    int i;
+    for (i = 1; i <= 10; i++) {
+        if (mdm.connect(SIMPIN, APN,USERNAME,PASSWORD)) {
+            printf("Connected\n");
+            mdm.setDebug(0); // disable debug again
+            break;
+        } else {
+            printf("Attempt %2d to connect to the modem FAILED.\n", i);
+            wait(1);
+            mdm.setDebug(min(i, 4)); // to add more and more debug output
+        }
+    }
+    if (i > 10) {
+        printf("Failed to connect to the modem\n");
+        mbed_die();
+    }
+    
+    forceStatusUpdate = true;
+    //status_msg(pn);
+    // lcd.printf("pub... ");
+
+    Thread t_p(publish_thread);
+    Thread t_s(subscribe_thread);
+
+    while (1) {
+        Thread::wait(2000);
+        safe_printf(".\n");
+    }
+
+    mdm.disconnect();
+    mdm.powerOff();
+}
diff -r 000000000000 -r 713518ea5028 mbed-rtos.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed-rtos.lib	Wed Oct 01 11:39:10 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed-rtos/#631c0f1008c3
diff -r 000000000000 -r 713518ea5028 mbed.bld
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.bld	Wed Oct 01 11:39:10 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/builds/552587b429a1
\ No newline at end of file
diff -r 000000000000 -r 713518ea5028 picojson.lib
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/picojson.lib	Wed Oct 01 11:39:10 2014 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mimil/code/picojson/#2bb500b021e2
diff -r 000000000000 -r 713518ea5028 pubnub_acc.html
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/pubnub_acc.html	Wed Oct 01 11:39:10 2014 +0000
@@ -0,0 +1,186 @@
+<html>
+	<head>
+<!--		<script type="text/javascript" src="jscolor/jscolor.js"></script>-->
+		<script type="text/javascript" src="https://www.google.com/jsapi"></script>
+    <script type="text/javascript">
+	  var baseline = Math.round(new Date().getTime()/10); // current time as integer in 10ms resolution
+	  var temps = [['Time', 'Temp']];
+	  var accs = [['Time', 'X', 'Y', 'Z']];
+      google.load("visualization", "1", {packages:["corechart"]});
+      //google.setOnLoadCallback(drawChart);
+      function drawChart() {
+        /*var data = google.visualization.arrayToDataTable([
+          ['Year', 'Sales', 'Expenses'],
+          ['2004',  1000,      400],
+          ['2005',  1170,      460],
+          ['2006',  660,       1120],
+          ['2007',  1030,      540]
+        ]);*/
+		var data = google.visualization.arrayToDataTable(temps);
+
+        var options = {
+          title: 'Temperature over time',
+		  vAxis: { title: "Degrees C" },
+		  hAxis: { title: "Time since first message (in seconds)" },
+		  curveType: 'function',
+		  legend: { position: 'none' },
+        };
+
+        var chart = new google.visualization.LineChart(document.getElementById('chart_div'));
+
+        chart.draw(data, options);
+
+		// Acc chart
+		var data = google.visualization.arrayToDataTable(accs);
+
+        var options = {
+          title: 'Acceleration over time',
+		  vAxis: { title: "Acc value", minValue: -60, maxValue: 60 },
+		  hAxis: { title: "Time since first message (in seconds)" },
+		  curveType: 'function',
+		  //legend: { position: 'none' },
+        };
+
+        var chart = new google.visualization.LineChart(document.getElementById('acc_chart_div'));
+
+        chart.draw(data, options);
+      }
+	  function addToChart(t, x, y, z) {
+	    var now = Math.round(new Date().getTime()/10); // current time as integer in 10ms resolution
+	    console.log(new Date().getTime()/10 + " " + (now - baseline) + " temp = " + t+ " acc {"+x+","+y+","+z+"}");
+	    temps[temps.length] = [ (now - baseline)/100, t ];
+	    accs[accs.length] = [ (now - baseline)/100, x, y, z];
+		drawChart();
+	  }
+    </script>
+   <script src=http://cdn.pubnub.com/pubnub.min.js ></script>
+   <script>
+	 var pubnub = PUBNUB.init({
+		publish_key: 'pub-c-e4a8b6d6-7be2-4ef9-85b9-f6dfbed23f7d',
+		subscribe_key: 'sub-c-83ad9d3a-3365-11e4-9846-02ee2ddab7fe'
+	 });
+ 
+	function receiveMessage(message) {
+		//console.log(message);
+
+		var type = 0;
+		try {
+			var test = message.status.mx;
+			type = 1;
+		} catch (err) {
+			// not a measurement status message from HW
+		}
+		try {
+			var test = message.led.r;
+			type = 2;
+		} catch (err) {
+			// not a set RGB color request from us
+		}
+		
+		var messageLog = document.getElementById("messageLog");
+		if (type == 1) {			
+			var listItem = document.createElement("li");
+			var msg = "Acc X,Y,Z = {" + message.status.mx + ", " + message.status.my + ", " + message.status.mz + "} Temp = " + message.status.temp;
+			var text = document.createTextNode(msg);
+			listItem.appendChild(text);
+			document.getElementById("messageList").appendChild(listItem);
+			messageLog.scrollTop = messageLog.scrollHeight;			
+			addToChart(message.status.temp, message.status.mx, message.status.my, message.status.mz);
+		} else if (type == 2) {
+			var listItem = document.createElement("li");
+			var msg = "Set RGB LED: {" + message.led.r + ", " + message.led.g + ", " + message.led.b + "}";
+			var text = document.createTextNode(msg);
+			listItem.appendChild(text);
+			document.getElementById("messageList").appendChild(listItem);
+			messageLog.scrollTop = messageLog.scrollHeight;			
+			//addToChart(message.status.temp);
+		} else {
+			// got an error, probably because message is not from mbed
+			var listItem = document.createElement("li");
+			var msg = "Unknwon RAW message: " + message;
+			var text = document.createTextNode(msg);
+			listItem.appendChild(text);
+			document.getElementById("messageList").appendChild(listItem);
+			messageLog.scrollTop = messageLog.scrollHeight;			
+			//addToChart(message.status.temp);
+		}
+	}
+	
+	/*function sendMessage(newcolor) {
+		//var r = parseInt(newcolor.substr(0,2), 16)/255;
+		//var g = parseInt(newcolor.substr(2,2), 16)/255;
+		//var b = parseInt(newcolor.substr(4,2), 16)/255;
+		//var msg = '{ "led": {"r": ' + r + ', "g": ' + g + ', "b": ' + b + '} }';
+		//var msg = '{ "led": {"r": ' + newcolor.rgb[0] + ', "g": ' + newcolor.rgb[1] + ', "b": ' + newcolor.rgb[2] + '} }';
+		var msg = { "led": {"r": newcolor.rgb[0], "g": newcolor.rgb[1], "b": newcolor.rgb[2]} };
+		console.log("new color #" + newcolor + " => message " + msg.led.r+","+msg.led.g+","+msg.led.b);
+		pubnub.publish({
+			channel: 'mbed_cmd',//'hello_world',
+			message: msg
+		});
+	}*/
+	function sendColorMessage(r,g,b) {
+		var msg = { "led": {"r": r, "g": g, "b": b} };
+		console.log("message " + msg.led.r+","+msg.led.g+","+msg.led.b);
+		pubnub.publish({
+			channel: 'mbed_cmd',//'hello_world',
+			message: msg
+		});
+	}
+ 
+	 pubnub.subscribe({
+		channel: 'mbed_data',//'hello_world',
+		message: receiveMessage
+	 });
+ 
+/* pubnub.unsubscribe({
+    channel: 'a',
+    message: function(m){console.log(m)}
+ });*/
+   </script>
+		<style>
+			li { font-style: monospace; }
+			table,tr {border: none; }
+		</style>
+	</head>
+   <body>
+   <!--<img src="http://www.pubnub.com/static/images/illustrations/cloud-red.png">-->
+   
+   <table>
+   <tr>
+	<td valign="top">
+		<table>
+			<tr valign="top">
+				<td><div id="chart_div" style="width: 800px; height: 400px;"></div></td>
+			</tr>
+			<tr valign="top">
+				<td><div id="acc_chart_div" style="width: 800px; height: 400px;"></div></td>
+			</tr>
+			<!--<tr valign="top">
+				<td>Change color on RGB LED to:&nbsp;&nbsp;&nbsp;<input class="color" onchange="sendMessage(this.color)"></td>
+			</tr>-->
+			<tr valign="top">
+				<td>
+					<input type="button" value="Set color to RED" onclick="sendColorMessage(1,0,0)">
+					<input type="button" value="Set color to GREEN" onclick="sendColorMessage(0,1,0)">
+					<input type="button" value="Set color to BLUE" onclick="sendColorMessage(0,0,1)">
+				</td>
+			</tr>
+		</table>
+	</td>
+	<td>
+	<p><b>Data from mbed:</b></p>
+    <div id="messageLog" style="height: 600px; width: 350px; overflow:auto;">
+        <ol id="messageList">
+            <!-- This will be populated dynamically. -->
+        </ol>
+    </div>
+	</td>
+	</tr>
+	<tr>
+	<td>
+		<!--<input class="color" onchange="sendMessage(this.color)">-->
+	</td>
+	</tr>
+	</body>
+</html>
\ No newline at end of file