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
Revision 0:713518ea5028, committed 2014-10-01
- Comitter:
- embeddedartists
- Date:
- Wed Oct 01 11:39:10 2014 +0000
- Commit message:
- First version
Changed in this revision
--- /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
--- /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
--- /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
--- /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
--- /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(); +}
--- /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
--- /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
--- /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
--- /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: <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