mbed based IoT Gateway More details http://blog.thiseldo.co.uk/wp-filez/IoTGateway.pdf

Dependencies:   NetServices FatFileSystem csv_parser mbed MQTTClient RF12B DNSResolver SDFileSystem

Revision:
0:a29a0225f203
Child:
2:27714c8c9c0a
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Mon Apr 02 22:05:20 2012 +0000
@@ -0,0 +1,401 @@
+/** IoT Gateway main code
+ *
+ * @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
+ *
+ * Code is to be classed as beta. There is a lot of debug code still includes
+ * to dump heap sizes and other values. It is still a work in progress and
+ * should be treated as such.
+ *
+ * Sample configuration file IOTSETUP.TXT
+ *
+ * @code
+ * pachube.key=***your pachube api key***
+ * ip.mode=fixed
+ * ip.address=192.168.1.99
+ * ip.netmask=255.255.255.0
+ * ip.gateway=192.168.1.1
+ * ip.dns=192.168.1.1
+ * rfm12b.band=868
+ * rfm12b.id=30
+ * rfm12b.group=212
+ * time.timezone=GMT
+ * time.dst=yes
+ * mqtt.host=
+ * mqtt.port=
+ * @endcode
+ *
+ * Some values are not yet used
+ *
+ */
+
+
+#include "mbed.h"
+#include "SDFileSystem.h"
+#include "EthernetNetIf.h"
+#include "NTPClient.h"
+#include "RF12B.h"
+#include "IoTRouting.h"
+
+
+using std::string;
+
+#define VERSION_INFO "IoT Gateway Basic - Version 0.4-BETA "
+
+DigitalOut heartbeatLED(LED1, "heartbeatLED");
+DigitalOut led2(LED2, "led2");
+DigitalOut led3(LED3, "led3");
+//DigitalOut led4(LED4, "led4");
+DigitalOut linkLED(p30, "linkLED");
+DigitalOut statusLED(p25, "statusLED");
+
+// Setup which filesystem to use, Local or uSD card
+__attribute((section("AHBSRAM0"))) LocalFileSystem fs("iotfs");
+//__attribute((section("AHBSRAM0"))) SDFileSystem sd(p5, p6, p7, p8, "iotfs");
+
+__attribute((section("AHBSRAM0"))) EthernetNetIf *eth;
+__attribute((section("AHBSRAM0"))) NTPClient ntp;
+__attribute((section("AHBSRAM0"))) Ethernet ethernet;
+
+// Configuration values loaded from file iotsetup.dat
+__attribute((section("AHBSRAM0"))) IpAddr ipAddress(0, 0, 0, 0);
+__attribute((section("AHBSRAM0"))) IpAddr netMask(255, 255, 255, 0);
+__attribute((section("AHBSRAM0"))) IpAddr gwAddress(0, 0, 0, 0);
+__attribute((section("AHBSRAM0"))) IpAddr dnsAddress(0, 0, 0, 0);
+__attribute((section("AHBSRAM0"))) bool useDHCP = false;
+
+// Static buffers
+#define MAX_LINE_LENGTH 128
+__attribute__((section("AHBSRAM0"))) static char lineBuf[MAX_LINE_LENGTH];
+__attribute__((section("AHBSRAM0"))) static OutputPachube outPachube;
+__attribute__((section("AHBSRAM0"))) static IoTRouting rtr;
+
+// Pachube config
+__attribute__((section("AHBSRAM0"))) static char pachubeApiKey[65];
+
+// MQTT config
+__attribute((section("AHBSRAM0"))) IpAddr mqttHostAddress( 0, 0, 0, 0);
+//char mqttHostName[65];
+
+
+// RFM12B config
+__attribute((section("AHBSRAM0"))) static string rfm12bBands[4] = {"xxx", "433", "868", "915" };
+__attribute((section("AHBSRAM0"))) uint8_t rfm12bId;
+__attribute((section("AHBSRAM0"))) uint8_t rfm12bBand;
+__attribute((section("AHBSRAM0"))) uint8_t rfm12bGroup;
+
+#define iotConfigFile "/iotfs/IOTSETUP.TXT"
+#define startUrlFile  "/iotfs/START.URL"
+
+__attribute((section("AHBSRAM0"))) RF12B rfm12b(p11, p12, p13, p14, p18);
+
+__attribute((section("AHBSRAM0"))) Serial pc(USBTX, USBRX); // tx, rx
+
+// Utility functions
+
+
+/** convert string to IP address
+ *
+ * @param ipAddrInt  IP address as single 32bit integer
+ * @param value      The IP address as a string
+ */
+void setIpAddress( int *ipAddrInt, char *value ) {
+    sscanf(value, "%d.%d.%d.%d", &ipAddrInt[0],&ipAddrInt[1],&ipAddrInt[2],&ipAddrInt[3]);
+}
+
+/** Get the value from a name=value pair
+ *
+ * @param buf  The name/value pair character buffer
+ * @returns pointer to value
+ */
+char *getConfigValue( char *buf ) {
+    char *ptr = strchr(buf, '=');
+    if ( ptr == NULL )
+        return NULL;
+    ptr++;
+    return ptr;
+}
+
+/** Copy zero or CR/LF terminated string to new zero terminated string
+ * Used when reading config values from files to remove CR/LF endings
+ *
+ * @param to   Char pointer to destination
+ * @param from Char pointer to source
+ */
+void strcpynull(char *to, char *from ) {
+    while ( *from != '\n' && *from != '\r' && *from != '\0' ) {
+        *to++ = *from++;
+    }
+    *to = '\0';
+}
+
+
+/** Read IoT gateway configuration file
+ * File is of format name=value
+ *
+ */
+bool readConfig() {
+
+    FILE *fp = fopen(iotConfigFile, "r");
+    if (fp == NULL) {
+        printf("Could not open file %s for read\n", iotConfigFile);
+        return false;
+    }
+    // read file
+    while (!feof( fp )) {
+        fgets(lineBuf,MAX_LINE_LENGTH,fp);
+        //printf("%s",lineBuf);
+        // Need to read each entry and update config
+        char *nameStr;
+        char *valueStr;
+        nameStr = lineBuf;
+        valueStr = strchr( lineBuf, '=' );
+        if ( valueStr != NULL ) {
+            *valueStr++ = '\0';
+            int tmpAddress[4] = {0,0,0,0};
+            if ( strcmp( nameStr, "ip.address" ) == 0 ) {
+                setIpAddress( &tmpAddress[0], valueStr );
+                ipAddress = IpAddr( tmpAddress[0],tmpAddress[1],tmpAddress[2],tmpAddress[3]);
+            } else             if ( strcmp( nameStr, "ip.netmask" ) == 0 ) {
+                setIpAddress( &tmpAddress[0], valueStr );
+                netMask = IpAddr( tmpAddress[0],tmpAddress[1],tmpAddress[2],tmpAddress[3]);
+            } else             if ( strcmp( nameStr, "ip.gateway" ) == 0 ) {
+                setIpAddress( &tmpAddress[0], valueStr );
+                gwAddress = IpAddr( tmpAddress[0],tmpAddress[1],tmpAddress[2],tmpAddress[3]);
+            } else             if ( strcmp( nameStr, "ip.dns" ) == 0 ) {
+                setIpAddress( &tmpAddress[0], valueStr );
+                dnsAddress = IpAddr( tmpAddress[0],tmpAddress[1],tmpAddress[2],tmpAddress[3]);
+            }  else if ( strcmp( nameStr, "pachube.key" ) == 0 ) {
+                strcpynull(pachubeApiKey, valueStr );
+            }  else if ( strcmp( nameStr, "ip.mode" ) == 0 ) {
+                useDHCP = (strncmp( valueStr, "dhcp", 4) == 0 ? true : false);
+            }  else if ( strcmp( nameStr, "rfm12b.band" ) == 0 ) {
+                if ( strncmp( valueStr, "433", 3 ) == 0 )
+                    rfm12bBand = RF12_433MHZ;
+                else if ( strncmp( valueStr, "868", 3 ) == 0 )
+                    rfm12bBand = RF12_868MHZ;
+                else if ( strncmp( valueStr, "915", 3 ) == 0 )
+                    rfm12bBand = RF12_915MHZ;
+            }  else if ( strcmp( nameStr, "rfm12b.id" ) == 0 ) {
+                rfm12bId = atoi( valueStr );
+            }  else if ( strcmp( nameStr, "rfm12b.group" ) == 0 ) {
+                rfm12bGroup = atoi( valueStr );
+            }
+        }
+    }
+    fclose(fp);
+
+    return true;
+}
+
+/** Write the current config to file
+ */
+bool writeConfig() {
+
+// Doesnt work?
+    // Rename original file
+//    if( rename ( iotConfigFile.c_str(), iotConfigFileBak.c_str() ) != 0 ) {
+//        printf("Could not rename file %s\n", iotConfigFile);
+//        return false;
+//    }
+
+    FILE *fp = fopen(iotConfigFile, "w");
+    if (fp == NULL) {
+        printf("Could not open file %s for write\n", iotConfigFile);
+        return false;
+    }
+
+    time_t ctTime;
+    ctTime = time(NULL);
+
+    fprintf(fp, "# iotsetup created (UTC) %s\n", ctime(&ctTime));
+    fprintf(fp, "pachube.key=%s\n", pachubeApiKey );
+    fprintf(fp, "ip.mode=%s\n", (useDHCP ? "dhcp" : "fixed") );
+    // Add msg to say net config being ignored
+    if ( useDHCP )
+        fprintf(fp, "# Following ip.* parameters not used in DHCP mode\n");
+
+    fprintf(fp, "ip.address=%hhu.%hhu.%hhu.%hhu\n", ipAddress[0], ipAddress[1],ipAddress[2],ipAddress[3]);
+    fprintf(fp, "ip.netmask=%hhu.%hhu.%hhu.%hhu\n",netMask[0], netMask[1], netMask[2], netMask[3]);
+    fprintf(fp, "ip.gateway=%hhu.%hhu.%hhu.%hhu\n",gwAddress[0],gwAddress[1],gwAddress[2],gwAddress[3]);
+    fprintf(fp, "ip.dns=%hhu.%hhu.%hhu.%hhu\n",dnsAddress[0],dnsAddress[1],dnsAddress[2],dnsAddress[3]);
+
+    fprintf(fp, "rfm12b.band=%s\n",rfm12bBands[rfm12bBand].c_str());
+    fprintf(fp, "rfm12b.id=%d\n",rfm12bId);
+    fprintf(fp, "rfm12b.group=%d\n",rfm12bGroup);
+
+    fprintf(fp, "time.timezone=GMT\n");
+    fprintf(fp, "time.dst=yes\n");
+    fclose(fp);
+
+    return true;
+}
+
+
+// These external symbols are maintained by the linker to indicate the
+// location of various regions in the device's memory.  They will be used by
+// DisplayRAMBanks() to dump the size of each RAM bank to stdout.
+extern unsigned int Image$$RW_IRAM1$$Base;
+extern unsigned int Image$$RW_IRAM1$$ZI$$Limit;
+extern unsigned int Image$$RW_IRAM2$$Base;
+extern unsigned int Image$$RW_IRAM2$$ZI$$Limit;
+extern unsigned int Image$$RW_IRAM3$$Base;
+extern unsigned int Image$$RW_IRAM3$$ZI$$Limit;
+
+// Displays the size of static allocations for each RAM bank as indicated by
+// ARM linker to stdout.
+static void DisplayRAMBanks(void) {
+    printf("Static RAM bank allocations\r\n");
+    printf("  Main RAM = %u\r\n", (unsigned int)&Image$$RW_IRAM1$$ZI$$Limit -
+           (unsigned int)&Image$$RW_IRAM1$$Base);
+    printf("  RAM0     = %u\r\n", (unsigned int)&Image$$RW_IRAM2$$ZI$$Limit -
+           (unsigned int)&Image$$RW_IRAM2$$Base);
+    printf("  RAM1     = %u\r\n", (unsigned int)&Image$$RW_IRAM3$$ZI$$Limit -
+           (unsigned int)&Image$$RW_IRAM3$$Base);
+}
+
+/** Main function, where all the magic starts
+ */
+int main() {
+    linkLED = 1;
+    statusLED = 0;
+    pc.baud(115200);
+
+    printf(VERSION_INFO);
+    printf("\n");
+
+    DisplayRAMBanks();
+
+    printf("Setting up...\n");
+    printf("\nHEAP STATS\n");
+    __heapstats((__heapprt)fprintf,stderr);
+
+    if ( !readConfig() ) {
+        error("Setup failed");
+    }
+
+    if (useDHCP) {
+        printf("Using DHCP\n");
+        eth = new EthernetNetIf( "IoTGateway" );
+    } else {
+//        printf("Using Fixed addressing\n");
+        eth = new EthernetNetIf( ipAddress, netMask, gwAddress, dnsAddress );
+    }
+    EthernetErr ethErr = eth->setup();
+    if (ethErr) {
+        printf("Error %d in setup.\n", ethErr);
+        return -1;
+    }
+
+    linkLED = !ethernet.link();
+
+    if (useDHCP) {
+        // We are using dhcp so get IP Address
+        ipAddress = eth->getIp();
+    }
+
+
+    // Get Current time
+    Host server(IpAddr(), 123, "0.uk.pool.ntp.org");
+    ntp.setTime(server);
+
+    time_t ctTime = time(NULL);
+    printf("\nTime is now (UTC): %s\n", ctime(&ctTime));
+
+    outPachube = OutputPachube();
+    outPachube.setApiKey( pachubeApiKey );
+//    IpAddr serverIpAddr(192,168,1,77);
+//    OutputMqtt outMqtt = OutputMqtt();
+//    outMqtt.setHost( &serverIpAddr );
+
+//    printf("MAIN: outPachube = %ld\n",(int)&outPachube);
+    rtr.addOutput( (OutputDef*)&outPachube , 1);
+//    rtr.addOutput( (OutputDef*)&outMqtt , 2);
+
+    rtr.initRouting();
+
+    printf("Setup OK\n");
+
+    printf( "Setting RFM12B ID %d, Band %d Group %d\n",rfm12bId, rfm12bBand, rfm12bGroup);
+    rfm12b.init(rfm12bId, rfm12bBand, rfm12bGroup );   //id = 2, band 866, group 5
+
+    printf("Listening...\n");
+
+    Timer tm;
+    tm.start();
+
+    printf("\nHEAP STATS\n");
+    __heapstats((__heapprt)fprintf,stderr);
+
+    short dataLen = 0;
+    uint8_t *rf12Buf;
+
+    // Start receiving data
+    rfm12b.rf12_recvStart();
+    while (true) {
+        Net::poll();
+
+        // This is RFM12B specific
+        if ( rfm12b.available() > 0 ) {
+            statusLED = 1;
+            rf12Buf =  rfm12b.get_data();
+            dataLen = rfm12b.length();
+
+            if ( rtr.routePayload( rf12Buf, dataLen + 3 ) ) {
+                // Successfully dealt with a packet
+
+                // Do something different if routed
+
+            }
+
+            // For now, acknowledge everything
+
+            // Send an ack if required
+            if ((rf12Buf[1] & ~RF12_HDR_MASK) == RF12_HDR_ACK // &&
+                    //(config.nodeId & 0x20) == 0
+               ) {
+
+                printf("RFM12B -> ack\n");
+
+                byte addr = rf12Buf[1] & RF12_HDR_MASK;
+                rfm12b.rf12_sendStart(RF12_HDR_CTL | RF12_HDR_DST | addr, 0, 1);
+            }
+
+            statusLED = 0;
+        }
+
+        if (tm.read()>.5) {
+            heartbeatLED=!heartbeatLED; //Show that we are alive
+            tm.start();
+        }
+
+        linkLED = !ethernet.link();
+
+    }
+
+}
+
+// The End!
\ No newline at end of file