Simple sample that demonstrates reading the FXOS8700CQ accelerometer, convert the data to JSON and send to an Azure IoT Hub.

Dependencies:   azure_umqtt_c iothub_mqtt_transport mbed-rtos mbed wolfSSL Socket lwip-eth lwip-sys lwip

Files at this revision

API Documentation at this revision

Comitter:
markrad
Date:
Tue Apr 25 01:33:13 2017 +0000
Parent:
6:0bffe8529f60
Commit message:
Fix bug in NTP library. Clean up code some.

Changed in this revision

NTPClient.lib Show diff for this revision Revisions of this file
NTPClient/NTPClient.cpp Show annotated file Show diff for this revision Revisions of this file
NTPClient/NTPClient.h 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
diff -r 0bffe8529f60 -r 2564d95cbf81 NTPClient.lib
--- a/NTPClient.lib	Tue Apr 18 22:15:09 2017 +0000
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,1 +0,0 @@
-http://developer.mbed.org/users/donatien/code/NTPClient/#881559865a93
diff -r 0bffe8529f60 -r 2564d95cbf81 NTPClient/NTPClient.cpp
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NTPClient/NTPClient.cpp	Tue Apr 25 01:33:13 2017 +0000
@@ -0,0 +1,163 @@
+/* NTPClient.cpp */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * 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.
+ */
+
+//Debug is disabled by default
+#if 0
+//Enable debug
+#define __DEBUG__
+#include <cstdio>
+#define DBG(x, ...) std::printf("[NTPClient : DBG]"x"\r\n", ##__VA_ARGS__); 
+#define WARN(x, ...) std::printf("[NTPClient : WARN]"x"\r\n", ##__VA_ARGS__); 
+#define ERR(x, ...) std::printf("[NTPClient : ERR]"x"\r\n", ##__VA_ARGS__); 
+
+#else
+//Disable debug
+#define DBG(x, ...) 
+#define WARN(x, ...)
+#define ERR(x, ...) 
+
+#endif
+
+#include "NTPClient.h"
+
+#include "UDPSocket.h"
+
+#include "mbed.h" //time() and set_time()
+
+#define NTP_PORT 123
+#define NTP_CLIENT_PORT 0 //Random port
+#define NTP_TIMESTAMP_DELTA 2208988800ull //Diff btw a UNIX timestamp (Starting Jan, 1st 1970) and a NTP timestamp (Starting Jan, 1st 1900)
+
+NTPClient::NTPClient() : m_sock()
+{
+
+
+}
+
+NTPResult NTPClient::setTime(const char* host, uint16_t port, uint32_t timeout)
+{
+#ifdef __DEBUG__
+  time_t ctTime;
+  ctTime = time(NULL);
+  DBG("Time is set to (UTC): %s", ctime(&ctTime));
+#endif
+
+  //Create & bind socket
+  DBG("Binding socket");
+  m_sock.bind(0); //Bind to a random port
+  
+  m_sock.set_blocking(false, timeout); //Set not blocking
+
+  struct NTPPacket pkt;
+
+  //Now ping the server and wait for response
+  DBG("Ping");
+  //Prepare NTP Packet:
+  pkt.li = 0; //Leap Indicator : No warning
+  pkt.vn = 4; //Version Number : 4
+  pkt.mode = 3; //Client mode
+  pkt.stratum = 0; //Not relevant here
+  pkt.poll = 0; //Not significant as well
+  pkt.precision = 0; //Neither this one is
+
+  pkt.rootDelay = 0; //Or this one
+  pkt.rootDispersion = 0; //Or that one
+  pkt.refId = 0; //...
+
+  pkt.refTm_s = 0;
+  pkt.origTm_s = 0;
+  pkt.rxTm_s = 0;
+  pkt.txTm_s = htonl( NTP_TIMESTAMP_DELTA + time(NULL) ); //WARN: We are in LE format, network byte order is BE
+
+  pkt.refTm_f = pkt.origTm_f = pkt.rxTm_f = pkt.txTm_f = 0;
+
+  Endpoint outEndpoint;
+  
+  if( outEndpoint.set_address(host, port) < 0)
+  {
+    m_sock.close();
+    return NTP_DNS;
+  }
+  
+  //Set timeout, non-blocking and wait using select
+  int ret = m_sock.sendTo( outEndpoint, (char*)&pkt, sizeof(NTPPacket) );
+  if (ret < 0 )
+  {
+    ERR("Could not send packet");
+    m_sock.close();
+    return NTP_CONN;
+  }
+
+  //Read response
+  Endpoint inEndpoint;
+
+  DBG("Pong");
+  do
+  {
+    ret = m_sock.receiveFrom( inEndpoint, (char*)&pkt, sizeof(NTPPacket) ); //FIXME need a DNS Resolver to actually compare the incoming address with the DNS name
+    if(ret < 0)
+    {
+      ERR("Could not receive packet");
+      m_sock.close();
+      return NTP_CONN;
+    }
+  } while( strcmp(outEndpoint.get_address(), inEndpoint.get_address()) != 0 );
+
+  if(ret < sizeof(NTPPacket)) //TODO: Accept chunks
+  {
+    ERR("Receive packet size does not match");
+    m_sock.close();
+    return NTP_PRTCL;
+  }
+
+  if( pkt.stratum == 0)  //Kiss of death message : Not good !
+  {
+    ERR("Kissed to death!");
+    m_sock.close();
+    return NTP_PRTCL;
+  }
+
+  //Correct Endianness
+  pkt.refTm_s = ntohl( pkt.refTm_s );
+  pkt.refTm_f = ntohl( pkt.refTm_f );
+  pkt.origTm_s = ntohl( pkt.origTm_s );
+  pkt.origTm_f = ntohl( pkt.origTm_f );
+  pkt.rxTm_s = ntohl( pkt.rxTm_s );
+  pkt.rxTm_f = ntohl( pkt.rxTm_f );
+  pkt.txTm_s = ntohl( pkt.txTm_s );
+  pkt.txTm_f = ntohl( pkt.txTm_f );
+
+  //Compute offset, see RFC 4330 p.13
+  uint32_t destTm_s = (NTP_TIMESTAMP_DELTA + time(NULL));
+  int64_t offset = ( (int64_t)( pkt.rxTm_s - pkt.origTm_s ) + (int64_t) ( pkt.txTm_s - destTm_s ) ) / 2; //Avoid overflow
+  DBG("Sent @%ul", pkt.txTm_s);
+  DBG("Offset: %lld", offset);
+  //Set time accordingly
+  set_time( time(NULL) + offset );
+
+#ifdef __DEBUG__
+  ctTime = time(NULL);
+  DBG("Time is now (UTC): %s", ctime(&ctTime));
+#endif
+
+  m_sock.close();
+
+  return NTP_OK;
+}
+
diff -r 0bffe8529f60 -r 2564d95cbf81 NTPClient/NTPClient.h
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/NTPClient/NTPClient.h	Tue Apr 25 01:33:13 2017 +0000
@@ -0,0 +1,102 @@
+/* NTPClient.h */
+/* Copyright (C) 2012 mbed.org, MIT License
+ *
+ * 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.
+ */
+
+/** \file
+NTP Client header file
+*/
+
+#ifndef NTPCLIENT_H_
+#define NTPCLIENT_H_
+
+#include <cstdint>
+
+using std::uint8_t;
+using std::uint16_t;
+using std::uint32_t;
+
+#include "UDPSocket.h"
+
+#define NTP_DEFAULT_PORT 123
+#define NTP_DEFAULT_TIMEOUT 4000
+
+///NTP client results
+enum NTPResult
+{
+  NTP_OK = 0, ///<Success
+  NTP_DNS, ///<Could not resolve name
+  NTP_PRTCL, ///<Protocol error
+  NTP_TIMEOUT, ///<Connection timeout
+  NTP_CONN, ///<Connection error
+};
+
+/** NTP Client to update the mbed's RTC using a remote time server
+*
+*/
+class NTPClient
+{
+public:
+  /**
+  Instantiate the NTP client
+  */
+  NTPClient();
+
+  /**Get current time (blocking)
+  Update the time using the server host
+  Blocks until completion
+  @param host NTP server IPv4 address or hostname (will be resolved via DNS)
+  @param port port to use; defaults to 123
+  @param timeout waiting timeout in ms (osWaitForever for blocking function, not recommended)
+  @return 0 on success, NTP error code (<0) on failure
+  */
+  NTPResult setTime(const char* host, uint16_t port = NTP_DEFAULT_PORT, uint32_t timeout = NTP_DEFAULT_TIMEOUT); //Blocking
+
+private:
+  struct NTPPacket //See RFC 4330 for Simple NTP
+  {
+    //WARN: We are in LE! Network is BE!
+    //LSb first
+    unsigned mode : 3;
+    unsigned vn : 3;
+    unsigned li : 2;
+
+    uint8_t stratum;
+    uint8_t poll;
+    uint8_t precision;
+    //32 bits header
+
+    uint32_t rootDelay;
+    uint32_t rootDispersion;
+    uint32_t refId;
+
+    uint32_t refTm_s;
+    uint32_t refTm_f;
+    uint32_t origTm_s;
+    uint32_t origTm_f;
+    uint32_t rxTm_s;
+    uint32_t rxTm_f;
+    uint32_t txTm_s;
+    uint32_t txTm_f;
+  } __attribute__ ((packed));
+  
+  UDPSocket m_sock;
+
+};
+
+
+#endif /* NTPCLIENT_H_ */
diff -r 0bffe8529f60 -r 2564d95cbf81 main.cpp
--- a/main.cpp	Tue Apr 18 22:15:09 2017 +0000
+++ b/main.cpp	Tue Apr 25 01:33:13 2017 +0000
@@ -112,7 +112,7 @@
 
 static int JSONifyData(char *buffer, int bufferlen, int reading)
 {
-    static const char *format = "{ \"device\": \"%s\", \"timestamp\": \"%s\", \"reading\": %f }";
+    static const char *format = "{ \"device\": \"%s\", \"timestamp\": \"%s\", \"epochoffset\": %d, \"reading\": %f }";
     static const char *timeFormat = "%FT%X";
     char timeOut[80];
     double work;
@@ -121,17 +121,13 @@
     struct tm *ptm;
     
     // gmtime() does not work on the FRDM K64F - set RTC to UTC
-    time(&rawtime);
-    printf("%x\r\n", ptm);
+    rawtime = time(NULL);
     ptm = localtime(&rawtime);
-    printf("%x\r\n", ptm);
     
     strftime(timeOut, sizeof(timeOut), timeFormat, ptm);
-    printf("rawtime >>%d<<\r\n", rawtime);
-    printf("timeOut >>%s<<\r\n", timeOut);
-    printf("month=%d\r\n", ptm->tm_mon);
+    printf("rawtime=%d;time=%s\r\n", rawtime, timeOut);
     work = sqrt((double)reading);
-    rc = snprintf(buffer, bufferlen, format, "mydevice", timeOut, work);   
+    rc = snprintf(buffer, bufferlen, format, "mydevice", timeOut, rawtime, work);   
     
     if (rc < 0)
         printf("*** ERROR *** out of buffer space\r\n");
@@ -261,7 +257,9 @@
     
     printf("Calibrating...\r\n");
     
-    for (i = 0; i < calibrationPeriod * 50; i++)
+    i = calibrationPeriod * 50;
+    
+    while (i > 0)
     {
         if (sfxos.getInt2Triggered())
         {
@@ -271,14 +269,13 @@
 //            data[i] = reading.accelerometer.x + reading.accelerometer.y;
             printf("x=%d\t\ty=%d\t\tsum=%f\r\n", reading.accelerometer.x, reading.accelerometer.y, data[i]);
             sum += data[i];
-            wait_ms(20);
+            --i;
         }
         else
         {
-            printf("no data\r\n");
-            wait_ms(20);
-            i--;        // Try that reading again
+            printf("WARNING: Sensor was not ready in time during calibration\r\n");
         }
+        wait_ms(20);
     }
     
     mean = (double)sum / (double)(calibrationPeriod * 50);
@@ -301,6 +298,9 @@
 int main()
 {
     const char *connectionString = "HostName=MarkRadHub1.azure-devices.net;DeviceId=mrcc3200;SharedAccessKey=8pGKChTBsz0VGw234iLX7XDDKwcyWRC7hsrVZEHfZHs=";
+    const char *ntpServer = "0.pool.ntp.org";
+    const int ntpRefreshInterval = 60 * 60;
+    const int ledInterval = 300 / 20;
 
     READING reading;
     Serial pc(USBTX, USBRX); // Primary output to demonstrate library
@@ -310,8 +310,10 @@
     int transmitCounter = 0;
     double mean;
     double deviation;
+    DigitalOut ledBlue(LED_BLUE);    
     
     pc.baud(115200); // Print quickly! 200Hz x line of output data!
+    ledBlue = 1;
     
     printf("\n\n\rFXOS8700CQ identity = %X\r\n", sfxos.getWhoAmI());
     
@@ -332,13 +334,22 @@
     char buffer[200];
     
     iotHubClientHandle = setupConnection(pc, connectionString, MQTT_Protocol, &receiveContext);
-    
     calibrate(&mean, &deviation);
     
     int readCount = 0;
     int32_t maxVal = LONG_MIN;
     int32_t curVal;
-    int32_t oneHour = 60 * 60 * 50;
+    time_t lastUpdate = 0;
+    int ntpRc;
+    int ledOffAt = 0;
+    
+    while (NTP_OK != (ntpRc = ntp.setTime("0.pool.ntp.org")))
+    {
+        printf("ERROR: Failed to set current time from NTP server - rc = %d\r\n", ntpRc);
+        wait_ms(100);
+    }
+    
+    lastUpdate = time(NULL);
     
     while (LOOPCOUNT)
     {
@@ -389,6 +400,8 @@
                             else
                             {
                                 (void)printf("IoTHubClient_LL_SendEventAsync accepted message [%d] for transmission to IoT Hub.\r\n", (int)transmitCounter);
+                                ledBlue = 0;
+                                ledOffAt = ledInterval;
                             }
                             
                             IoTHubMessage_Destroy(msgHandle);
@@ -425,8 +438,20 @@
                             
                 if (LOOPCOUNT > 0)
                     LOOPCOUNT--;
+                    
                 readCount = 0;
                 maxVal = LONG_MIN;
+                
+                if (time(NULL) - lastUpdate > ntpRefreshInterval)
+                {
+                    while (NTP_OK != (ntpRc = ntp.setTime("0.pool.ntp.org")))
+                    {
+                        printf("ERROR: Failed to set current time from NTP server - rc = %d\r\n", ntpRc);
+                        wait_ms(100);
+                    }
+                    
+                    lastUpdate = time(NULL);
+                }
             }
         }
         else
@@ -434,22 +459,12 @@
             printf("WARNING: Sensor was not ready in time\r\n");
         }
         
-        // Read at 50 hz
-        
-        if (--oneHour <= 0)
+        if (!((int)ledBlue) && --ledOffAt <= 0)
         {
-            printf("INFO: Updating RTC from NTP server\r\n");
-            
-            if (ntp.setTime("0.pool.ntp.org") != 0)
-            {
-                printf("ERROR: Failed to set current time from NTP server\r\n");
-            }         
-            else
-            {
-                oneHour = 60 * 60 * 50;
-            }
+            ledBlue = 1;
         }
-            
+        
+        // Read at 50 hz
         wait_ms(20);
     }