Example program that shows how to use the Secure (TLS) SharkMQ library included in SharkSSL-Lite
Dependencies: EthernetInterface SharkSSL-Lite mbed-rtos mbed
Introduction
The SMQ Architecture is an Internet of Things (IoT) publish subscribe end-to-end solution that is optimized for embedded systems to provide instantaneous Device Edge Node connectivity, 1 to 1 Communications, and Ease of Transcending Firewalls. The solution is ideal for resource constrained devices that require real-time dynamic control, analytic information, and firmware updates in both LAN and WAN environments.
Architecture Component List
- SMQ C Client (Non-secure)
- SharkMQ Secure C Client (this mbed example)
- SMQjs (Javascript)
- SMQ JAVA
- SMQ Broker
SharkMQ-LED-Demo
An example of (Secure) device control via a Browser interface. It includes the LED demonstration example code, SharkMQ, and SharkSSL SSL|TLS stack for authentication and encryption.
- Code Size: 21kB ROM | 4kB RAM.
- Requires: SharkSSL-Lite
Video Tutorials
How to setup your own secure SMQ IoT cloud server
Most IoT cloud server solutions, whether they provide ready-to-use hosted services or not, are based on a standard Virtual Private Server (VPS). Most developers probably think of Amazon or Microsoft Azure's services when considering the server side of their IoT solution. These high-end services are great if you need to scale up to millions of connected devices. However, for most small-scale operations and DIY projects, a low-cost VPS is more than adequate.
SMQ LED Demo
See Also
- SMQ Client-Example (NonSecure) SMQ Client LED Demonstration.
- SMQ LED Demonstration Tutorial
- SMQ Documentation
- Real Time Logic LLC public SMQ Broker access.
- How to set up your own low cost SMQ Broker cloud server solution Tutorial.
m2m-led-SharkMQ.c@5:6526b95442e7, 2016-04-08 (annotated)
- Committer:
- wini
- Date:
- Fri Apr 08 16:44:27 2016 +0000
- Revision:
- 5:6526b95442e7
- Parent:
- 0:10b4212318d4
Readme file fix
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
wini | 0:10b4212318d4 | 1 | /** |
wini | 0:10b4212318d4 | 2 | * ____ _________ __ _ |
wini | 0:10b4212318d4 | 3 | * / __ \___ ____ _/ /_ __(_)___ ___ ___ / / ____ ____ _(_)____ |
wini | 0:10b4212318d4 | 4 | * / /_/ / _ \/ __ `/ / / / / / __ `__ \/ _ \/ / / __ \/ __ `/ / ___/ |
wini | 0:10b4212318d4 | 5 | * / _, _/ __/ /_/ / / / / / / / / / / / __/ /___/ /_/ / /_/ / / /__ |
wini | 0:10b4212318d4 | 6 | * /_/ |_|\___/\__,_/_/ /_/ /_/_/ /_/ /_/\___/_____/\____/\__, /_/\___/ |
wini | 0:10b4212318d4 | 7 | * /____/ |
wini | 0:10b4212318d4 | 8 | * |
wini | 0:10b4212318d4 | 9 | * SharkSSL Embedded SSL/TLS Stack |
wini | 0:10b4212318d4 | 10 | **************************************************************************** |
wini | 0:10b4212318d4 | 11 | * PROGRAM MODULE |
wini | 0:10b4212318d4 | 12 | * |
wini | 0:10b4212318d4 | 13 | * $Id: m2m-led-SharkMQ.c 3878 2016-04-01 19:48:24Z wini $ |
wini | 0:10b4212318d4 | 14 | * |
wini | 0:10b4212318d4 | 15 | * COPYRIGHT: Real Time Logic LLC, 2014 - 2016 |
wini | 0:10b4212318d4 | 16 | * |
wini | 0:10b4212318d4 | 17 | * This software is copyrighted by and is the sole property of Real |
wini | 0:10b4212318d4 | 18 | * Time Logic LLC. All rights, title, ownership, or other interests in |
wini | 0:10b4212318d4 | 19 | * the software remain the property of Real Time Logic LLC. This |
wini | 0:10b4212318d4 | 20 | * software may only be used in accordance with the terms and |
wini | 0:10b4212318d4 | 21 | * conditions stipulated in the corresponding license agreement under |
wini | 0:10b4212318d4 | 22 | * which the software has been supplied. Any unauthorized use, |
wini | 0:10b4212318d4 | 23 | * duplication, transmission, distribution, or disclosure of this |
wini | 0:10b4212318d4 | 24 | * software is expressly forbidden. |
wini | 0:10b4212318d4 | 25 | * |
wini | 0:10b4212318d4 | 26 | * This Copyright notice may not be removed or modified without prior |
wini | 0:10b4212318d4 | 27 | * written consent of Real Time Logic LLC. |
wini | 0:10b4212318d4 | 28 | * |
wini | 0:10b4212318d4 | 29 | * Real Time Logic LLC. reserves the right to modify this software |
wini | 0:10b4212318d4 | 30 | * without notice. |
wini | 0:10b4212318d4 | 31 | * |
wini | 0:10b4212318d4 | 32 | * https://realtimelogic.com |
wini | 0:10b4212318d4 | 33 | **************************************************************************** |
wini | 0:10b4212318d4 | 34 | |
wini | 0:10b4212318d4 | 35 | SharkMQ (secure SMQ) LED example. |
wini | 0:10b4212318d4 | 36 | |
wini | 0:10b4212318d4 | 37 | This code is the device side for the SMQ LED controller, an example |
wini | 0:10b4212318d4 | 38 | that enables LEDs in a device to be controlled from a browser and |
wini | 0:10b4212318d4 | 39 | Java (including Android). |
wini | 0:10b4212318d4 | 40 | |
wini | 0:10b4212318d4 | 41 | When this code runs, it connects to our public SMQ test broker. The |
wini | 0:10b4212318d4 | 42 | device will show up as a tab on the following page: |
wini | 0:10b4212318d4 | 43 | https://simplemq.com/m2m-led/ |
wini | 0:10b4212318d4 | 44 | |
wini | 0:10b4212318d4 | 45 | Introductory information on how the complete SMQ LED demo works |
wini | 0:10b4212318d4 | 46 | (including the browser UI) can be found online. The device code |
wini | 0:10b4212318d4 | 47 | details can be found under section " Device C code". |
wini | 0:10b4212318d4 | 48 | https://goo.gl/phXnWp |
wini | 0:10b4212318d4 | 49 | |
wini | 0:10b4212318d4 | 50 | The code is designed for embedded devices, but can also be run on a |
wini | 0:10b4212318d4 | 51 | host computer (Windows/Linux) as a simulated device with four |
wini | 0:10b4212318d4 | 52 | simulated LEDs. |
wini | 0:10b4212318d4 | 53 | |
wini | 0:10b4212318d4 | 54 | The macro HOST_PLATFORM must be defined if compiled and run on a |
wini | 0:10b4212318d4 | 55 | non embedded platform (HLOS). The code within this section sets up the |
wini | 0:10b4212318d4 | 56 | simulated environment. Do not set this macro if the code is to be |
wini | 0:10b4212318d4 | 57 | cross compiled for an embedded device. |
wini | 0:10b4212318d4 | 58 | |
wini | 0:10b4212318d4 | 59 | When cross compiling for an embedded device, create a separate C |
wini | 0:10b4212318d4 | 60 | file and include ledctrl.h. The C file must have the following |
wini | 0:10b4212318d4 | 61 | functions (used by the generic code in this file): |
wini | 0:10b4212318d4 | 62 | * int getUniqueId(const U8* id); |
wini | 0:10b4212318d4 | 63 | * const LedInfo* getLedInfo(int* len); |
wini | 0:10b4212318d4 | 64 | * const char* getDevName(void); |
wini | 0:10b4212318d4 | 65 | * int setLed(int ledId, int on); |
wini | 0:10b4212318d4 | 66 | * int setLedFromDevice(int* ledId, int* on); |
wini | 0:10b4212318d4 | 67 | * int getLedState(int ledId, int on, int set); |
wini | 0:10b4212318d4 | 68 | * void setProgramStatus(ProgramStatus s); |
wini | 0:10b4212318d4 | 69 | * int getUniqueId(const char** id); unless GETUNIQUEID is defined |
wini | 0:10b4212318d4 | 70 | * xprintf (selib.h) |
wini | 0:10b4212318d4 | 71 | |
wini | 0:10b4212318d4 | 72 | See the following documentation for how to interface the LED |
wini | 0:10b4212318d4 | 73 | functions to the hardware: |
wini | 0:10b4212318d4 | 74 | https://realtimelogic.com/ba/doc/en/C/shark/md_md_Examples.html#LedDemo |
wini | 0:10b4212318d4 | 75 | |
wini | 0:10b4212318d4 | 76 | The above functions are documented in ledctrl.h. You may also study |
wini | 0:10b4212318d4 | 77 | the simulated versions in the HOST_PLATFORM code section |
wini | 0:10b4212318d4 | 78 | below. Function xprintf is optional and used if macro XPRINTF=1. If |
wini | 0:10b4212318d4 | 79 | enabled, program status is printed during operation. |
wini | 0:10b4212318d4 | 80 | |
wini | 0:10b4212318d4 | 81 | A ready to use (non secure) mbed version can be found on the ARM |
wini | 0:10b4212318d4 | 82 | mbed web site: https://goo.gl/Rnhp3b |
wini | 0:10b4212318d4 | 83 | |
wini | 0:10b4212318d4 | 84 | To set up your own SMQ broker (server), download the Mako Server |
wini | 0:10b4212318d4 | 85 | and activate the tutorials. A ready to use broker is included in |
wini | 0:10b4212318d4 | 86 | the tutorials. The following non active copy of the tutorials |
wini | 0:10b4212318d4 | 87 | provide information on how the broker operates: |
wini | 0:10b4212318d4 | 88 | https://realtimelogic.com/bas-tutorials/IoT.lsp |
wini | 0:10b4212318d4 | 89 | */ |
wini | 0:10b4212318d4 | 90 | |
wini | 0:10b4212318d4 | 91 | |
wini | 0:10b4212318d4 | 92 | /* Change the domain/url if you are running your own broker |
wini | 0:10b4212318d4 | 93 | Note: you can also set the domain at the command prompt when in |
wini | 0:10b4212318d4 | 94 | simulation mode. |
wini | 0:10b4212318d4 | 95 | */ |
wini | 0:10b4212318d4 | 96 | #define SIMPLEMQ_DOMAIN "https://simplemq.com" |
wini | 0:10b4212318d4 | 97 | #define SIMPLEMQ_URL SIMPLEMQ_DOMAIN "/smq.lsp" |
wini | 0:10b4212318d4 | 98 | |
wini | 0:10b4212318d4 | 99 | #include "SharkMQ.h" |
wini | 0:10b4212318d4 | 100 | #include "ledctrl.h" |
wini | 0:10b4212318d4 | 101 | #include <ctype.h> |
wini | 0:10b4212318d4 | 102 | #include <stdlib.h> |
wini | 0:10b4212318d4 | 103 | |
wini | 0:10b4212318d4 | 104 | /* sharkSslCAList (Ref-CA) |
wini | 0:10b4212318d4 | 105 | |
wini | 0:10b4212318d4 | 106 | The data from the include file below is a CA (Certificate Authority) |
wini | 0:10b4212318d4 | 107 | Root Certificate. The CA enables SharkSSL to verify the identity of |
wini | 0:10b4212318d4 | 108 | realtimelogic.com. We include data for only one CA in this example |
wini | 0:10b4212318d4 | 109 | since only the signer of realtimelogi.com's certificate is required |
wini | 0:10b4212318d4 | 110 | for validation in this example. See the "certcheck" example for how to |
wini | 0:10b4212318d4 | 111 | validate any type of certificate and for more options on how to store |
wini | 0:10b4212318d4 | 112 | certificates, in addition to embedding the CA as it is done in this |
wini | 0:10b4212318d4 | 113 | example. |
wini | 0:10b4212318d4 | 114 | |
wini | 0:10b4212318d4 | 115 | The Certification Authority Root Certificate was |
wini | 0:10b4212318d4 | 116 | converted to 'sharkSslCAList' as follows: |
wini | 0:10b4212318d4 | 117 | SharkSSLParseCAList CA_RTL_EC_256.pem > CA_RTL_EC_256.h |
wini | 0:10b4212318d4 | 118 | |
wini | 0:10b4212318d4 | 119 | An introduction to certificate management can be found here: |
wini | 0:10b4212318d4 | 120 | https://goo.gl/rjdQjg |
wini | 0:10b4212318d4 | 121 | |
wini | 0:10b4212318d4 | 122 | */ |
wini | 0:10b4212318d4 | 123 | #include "certificates/CA_RTL_EC_256.h" |
wini | 0:10b4212318d4 | 124 | |
wini | 0:10b4212318d4 | 125 | |
wini | 0:10b4212318d4 | 126 | /**************************************************************************** |
wini | 0:10b4212318d4 | 127 | **************************-----------------------*************************** |
wini | 0:10b4212318d4 | 128 | **************************| BOARD SPECIFIC CODE |*************************** |
wini | 0:10b4212318d4 | 129 | **************************-----------------------*************************** |
wini | 0:10b4212318d4 | 130 | ****************************************************************************/ |
wini | 0:10b4212318d4 | 131 | |
wini | 0:10b4212318d4 | 132 | #if HOST_PLATFORM |
wini | 0:10b4212318d4 | 133 | |
wini | 0:10b4212318d4 | 134 | static const char* simpleMqUrl; /* defaults to SIMPLEMQ_DOMAIN */ |
wini | 0:10b4212318d4 | 135 | |
wini | 0:10b4212318d4 | 136 | #ifdef _WIN32 |
wini | 0:10b4212318d4 | 137 | // For calculating unique ID |
wini | 0:10b4212318d4 | 138 | #include <Rpc.h> |
wini | 0:10b4212318d4 | 139 | #pragma comment(lib, "Rpcrt4.lib") |
wini | 0:10b4212318d4 | 140 | #endif |
wini | 0:10b4212318d4 | 141 | |
wini | 0:10b4212318d4 | 142 | #include <stdio.h> |
wini | 0:10b4212318d4 | 143 | |
wini | 0:10b4212318d4 | 144 | |
wini | 0:10b4212318d4 | 145 | /* Enable simulated temperature */ |
wini | 0:10b4212318d4 | 146 | #ifndef ENABLE_TEMP |
wini | 0:10b4212318d4 | 147 | #define ENABLE_TEMP |
wini | 0:10b4212318d4 | 148 | #endif |
wini | 0:10b4212318d4 | 149 | |
wini | 0:10b4212318d4 | 150 | /* |
wini | 0:10b4212318d4 | 151 | The following is used by the logic managing the simulated temperature. |
wini | 0:10b4212318d4 | 152 | */ |
wini | 0:10b4212318d4 | 153 | #define KEY_UP_ARROW 1000 |
wini | 0:10b4212318d4 | 154 | #define KEY_DOWN_ARROW 1001 |
wini | 0:10b4212318d4 | 155 | static int currentTemperature=0; /* simulated value */ |
wini | 0:10b4212318d4 | 156 | |
wini | 0:10b4212318d4 | 157 | /* Replace with a function that prints to a console or create a stub |
wini | 0:10b4212318d4 | 158 | * that does nothing. |
wini | 0:10b4212318d4 | 159 | */ |
wini | 0:10b4212318d4 | 160 | void |
wini | 0:10b4212318d4 | 161 | _xprintf(const char* fmt, ...) |
wini | 0:10b4212318d4 | 162 | { |
wini | 0:10b4212318d4 | 163 | va_list varg; |
wini | 0:10b4212318d4 | 164 | va_start(varg, fmt); |
wini | 0:10b4212318d4 | 165 | vprintf(fmt, varg); |
wini | 0:10b4212318d4 | 166 | va_end(varg); |
wini | 0:10b4212318d4 | 167 | } |
wini | 0:10b4212318d4 | 168 | |
wini | 0:10b4212318d4 | 169 | |
wini | 0:10b4212318d4 | 170 | /* Not needed on host with printf support. This function is designed for |
wini | 0:10b4212318d4 | 171 | * embedded systems without console. |
wini | 0:10b4212318d4 | 172 | */ |
wini | 0:10b4212318d4 | 173 | void setProgramStatus(ProgramStatus s) |
wini | 0:10b4212318d4 | 174 | { |
wini | 0:10b4212318d4 | 175 | (void)s; |
wini | 0:10b4212318d4 | 176 | } |
wini | 0:10b4212318d4 | 177 | |
wini | 0:10b4212318d4 | 178 | |
wini | 0:10b4212318d4 | 179 | |
wini | 0:10b4212318d4 | 180 | /* The list of LEDs in the device, the name, color, and ID. Adapt this |
wini | 0:10b4212318d4 | 181 | list to the LEDs on your evaluation board (Ref-LED). |
wini | 0:10b4212318d4 | 182 | |
wini | 0:10b4212318d4 | 183 | The LED name shows up in the UI, the LED type tells the UI the |
wini | 0:10b4212318d4 | 184 | color of the LED, and the ID is used as a handle by the UI. The UI |
wini | 0:10b4212318d4 | 185 | will send this handle to the device when sending LED control |
wini | 0:10b4212318d4 | 186 | messages. You can use any number sequence for the ID. We use the |
wini | 0:10b4212318d4 | 187 | sequence 1 to 4 so it's easy to map to a C array. |
wini | 0:10b4212318d4 | 188 | |
wini | 0:10b4212318d4 | 189 | This data is encoded as JSON and sent to the UI when a new UI |
wini | 0:10b4212318d4 | 190 | requests the device capabilities. |
wini | 0:10b4212318d4 | 191 | */ |
wini | 0:10b4212318d4 | 192 | static const LedInfo ledInfo[] = { |
wini | 0:10b4212318d4 | 193 | { |
wini | 0:10b4212318d4 | 194 | "LED 1", |
wini | 0:10b4212318d4 | 195 | LedColor_red, |
wini | 0:10b4212318d4 | 196 | 1 |
wini | 0:10b4212318d4 | 197 | }, |
wini | 0:10b4212318d4 | 198 | { |
wini | 0:10b4212318d4 | 199 | "LED 2", |
wini | 0:10b4212318d4 | 200 | LedColor_yellow, |
wini | 0:10b4212318d4 | 201 | 2 |
wini | 0:10b4212318d4 | 202 | }, |
wini | 0:10b4212318d4 | 203 | { |
wini | 0:10b4212318d4 | 204 | "LED 3", |
wini | 0:10b4212318d4 | 205 | LedColor_green, |
wini | 0:10b4212318d4 | 206 | 3 |
wini | 0:10b4212318d4 | 207 | }, |
wini | 0:10b4212318d4 | 208 | { |
wini | 0:10b4212318d4 | 209 | "LED 4", |
wini | 0:10b4212318d4 | 210 | LedColor_blue, |
wini | 0:10b4212318d4 | 211 | 4 |
wini | 0:10b4212318d4 | 212 | } |
wini | 0:10b4212318d4 | 213 | }; |
wini | 0:10b4212318d4 | 214 | |
wini | 0:10b4212318d4 | 215 | const LedInfo* |
wini | 0:10b4212318d4 | 216 | getLedInfo(int* len) |
wini | 0:10b4212318d4 | 217 | { |
wini | 0:10b4212318d4 | 218 | *len = sizeof(ledInfo) / sizeof(ledInfo[0]); |
wini | 0:10b4212318d4 | 219 | return ledInfo; |
wini | 0:10b4212318d4 | 220 | } |
wini | 0:10b4212318d4 | 221 | |
wini | 0:10b4212318d4 | 222 | /* The LEDs: used by getLedState and setLed |
wini | 0:10b4212318d4 | 223 | */ |
wini | 0:10b4212318d4 | 224 | static int leds[sizeof(ledInfo)/sizeof(ledInfo[1])]; |
wini | 0:10b4212318d4 | 225 | |
wini | 0:10b4212318d4 | 226 | /* Returns the LED on/off state for led with ID 'ledId'. The 'ledId' |
wini | 0:10b4212318d4 | 227 | is the 'handle' sent by the UI. |
wini | 0:10b4212318d4 | 228 | */ |
wini | 0:10b4212318d4 | 229 | int |
wini | 0:10b4212318d4 | 230 | getLedState(int ledId) |
wini | 0:10b4212318d4 | 231 | { |
wini | 0:10b4212318d4 | 232 | baAssert(ledId >= 1 && ledId <= sizeof(ledInfo)/sizeof(ledInfo[1])); |
wini | 0:10b4212318d4 | 233 | return leds[ledId-1]; |
wini | 0:10b4212318d4 | 234 | } |
wini | 0:10b4212318d4 | 235 | |
wini | 0:10b4212318d4 | 236 | |
wini | 0:10b4212318d4 | 237 | /* Set LED on device. The 'ledId' is the 'handle' sent by the UI. |
wini | 0:10b4212318d4 | 238 | */ |
wini | 0:10b4212318d4 | 239 | int |
wini | 0:10b4212318d4 | 240 | setLed(int ledId, int on) |
wini | 0:10b4212318d4 | 241 | { |
wini | 0:10b4212318d4 | 242 | if(ledId >= 1 && ledId <= sizeof(ledInfo)/sizeof(ledInfo[1])) |
wini | 0:10b4212318d4 | 243 | { |
wini | 0:10b4212318d4 | 244 | printf("Set LED %d %s\n", ledId, on ? "on" : "off"); |
wini | 0:10b4212318d4 | 245 | leds[ledId-1] = on; |
wini | 0:10b4212318d4 | 246 | return 0; |
wini | 0:10b4212318d4 | 247 | } |
wini | 0:10b4212318d4 | 248 | return -1; |
wini | 0:10b4212318d4 | 249 | } |
wini | 0:10b4212318d4 | 250 | |
wini | 0:10b4212318d4 | 251 | |
wini | 0:10b4212318d4 | 252 | /* The optional function setLedFromDevice requires non blocking |
wini | 0:10b4212318d4 | 253 | * keyboard I/O in the simulated version. The following code sets this |
wini | 0:10b4212318d4 | 254 | * up for WIN and UNIX. Remove this code for embedded use and change |
wini | 0:10b4212318d4 | 255 | * setLedFromDevice as explained below. |
wini | 0:10b4212318d4 | 256 | */ |
wini | 0:10b4212318d4 | 257 | #include <ctype.h> |
wini | 0:10b4212318d4 | 258 | #ifdef _WIN32 |
wini | 0:10b4212318d4 | 259 | |
wini | 0:10b4212318d4 | 260 | #include <conio.h> |
wini | 0:10b4212318d4 | 261 | #define xkbhit _kbhit |
wini | 0:10b4212318d4 | 262 | |
wini | 0:10b4212318d4 | 263 | static int |
wini | 0:10b4212318d4 | 264 | xgetch() |
wini | 0:10b4212318d4 | 265 | { |
wini | 0:10b4212318d4 | 266 | int c = _getch(); |
wini | 0:10b4212318d4 | 267 | if(c == 224) |
wini | 0:10b4212318d4 | 268 | { |
wini | 0:10b4212318d4 | 269 | switch(_getch()) |
wini | 0:10b4212318d4 | 270 | { |
wini | 0:10b4212318d4 | 271 | case 72: return KEY_UP_ARROW; |
wini | 0:10b4212318d4 | 272 | case 80: return KEY_DOWN_ARROW; |
wini | 0:10b4212318d4 | 273 | } |
wini | 0:10b4212318d4 | 274 | return 'A'; /* dummy value */ |
wini | 0:10b4212318d4 | 275 | } |
wini | 0:10b4212318d4 | 276 | return c; |
wini | 0:10b4212318d4 | 277 | |
wini | 0:10b4212318d4 | 278 | } |
wini | 0:10b4212318d4 | 279 | |
wini | 0:10b4212318d4 | 280 | |
wini | 0:10b4212318d4 | 281 | #else |
wini | 0:10b4212318d4 | 282 | |
wini | 0:10b4212318d4 | 283 | #include <sys/socket.h> |
wini | 0:10b4212318d4 | 284 | #include <arpa/inet.h> |
wini | 0:10b4212318d4 | 285 | #include <netdb.h> |
wini | 0:10b4212318d4 | 286 | #include <sys/ioctl.h> |
wini | 0:10b4212318d4 | 287 | #include <net/if.h> |
wini | 0:10b4212318d4 | 288 | #include <termios.h> |
wini | 0:10b4212318d4 | 289 | /* UNIX kbhit and getch simulation */ |
wini | 0:10b4212318d4 | 290 | static struct termios orgTs; |
wini | 0:10b4212318d4 | 291 | |
wini | 0:10b4212318d4 | 292 | static void |
wini | 0:10b4212318d4 | 293 | resetTerminalMode() |
wini | 0:10b4212318d4 | 294 | { |
wini | 0:10b4212318d4 | 295 | tcsetattr(0, TCSANOW, &orgTs); |
wini | 0:10b4212318d4 | 296 | } |
wini | 0:10b4212318d4 | 297 | |
wini | 0:10b4212318d4 | 298 | static void |
wini | 0:10b4212318d4 | 299 | setConioTerminalMode() |
wini | 0:10b4212318d4 | 300 | { |
wini | 0:10b4212318d4 | 301 | struct termios asyncTs; |
wini | 0:10b4212318d4 | 302 | tcgetattr(0, &orgTs); |
wini | 0:10b4212318d4 | 303 | memcpy(&asyncTs, &orgTs, sizeof(asyncTs)); |
wini | 0:10b4212318d4 | 304 | /* register cleanup handler, and set the new terminal mode */ |
wini | 0:10b4212318d4 | 305 | atexit(resetTerminalMode); |
wini | 0:10b4212318d4 | 306 | cfmakeraw(&asyncTs); |
wini | 0:10b4212318d4 | 307 | asyncTs.c_oflag=orgTs.c_oflag; |
wini | 0:10b4212318d4 | 308 | tcsetattr(0, TCSANOW, &asyncTs); |
wini | 0:10b4212318d4 | 309 | } |
wini | 0:10b4212318d4 | 310 | |
wini | 0:10b4212318d4 | 311 | static int |
wini | 0:10b4212318d4 | 312 | xkbhit() |
wini | 0:10b4212318d4 | 313 | { |
wini | 0:10b4212318d4 | 314 | struct timeval tv = { 0L, 0L }; |
wini | 0:10b4212318d4 | 315 | fd_set fds; |
wini | 0:10b4212318d4 | 316 | FD_ZERO(&fds); |
wini | 0:10b4212318d4 | 317 | FD_SET(0, &fds); |
wini | 0:10b4212318d4 | 318 | return select(1, &fds, NULL, NULL, &tv); |
wini | 0:10b4212318d4 | 319 | } |
wini | 0:10b4212318d4 | 320 | |
wini | 0:10b4212318d4 | 321 | static int |
wini | 0:10b4212318d4 | 322 | xgetch() |
wini | 0:10b4212318d4 | 323 | { |
wini | 0:10b4212318d4 | 324 | int r; |
wini | 0:10b4212318d4 | 325 | unsigned char c; |
wini | 0:10b4212318d4 | 326 | if ((r = read(0, &c, sizeof(c))) < 0) |
wini | 0:10b4212318d4 | 327 | return r; |
wini | 0:10b4212318d4 | 328 | if(c == 3) /* CTRL-C Linux */ |
wini | 0:10b4212318d4 | 329 | exit(0); |
wini | 0:10b4212318d4 | 330 | if(c == 27) |
wini | 0:10b4212318d4 | 331 | { |
wini | 0:10b4212318d4 | 332 | U16 x; |
wini | 0:10b4212318d4 | 333 | read(0, &x, sizeof(x)); |
wini | 0:10b4212318d4 | 334 | switch(x) |
wini | 0:10b4212318d4 | 335 | { |
wini | 0:10b4212318d4 | 336 | case 0x415B: return KEY_UP_ARROW; |
wini | 0:10b4212318d4 | 337 | case 0x425B: return KEY_DOWN_ARROW; |
wini | 0:10b4212318d4 | 338 | } |
wini | 0:10b4212318d4 | 339 | return 'A'; /* dummy value */ |
wini | 0:10b4212318d4 | 340 | } |
wini | 0:10b4212318d4 | 341 | return c; |
wini | 0:10b4212318d4 | 342 | } |
wini | 0:10b4212318d4 | 343 | |
wini | 0:10b4212318d4 | 344 | static void |
wini | 0:10b4212318d4 | 345 | die(const char* fmt, ...) |
wini | 0:10b4212318d4 | 346 | { |
wini | 0:10b4212318d4 | 347 | va_list varg; |
wini | 0:10b4212318d4 | 348 | va_start(varg, fmt); |
wini | 0:10b4212318d4 | 349 | vprintf(fmt, varg); |
wini | 0:10b4212318d4 | 350 | va_end(varg); |
wini | 0:10b4212318d4 | 351 | printf("\n"); |
wini | 0:10b4212318d4 | 352 | exit(1); |
wini | 0:10b4212318d4 | 353 | } |
wini | 0:10b4212318d4 | 354 | |
wini | 0:10b4212318d4 | 355 | static void |
wini | 0:10b4212318d4 | 356 | getMacAddr(char macaddr[6], const char* ifname) |
wini | 0:10b4212318d4 | 357 | { |
wini | 0:10b4212318d4 | 358 | char buf[8192] = {0}; |
wini | 0:10b4212318d4 | 359 | struct ifconf ifc = {0}; |
wini | 0:10b4212318d4 | 360 | struct ifreq *ifr = NULL; |
wini | 0:10b4212318d4 | 361 | int sck = 0; |
wini | 0:10b4212318d4 | 362 | int nInterfaces = 0; |
wini | 0:10b4212318d4 | 363 | int i = 0; |
wini | 0:10b4212318d4 | 364 | struct ifreq *item; |
wini | 0:10b4212318d4 | 365 | struct sockaddr *addr; |
wini | 0:10b4212318d4 | 366 | /* Get a socket handle. */ |
wini | 0:10b4212318d4 | 367 | sck = socket(PF_INET, SOCK_DGRAM, 0); |
wini | 0:10b4212318d4 | 368 | if(sck < 0) |
wini | 0:10b4212318d4 | 369 | die("socket: %s",strerror(errno)); |
wini | 0:10b4212318d4 | 370 | /* Query available interfaces. */ |
wini | 0:10b4212318d4 | 371 | ifc.ifc_len = sizeof(buf); |
wini | 0:10b4212318d4 | 372 | ifc.ifc_buf = buf; |
wini | 0:10b4212318d4 | 373 | if(ioctl(sck, SIOCGIFCONF, &ifc) < 0) |
wini | 0:10b4212318d4 | 374 | die("ioctl(SIOCGIFCONF) %s", strerror(errno)); |
wini | 0:10b4212318d4 | 375 | /* Iterate through the list of interfaces. */ |
wini | 0:10b4212318d4 | 376 | ifr = ifc.ifc_req; |
wini | 0:10b4212318d4 | 377 | nInterfaces = ifc.ifc_len / sizeof(struct ifreq); |
wini | 0:10b4212318d4 | 378 | for(i = 0; i < nInterfaces; i++) |
wini | 0:10b4212318d4 | 379 | { |
wini | 0:10b4212318d4 | 380 | unsigned long ipaddr; |
wini | 0:10b4212318d4 | 381 | item = &ifr[i]; |
wini | 0:10b4212318d4 | 382 | addr = &(item->ifr_addr); |
wini | 0:10b4212318d4 | 383 | /* Get the IP address*/ |
wini | 0:10b4212318d4 | 384 | if(ioctl(sck, SIOCGIFADDR, item) < 0) |
wini | 0:10b4212318d4 | 385 | { |
wini | 0:10b4212318d4 | 386 | perror("ioctl(OSIOCGIFADDR)"); |
wini | 0:10b4212318d4 | 387 | continue; |
wini | 0:10b4212318d4 | 388 | } |
wini | 0:10b4212318d4 | 389 | ipaddr = ((struct sockaddr_in *)addr)->sin_addr.s_addr; |
wini | 0:10b4212318d4 | 390 | if(0x100007F == ipaddr || 0 == ipaddr) |
wini | 0:10b4212318d4 | 391 | continue; |
wini | 0:10b4212318d4 | 392 | /* Get the MAC address */ |
wini | 0:10b4212318d4 | 393 | if(ioctl(sck, SIOCGIFHWADDR, item) < 0) { |
wini | 0:10b4212318d4 | 394 | perror("ioctl(SIOCGIFHWADDR)"); |
wini | 0:10b4212318d4 | 395 | continue; |
wini | 0:10b4212318d4 | 396 | } |
wini | 0:10b4212318d4 | 397 | break; |
wini | 0:10b4212318d4 | 398 | } |
wini | 0:10b4212318d4 | 399 | close(sck); |
wini | 0:10b4212318d4 | 400 | if(i == nInterfaces) |
wini | 0:10b4212318d4 | 401 | die("Cannot get a MAC address\n"); |
wini | 0:10b4212318d4 | 402 | memcpy(macaddr, item->ifr_hwaddr.sa_data, 6); |
wini | 0:10b4212318d4 | 403 | } |
wini | 0:10b4212318d4 | 404 | #endif |
wini | 0:10b4212318d4 | 405 | /* Endif UNIX/Linux specific code */ |
wini | 0:10b4212318d4 | 406 | |
wini | 0:10b4212318d4 | 407 | |
wini | 0:10b4212318d4 | 408 | /* Optional function that can be used to turn an LED on/off from the |
wini | 0:10b4212318d4 | 409 | device by using buttons. The function must return TRUE if a button |
wini | 0:10b4212318d4 | 410 | was pressed, otherwise FALSE must be returned. The LED state on/off |
wini | 0:10b4212318d4 | 411 | information is managed by the online web service. |
wini | 0:10b4212318d4 | 412 | */ |
wini | 0:10b4212318d4 | 413 | int |
wini | 0:10b4212318d4 | 414 | setLedFromDevice(int* ledId, int* on) |
wini | 0:10b4212318d4 | 415 | { |
wini | 0:10b4212318d4 | 416 | int ledLen; |
wini | 0:10b4212318d4 | 417 | const LedInfo* ledInfo = getLedInfo(&ledLen); |
wini | 0:10b4212318d4 | 418 | if(xkbhit()) |
wini | 0:10b4212318d4 | 419 | { |
wini | 0:10b4212318d4 | 420 | int base,i; |
wini | 0:10b4212318d4 | 421 | int c = xgetch(); |
wini | 0:10b4212318d4 | 422 | if(c == KEY_UP_ARROW) |
wini | 0:10b4212318d4 | 423 | { |
wini | 0:10b4212318d4 | 424 | currentTemperature += 8; /* increment by 0.8 celcius */ |
wini | 0:10b4212318d4 | 425 | return 0; |
wini | 0:10b4212318d4 | 426 | } |
wini | 0:10b4212318d4 | 427 | if(c == KEY_DOWN_ARROW) |
wini | 0:10b4212318d4 | 428 | { |
wini | 0:10b4212318d4 | 429 | currentTemperature -= 8; /* decrement by 0.8 celcius */ |
wini | 0:10b4212318d4 | 430 | return 0; |
wini | 0:10b4212318d4 | 431 | } |
wini | 0:10b4212318d4 | 432 | if(isupper(c)) |
wini | 0:10b4212318d4 | 433 | { |
wini | 0:10b4212318d4 | 434 | *on=1; |
wini | 0:10b4212318d4 | 435 | base='A'; |
wini | 0:10b4212318d4 | 436 | } |
wini | 0:10b4212318d4 | 437 | else |
wini | 0:10b4212318d4 | 438 | { |
wini | 0:10b4212318d4 | 439 | *on=0; |
wini | 0:10b4212318d4 | 440 | base='a'; |
wini | 0:10b4212318d4 | 441 | } |
wini | 0:10b4212318d4 | 442 | c -= base; |
wini | 0:10b4212318d4 | 443 | base=0; |
wini | 0:10b4212318d4 | 444 | for(i = 0 ; i < ledLen ; i++) |
wini | 0:10b4212318d4 | 445 | { |
wini | 0:10b4212318d4 | 446 | if(ledInfo[i].id == c) |
wini | 0:10b4212318d4 | 447 | { |
wini | 0:10b4212318d4 | 448 | base=1; |
wini | 0:10b4212318d4 | 449 | break; |
wini | 0:10b4212318d4 | 450 | } |
wini | 0:10b4212318d4 | 451 | } |
wini | 0:10b4212318d4 | 452 | if(base) |
wini | 0:10b4212318d4 | 453 | { |
wini | 0:10b4212318d4 | 454 | *ledId = c; |
wini | 0:10b4212318d4 | 455 | return 1; |
wini | 0:10b4212318d4 | 456 | } |
wini | 0:10b4212318d4 | 457 | printf("Invalid LedId %d. Valid keys (upper/lower): ",c); |
wini | 0:10b4212318d4 | 458 | for(i = 0 ; i < ledLen ; i++) |
wini | 0:10b4212318d4 | 459 | printf("%c ",'A'+ledInfo[i].id); |
wini | 0:10b4212318d4 | 460 | printf("\n"); |
wini | 0:10b4212318d4 | 461 | } |
wini | 0:10b4212318d4 | 462 | |
wini | 0:10b4212318d4 | 463 | { /* Print out usage info at startup */ |
wini | 0:10b4212318d4 | 464 | static int oneshot=0; |
wini | 0:10b4212318d4 | 465 | if( ! oneshot ) |
wini | 0:10b4212318d4 | 466 | { |
wini | 0:10b4212318d4 | 467 | oneshot = 1; |
wini | 0:10b4212318d4 | 468 | xprintf( |
wini | 0:10b4212318d4 | 469 | ("Set LED from keyboard. Uppercase = ON, lowercase = OFF.\n" |
wini | 0:10b4212318d4 | 470 | "Switching LED state updates UI in all connected browsers.\n")); |
wini | 0:10b4212318d4 | 471 | } |
wini | 0:10b4212318d4 | 472 | } |
wini | 0:10b4212318d4 | 473 | return 0; |
wini | 0:10b4212318d4 | 474 | } |
wini | 0:10b4212318d4 | 475 | |
wini | 0:10b4212318d4 | 476 | |
wini | 0:10b4212318d4 | 477 | int getTemp(void) |
wini | 0:10b4212318d4 | 478 | { |
wini | 0:10b4212318d4 | 479 | return currentTemperature; |
wini | 0:10b4212318d4 | 480 | } |
wini | 0:10b4212318d4 | 481 | |
wini | 0:10b4212318d4 | 482 | |
wini | 0:10b4212318d4 | 483 | const char* getDevName(void) |
wini | 0:10b4212318d4 | 484 | { |
wini | 0:10b4212318d4 | 485 | static char devInfo[100]; |
wini | 0:10b4212318d4 | 486 | char* ptr; |
wini | 0:10b4212318d4 | 487 | strcpy(devInfo,"Simulated Device: "); |
wini | 0:10b4212318d4 | 488 | ptr = devInfo + strlen(devInfo); |
wini | 0:10b4212318d4 | 489 | gethostname(ptr, 100 - (ptr - devInfo)); |
wini | 0:10b4212318d4 | 490 | return devInfo; |
wini | 0:10b4212318d4 | 491 | } |
wini | 0:10b4212318d4 | 492 | |
wini | 0:10b4212318d4 | 493 | |
wini | 0:10b4212318d4 | 494 | static void printUniqueID(const char* uuid, int uuidLen) |
wini | 0:10b4212318d4 | 495 | { |
wini | 0:10b4212318d4 | 496 | int i; |
wini | 0:10b4212318d4 | 497 | printf("UUID: "); |
wini | 0:10b4212318d4 | 498 | for(i = 0 ; i < uuidLen ; i++) |
wini | 0:10b4212318d4 | 499 | printf("%X ", (unsigned int)((U8)uuid[i])); |
wini | 0:10b4212318d4 | 500 | printf("\n"); |
wini | 0:10b4212318d4 | 501 | } |
wini | 0:10b4212318d4 | 502 | |
wini | 0:10b4212318d4 | 503 | |
wini | 0:10b4212318d4 | 504 | int getUniqueId(const char** id) |
wini | 0:10b4212318d4 | 505 | { |
wini | 0:10b4212318d4 | 506 | #ifdef _WIN32 |
wini | 0:10b4212318d4 | 507 | UUID winid; |
wini | 0:10b4212318d4 | 508 | static char uuid[8]; |
wini | 0:10b4212318d4 | 509 | if(RPC_S_OK == UuidCreateSequential(&winid)) |
wini | 0:10b4212318d4 | 510 | memcpy(uuid,winid.Data4,8); |
wini | 0:10b4212318d4 | 511 | else |
wini | 0:10b4212318d4 | 512 | memset(uuid,0,8); |
wini | 0:10b4212318d4 | 513 | printUniqueID(uuid, 8); |
wini | 0:10b4212318d4 | 514 | *id = uuid; |
wini | 0:10b4212318d4 | 515 | return 8; |
wini | 0:10b4212318d4 | 516 | #else |
wini | 0:10b4212318d4 | 517 | static char addr[6]; |
wini | 0:10b4212318d4 | 518 | getMacAddr(addr, "eth0"); |
wini | 0:10b4212318d4 | 519 | printUniqueID(addr, 6); |
wini | 0:10b4212318d4 | 520 | *id = addr; |
wini | 0:10b4212318d4 | 521 | return 6; |
wini | 0:10b4212318d4 | 522 | #endif |
wini | 0:10b4212318d4 | 523 | } |
wini | 0:10b4212318d4 | 524 | |
wini | 0:10b4212318d4 | 525 | int main(int argc, char* argv[]) |
wini | 0:10b4212318d4 | 526 | { |
wini | 0:10b4212318d4 | 527 | #ifdef _WIN32 |
wini | 0:10b4212318d4 | 528 | WSADATA wsaData; |
wini | 0:10b4212318d4 | 529 | /* Windows specific: Start winsock library */ |
wini | 0:10b4212318d4 | 530 | WSAStartup(MAKEWORD(1,1), &wsaData); |
wini | 0:10b4212318d4 | 531 | #else |
wini | 0:10b4212318d4 | 532 | setConioTerminalMode(); |
wini | 0:10b4212318d4 | 533 | #endif |
wini | 0:10b4212318d4 | 534 | |
wini | 0:10b4212318d4 | 535 | if(argc > 1) |
wini | 0:10b4212318d4 | 536 | { |
wini | 0:10b4212318d4 | 537 | simpleMqUrl = argv[1]; |
wini | 0:10b4212318d4 | 538 | xprintf(("Overriding broker URL\n\tfrom %s\n\tto %s\n%s\n\n", |
wini | 0:10b4212318d4 | 539 | SIMPLEMQ_URL,simpleMqUrl, |
wini | 0:10b4212318d4 | 540 | "Note: error messages will include original broker name")); |
wini | 0:10b4212318d4 | 541 | |
wini | 0:10b4212318d4 | 542 | } |
wini | 0:10b4212318d4 | 543 | else |
wini | 0:10b4212318d4 | 544 | { |
wini | 0:10b4212318d4 | 545 | simpleMqUrl = SIMPLEMQ_URL; |
wini | 0:10b4212318d4 | 546 | } |
wini | 0:10b4212318d4 | 547 | |
wini | 0:10b4212318d4 | 548 | mainTask(0); |
wini | 0:10b4212318d4 | 549 | printf("Press return key to exit\n"); |
wini | 0:10b4212318d4 | 550 | getchar(); |
wini | 0:10b4212318d4 | 551 | return 0; |
wini | 0:10b4212318d4 | 552 | } |
wini | 0:10b4212318d4 | 553 | |
wini | 0:10b4212318d4 | 554 | #endif /* HOST_PLATFORM */ |
wini | 0:10b4212318d4 | 555 | |
wini | 0:10b4212318d4 | 556 | |
wini | 0:10b4212318d4 | 557 | |
wini | 0:10b4212318d4 | 558 | |
wini | 0:10b4212318d4 | 559 | /**************************************************************************** |
wini | 0:10b4212318d4 | 560 | **************************----------------------**************************** |
wini | 0:10b4212318d4 | 561 | **************************| GENERIC CODE BELOW |**************************** |
wini | 0:10b4212318d4 | 562 | **************************----------------------**************************** |
wini | 0:10b4212318d4 | 563 | ****************************************************************************/ |
wini | 0:10b4212318d4 | 564 | |
wini | 0:10b4212318d4 | 565 | #ifdef GETUNIQUEID |
wini | 0:10b4212318d4 | 566 | /* |
wini | 0:10b4212318d4 | 567 | The following getUniqueId function can be enabled on development |
wini | 0:10b4212318d4 | 568 | boards where you cannot fetch the MAC address or if the MAC address |
wini | 0:10b4212318d4 | 569 | is not globally unique (not set from factory). |
wini | 0:10b4212318d4 | 570 | |
wini | 0:10b4212318d4 | 571 | The SMQ broker requires a persistent (non random) unique ID for each |
wini | 0:10b4212318d4 | 572 | client. The broker uses this ID to detect board restarts, where the |
wini | 0:10b4212318d4 | 573 | old connection still lingers in the broker. The ID must for this |
wini | 0:10b4212318d4 | 574 | reason be the same when the board restarts. The following logic |
wini | 0:10b4212318d4 | 575 | fetches the WAN address from a specially constructed service. This |
wini | 0:10b4212318d4 | 576 | address is then combined with the local LAN address. The LAN address |
wini | 0:10b4212318d4 | 577 | will most likely be the same when the board restarts, even with |
wini | 0:10b4212318d4 | 578 | DHCP. The address may change if the board has been offline for a |
wini | 0:10b4212318d4 | 579 | longer time, but in that case, the lingering connection in the |
wini | 0:10b4212318d4 | 580 | broker will have been removed by the time the board restarts. |
wini | 0:10b4212318d4 | 581 | */ |
wini | 0:10b4212318d4 | 582 | int getUniqueId(const char** id) |
wini | 0:10b4212318d4 | 583 | { |
wini | 0:10b4212318d4 | 584 | SOCKET sock; |
wini | 0:10b4212318d4 | 585 | S32 len = -1; |
wini | 0:10b4212318d4 | 586 | if( ! se_connect(&sock, "simplemq.com", 80) ) |
wini | 0:10b4212318d4 | 587 | { |
wini | 0:10b4212318d4 | 588 | /* The following service is designed to send back the WAN IP |
wini | 0:10b4212318d4 | 589 | * address without sending any HTTP headers. |
wini | 0:10b4212318d4 | 590 | */ |
wini | 0:10b4212318d4 | 591 | static const char cmd[]={ |
wini | 0:10b4212318d4 | 592 | "GET /addr.lsp HTTP/1.0\r\nHost:simplemq.com\r\n\r\n"}; |
wini | 0:10b4212318d4 | 593 | static char uuid[40]; |
wini | 0:10b4212318d4 | 594 | se_send(&sock, cmd, sizeof(cmd)-1); |
wini | 0:10b4212318d4 | 595 | len = se_recv(&sock, uuid, sizeof(uuid) - 16, 1000); |
wini | 0:10b4212318d4 | 596 | if(len > 0) |
wini | 0:10b4212318d4 | 597 | { |
wini | 0:10b4212318d4 | 598 | int status; |
wini | 0:10b4212318d4 | 599 | se_getSockName(&sock,uuid+len,&status); |
wini | 0:10b4212318d4 | 600 | if( status > 1 ) |
wini | 0:10b4212318d4 | 601 | { |
wini | 0:10b4212318d4 | 602 | *id = uuid; |
wini | 0:10b4212318d4 | 603 | len += status; |
wini | 0:10b4212318d4 | 604 | #if HOST_PLATFORM |
wini | 0:10b4212318d4 | 605 | printUniqueID(uuid, len); |
wini | 0:10b4212318d4 | 606 | #endif |
wini | 0:10b4212318d4 | 607 | } |
wini | 0:10b4212318d4 | 608 | } |
wini | 0:10b4212318d4 | 609 | se_close(&sock); |
wini | 0:10b4212318d4 | 610 | } |
wini | 0:10b4212318d4 | 611 | return len; |
wini | 0:10b4212318d4 | 612 | } |
wini | 0:10b4212318d4 | 613 | #endif |
wini | 0:10b4212318d4 | 614 | |
wini | 0:10b4212318d4 | 615 | |
wini | 0:10b4212318d4 | 616 | |
wini | 0:10b4212318d4 | 617 | |
wini | 0:10b4212318d4 | 618 | static const char* |
wini | 0:10b4212318d4 | 619 | ledType2String(LedColor t) |
wini | 0:10b4212318d4 | 620 | { |
wini | 0:10b4212318d4 | 621 | switch(t) |
wini | 0:10b4212318d4 | 622 | { |
wini | 0:10b4212318d4 | 623 | case LedColor_red: return "red"; |
wini | 0:10b4212318d4 | 624 | case LedColor_yellow: return "yellow"; |
wini | 0:10b4212318d4 | 625 | case LedColor_green: return "green"; |
wini | 0:10b4212318d4 | 626 | case LedColor_blue: return "blue"; |
wini | 0:10b4212318d4 | 627 | } |
wini | 0:10b4212318d4 | 628 | baAssert(0); |
wini | 0:10b4212318d4 | 629 | return ""; |
wini | 0:10b4212318d4 | 630 | } |
wini | 0:10b4212318d4 | 631 | |
wini | 0:10b4212318d4 | 632 | |
wini | 0:10b4212318d4 | 633 | /* Send the device capabilities as JSON to the browser. Note: we could |
wini | 0:10b4212318d4 | 634 | have used our JSON library for creating the JSON, but the library |
wini | 0:10b4212318d4 | 635 | adds additional code. We have opted to manually craft the JSON |
wini | 0:10b4212318d4 | 636 | instead of using the JSON library. This keeps the code size |
wini | 0:10b4212318d4 | 637 | down. Manually crafting JSON data is easy, parsing JSON is not |
wini | 0:10b4212318d4 | 638 | easy. However, we have no need for parsing JSON in this demo. |
wini | 0:10b4212318d4 | 639 | |
wini | 0:10b4212318d4 | 640 | You can optionally rewrite this code and use the following JSON |
wini | 0:10b4212318d4 | 641 | library: https://realtimelogic.com/products/json/ |
wini | 0:10b4212318d4 | 642 | |
wini | 0:10b4212318d4 | 643 | When you manually craft JSON, it can be good to use a JSON lint |
wini | 0:10b4212318d4 | 644 | parser if you should get a parse error in the browser. The JSON |
wini | 0:10b4212318d4 | 645 | lint parser will give you much better error reporting: |
wini | 0:10b4212318d4 | 646 | http://jsonlint.com/ |
wini | 0:10b4212318d4 | 647 | */ |
wini | 0:10b4212318d4 | 648 | static int |
wini | 0:10b4212318d4 | 649 | sendDevInfo(SharkMQ* smq, const char* ipaddr, U32 tid, U32 subtid) |
wini | 0:10b4212318d4 | 650 | { |
wini | 0:10b4212318d4 | 651 | int i, ledLen; |
wini | 0:10b4212318d4 | 652 | char buf[11]; |
wini | 0:10b4212318d4 | 653 | char *ptr; |
wini | 0:10b4212318d4 | 654 | int val; |
wini | 0:10b4212318d4 | 655 | const LedInfo* ledInfo = getLedInfo(&ledLen); |
wini | 0:10b4212318d4 | 656 | |
wini | 0:10b4212318d4 | 657 | SharkMQ_wrtstr(smq, "{\"ipaddr\":\""); |
wini | 0:10b4212318d4 | 658 | SharkMQ_wrtstr(smq, ipaddr); |
wini | 0:10b4212318d4 | 659 | SharkMQ_wrtstr(smq, "\",\"devname\":\""); |
wini | 0:10b4212318d4 | 660 | SharkMQ_wrtstr(smq, getDevName()); |
wini | 0:10b4212318d4 | 661 | SharkMQ_wrtstr(smq, "\",\"leds\":["); |
wini | 0:10b4212318d4 | 662 | |
wini | 0:10b4212318d4 | 663 | /* Write JSON: |
wini | 0:10b4212318d4 | 664 | { |
wini | 0:10b4212318d4 | 665 | "id": number, |
wini | 0:10b4212318d4 | 666 | "name": string, |
wini | 0:10b4212318d4 | 667 | "color": string, |
wini | 0:10b4212318d4 | 668 | "on": boolean |
wini | 0:10b4212318d4 | 669 | } |
wini | 0:10b4212318d4 | 670 | */ |
wini | 0:10b4212318d4 | 671 | for(i = 0 ; i < ledLen ; i++) |
wini | 0:10b4212318d4 | 672 | { |
wini | 0:10b4212318d4 | 673 | ptr = &buf[(sizeof buf) - 1]; |
wini | 0:10b4212318d4 | 674 | val = ledInfo[i].id; |
wini | 0:10b4212318d4 | 675 | *ptr = 0; |
wini | 0:10b4212318d4 | 676 | if(i != 0) |
wini | 0:10b4212318d4 | 677 | SharkMQ_wrtstr(smq,","); |
wini | 0:10b4212318d4 | 678 | SharkMQ_wrtstr(smq, "{\"id\":"); |
wini | 0:10b4212318d4 | 679 | do { /* convert number to string */ |
wini | 0:10b4212318d4 | 680 | int r = val % 10U; |
wini | 0:10b4212318d4 | 681 | val /= 10U; |
wini | 0:10b4212318d4 | 682 | *--ptr = (char)('0' + r); |
wini | 0:10b4212318d4 | 683 | } while (val && ptr > buf); |
wini | 0:10b4212318d4 | 684 | SharkMQ_wrtstr(smq, ptr); /* number converted to string */ |
wini | 0:10b4212318d4 | 685 | SharkMQ_wrtstr(smq, ",\"name\":\""); |
wini | 0:10b4212318d4 | 686 | SharkMQ_wrtstr(smq, ledInfo[i].name); |
wini | 0:10b4212318d4 | 687 | SharkMQ_wrtstr(smq, "\",\"color\":\""); |
wini | 0:10b4212318d4 | 688 | SharkMQ_wrtstr(smq, ledType2String(ledInfo[i].color)); |
wini | 0:10b4212318d4 | 689 | SharkMQ_wrtstr(smq, "\",\"on\":"); |
wini | 0:10b4212318d4 | 690 | SharkMQ_wrtstr(smq, getLedState(ledInfo[i].id)?"true":"false"); |
wini | 0:10b4212318d4 | 691 | SharkMQ_wrtstr(smq, "}"); |
wini | 0:10b4212318d4 | 692 | } |
wini | 0:10b4212318d4 | 693 | #ifdef ENABLE_TEMP |
wini | 0:10b4212318d4 | 694 | SharkMQ_wrtstr(smq, "],\"temp\":"); |
wini | 0:10b4212318d4 | 695 | ptr = &buf[(sizeof buf) - 1]; |
wini | 0:10b4212318d4 | 696 | *ptr = 0; |
wini | 0:10b4212318d4 | 697 | val = getTemp(); |
wini | 0:10b4212318d4 | 698 | if(val < 0) |
wini | 0:10b4212318d4 | 699 | { |
wini | 0:10b4212318d4 | 700 | val = -val; |
wini | 0:10b4212318d4 | 701 | i=TRUE; |
wini | 0:10b4212318d4 | 702 | } |
wini | 0:10b4212318d4 | 703 | else |
wini | 0:10b4212318d4 | 704 | i=FALSE; |
wini | 0:10b4212318d4 | 705 | do { /* convert number to string */ |
wini | 0:10b4212318d4 | 706 | int r = val % 10U; |
wini | 0:10b4212318d4 | 707 | val /= 10U; |
wini | 0:10b4212318d4 | 708 | *--ptr = (char)('0' + r); |
wini | 0:10b4212318d4 | 709 | } while (val && ptr > buf); |
wini | 0:10b4212318d4 | 710 | if(i) |
wini | 0:10b4212318d4 | 711 | *--ptr='-'; |
wini | 0:10b4212318d4 | 712 | SharkMQ_wrtstr(smq, ptr); /* number converted to string */ |
wini | 0:10b4212318d4 | 713 | SharkMQ_wrtstr(smq, "}"); |
wini | 0:10b4212318d4 | 714 | #else |
wini | 0:10b4212318d4 | 715 | SharkMQ_wrtstr(smq, "]}"); |
wini | 0:10b4212318d4 | 716 | #endif |
wini | 0:10b4212318d4 | 717 | return SharkMQ_pubflush(smq,tid,subtid); |
wini | 0:10b4212318d4 | 718 | } |
wini | 0:10b4212318d4 | 719 | |
wini | 0:10b4212318d4 | 720 | |
wini | 0:10b4212318d4 | 721 | /* |
wini | 0:10b4212318d4 | 722 | The M2M-LED main function does not return unless the code cannot |
wini | 0:10b4212318d4 | 723 | connect to the broker or the connection should break. The return |
wini | 0:10b4212318d4 | 724 | value 0 means that the caller can attempt to reconnect by calling |
wini | 0:10b4212318d4 | 725 | this function again. |
wini | 0:10b4212318d4 | 726 | */ |
wini | 0:10b4212318d4 | 727 | static int |
wini | 0:10b4212318d4 | 728 | m2mled(SharkMQ* smq, SharkSslCon* scon, |
wini | 0:10b4212318d4 | 729 | const char* smqUniqueId, int smqUniqueIdLen) |
wini | 0:10b4212318d4 | 730 | { |
wini | 0:10b4212318d4 | 731 | U32 displayTid=0; /* Topic ID (Tid) for "/m2m/led/display" */ |
wini | 0:10b4212318d4 | 732 | U32 ledSubTid=0; /* Sub Topic ID for "led" */ |
wini | 0:10b4212318d4 | 733 | U32 deviceTid=0; /* Tid for "/m2m/led/device" */ |
wini | 0:10b4212318d4 | 734 | U32 devInfoSubTid=0; /* Sub Topic ID for "devinfo" */ |
wini | 0:10b4212318d4 | 735 | #ifdef ENABLE_TEMP |
wini | 0:10b4212318d4 | 736 | U32 tempTid=0; /* Tid for "/m2m/temp" */ |
wini | 0:10b4212318d4 | 737 | S16 temperature = (S16)getTemp(); /* current temperature */ |
wini | 0:10b4212318d4 | 738 | #endif |
wini | 0:10b4212318d4 | 739 | char ipaddr[16]; |
wini | 0:10b4212318d4 | 740 | |
wini | 0:10b4212318d4 | 741 | /* We make it possible to override the URL at the command prompt when |
wini | 0:10b4212318d4 | 742 | * in simulation mode. |
wini | 0:10b4212318d4 | 743 | */ |
wini | 0:10b4212318d4 | 744 | #if HOST_PLATFORM |
wini | 0:10b4212318d4 | 745 | const char* str=simpleMqUrl; |
wini | 0:10b4212318d4 | 746 | #else |
wini | 0:10b4212318d4 | 747 | const char* str=SIMPLEMQ_URL; |
wini | 0:10b4212318d4 | 748 | #endif |
wini | 0:10b4212318d4 | 749 | |
wini | 0:10b4212318d4 | 750 | xprintf(("Connecting to %s\n", str)); |
wini | 0:10b4212318d4 | 751 | smq->timeout = 3000; /* Bail out if the connection takes this long */ |
wini | 0:10b4212318d4 | 752 | setProgramStatus(ProgramStatus_Connecting); |
wini | 0:10b4212318d4 | 753 | if(SharkMQ_init(smq, scon, str, 0) < 0) |
wini | 0:10b4212318d4 | 754 | { |
wini | 0:10b4212318d4 | 755 | xprintf(("Cannot establish connection, status: %d\n", smq->status)); |
wini | 0:10b4212318d4 | 756 | switch(smq->status) |
wini | 0:10b4212318d4 | 757 | { |
wini | 0:10b4212318d4 | 758 | case -1: |
wini | 0:10b4212318d4 | 759 | str="Socket error!"; |
wini | 0:10b4212318d4 | 760 | setProgramStatus(ProgramStatus_SocketError); |
wini | 0:10b4212318d4 | 761 | break; |
wini | 0:10b4212318d4 | 762 | case -2: |
wini | 0:10b4212318d4 | 763 | str="Cannot resolve IP address for " SIMPLEMQ_DOMAIN "."; |
wini | 0:10b4212318d4 | 764 | setProgramStatus(ProgramStatus_DnsError); |
wini | 0:10b4212318d4 | 765 | break; |
wini | 0:10b4212318d4 | 766 | default: |
wini | 0:10b4212318d4 | 767 | str="Cannot connect to " SIMPLEMQ_DOMAIN "."; |
wini | 0:10b4212318d4 | 768 | setProgramStatus(ProgramStatus_ConnectionError); |
wini | 0:10b4212318d4 | 769 | break; |
wini | 0:10b4212318d4 | 770 | } |
wini | 0:10b4212318d4 | 771 | xprintf(("%s\n", str)); |
wini | 0:10b4212318d4 | 772 | /* Cannot reconnect if any of the following are true: */ |
wini | 0:10b4212318d4 | 773 | return smq->status==SMQE_BUF_OVERFLOW || smq->status==SMQE_INVALID_URL; |
wini | 0:10b4212318d4 | 774 | } |
wini | 0:10b4212318d4 | 775 | else if(smq->status != SharkSslConTrust_CertCn) |
wini | 0:10b4212318d4 | 776 | { |
wini | 0:10b4212318d4 | 777 | setProgramStatus(ProgramStatus_CertificateNotTrustedError); |
wini | 0:10b4212318d4 | 778 | xprintf(("%cWARNING: certificate received from %s not trusted!\n", |
wini | 0:10b4212318d4 | 779 | 7,SIMPLEMQ_DOMAIN)); |
wini | 0:10b4212318d4 | 780 | } |
wini | 0:10b4212318d4 | 781 | |
wini | 0:10b4212318d4 | 782 | /* Fetch the IP address sent by the broker. We use this for the |
wini | 0:10b4212318d4 | 783 | * text shown in the left pane tab in the browser's user interface. |
wini | 0:10b4212318d4 | 784 | */ |
wini | 0:10b4212318d4 | 785 | strncpy(ipaddr, (char*)smq->buf, 16); |
wini | 0:10b4212318d4 | 786 | ipaddr[15]=0; |
wini | 0:10b4212318d4 | 787 | if(SharkMQ_connect(smq, |
wini | 0:10b4212318d4 | 788 | smqUniqueId, smqUniqueIdLen, |
wini | 0:10b4212318d4 | 789 | 0, 0, /* credentials */ |
wini | 0:10b4212318d4 | 790 | getDevName(), strlen(getDevName()))) |
wini | 0:10b4212318d4 | 791 | { |
wini | 0:10b4212318d4 | 792 | xprintf(("Connect failed, status: %d\n", smq->status)); |
wini | 0:10b4212318d4 | 793 | return smq->status == SMQE_BUF_OVERFLOW || smq->status > 0; |
wini | 0:10b4212318d4 | 794 | } |
wini | 0:10b4212318d4 | 795 | |
wini | 0:10b4212318d4 | 796 | xprintf(("\nConnected to %s.\n" |
wini | 0:10b4212318d4 | 797 | "Use a browser and navigate to this domain.\n\n", |
wini | 0:10b4212318d4 | 798 | str)); |
wini | 0:10b4212318d4 | 799 | setProgramStatus(ProgramStatus_DeviceReady); |
wini | 0:10b4212318d4 | 800 | |
wini | 0:10b4212318d4 | 801 | /* Request broker to return a topic ID for "/m2m/led/device", the |
wini | 0:10b4212318d4 | 802 | * topic where we publish the device capabilities as JSON data. |
wini | 0:10b4212318d4 | 803 | */ |
wini | 0:10b4212318d4 | 804 | SharkMQ_create(smq, "/m2m/led/device"); |
wini | 0:10b4212318d4 | 805 | |
wini | 0:10b4212318d4 | 806 | #ifdef ENABLE_TEMP |
wini | 0:10b4212318d4 | 807 | /* Request broker to return a topic ID for "/m2m/temp", the |
wini | 0:10b4212318d4 | 808 | * topic where we publish the device temperature. |
wini | 0:10b4212318d4 | 809 | */ |
wini | 0:10b4212318d4 | 810 | SharkMQ_create(smq, "/m2m/temp"); |
wini | 0:10b4212318d4 | 811 | #endif |
wini | 0:10b4212318d4 | 812 | |
wini | 0:10b4212318d4 | 813 | |
wini | 0:10b4212318d4 | 814 | /** Request broker to create two sub-topic IDs. We use the |
wini | 0:10b4212318d4 | 815 | * sub-topic IDs to further refine the messages published to the |
wini | 0:10b4212318d4 | 816 | * browser(s). |
wini | 0:10b4212318d4 | 817 | */ |
wini | 0:10b4212318d4 | 818 | SharkMQ_createsub(smq, "devinfo"); |
wini | 0:10b4212318d4 | 819 | SharkMQ_createsub(smq, "led"); |
wini | 0:10b4212318d4 | 820 | |
wini | 0:10b4212318d4 | 821 | /* Subscribe to browser "hello" messages. We send the device |
wini | 0:10b4212318d4 | 822 | * capabilities as JSON data to the browser's ephemeral ID when we |
wini | 0:10b4212318d4 | 823 | * receive a hello message from a browser. |
wini | 0:10b4212318d4 | 824 | */ |
wini | 0:10b4212318d4 | 825 | SharkMQ_subscribe(smq, "/m2m/led/display"); |
wini | 0:10b4212318d4 | 826 | |
wini | 0:10b4212318d4 | 827 | smq->timeout=50; /* Poll so we can locally update the LED buttons. */ |
wini | 0:10b4212318d4 | 828 | for(;;) |
wini | 0:10b4212318d4 | 829 | { |
wini | 0:10b4212318d4 | 830 | U8* msg; |
wini | 0:10b4212318d4 | 831 | U8 outData[2]; |
wini | 0:10b4212318d4 | 832 | int len = SharkMQ_getMessage(smq, &msg); |
wini | 0:10b4212318d4 | 833 | if(len < 0) /* We received a control message or an error code */ |
wini | 0:10b4212318d4 | 834 | { |
wini | 0:10b4212318d4 | 835 | switch(len) |
wini | 0:10b4212318d4 | 836 | { |
wini | 0:10b4212318d4 | 837 | /* Control messages */ |
wini | 0:10b4212318d4 | 838 | |
wini | 0:10b4212318d4 | 839 | /* Manage responses for create, createsub, and subscribe */ |
wini | 0:10b4212318d4 | 840 | case SMQ_SUBACK: /* ACK: "/m2m/led/display" */ |
wini | 0:10b4212318d4 | 841 | displayTid = smq->ptid; |
wini | 0:10b4212318d4 | 842 | break; |
wini | 0:10b4212318d4 | 843 | case SMQ_CREATEACK: /* ACK: "/m2m/temp" or "/m2m/led/device" */ |
wini | 0:10b4212318d4 | 844 | #ifdef ENABLE_TEMP |
wini | 0:10b4212318d4 | 845 | if( ! strcmp("/m2m/temp", (char*)msg ) ) |
wini | 0:10b4212318d4 | 846 | tempTid = smq->ptid; |
wini | 0:10b4212318d4 | 847 | else |
wini | 0:10b4212318d4 | 848 | #endif |
wini | 0:10b4212318d4 | 849 | { |
wini | 0:10b4212318d4 | 850 | deviceTid = smq->ptid; |
wini | 0:10b4212318d4 | 851 | SharkMQ_observe(smq, deviceTid); |
wini | 0:10b4212318d4 | 852 | } |
wini | 0:10b4212318d4 | 853 | break; |
wini | 0:10b4212318d4 | 854 | case SMQ_CREATESUBACK: /* We get a total of two messages */ |
wini | 0:10b4212318d4 | 855 | /* We get two suback messages ("devinfo" and "led") */ |
wini | 0:10b4212318d4 | 856 | if( ! strcmp("led", (char*)msg ) ) |
wini | 0:10b4212318d4 | 857 | { /* Ack for: SMQ_createsub(smq, "led"); */ |
wini | 0:10b4212318d4 | 858 | ledSubTid = smq->ptid; |
wini | 0:10b4212318d4 | 859 | } |
wini | 0:10b4212318d4 | 860 | else /* Must be ACK for devinfo */ |
wini | 0:10b4212318d4 | 861 | { /* Ack for: SMQ_createsub(smq, "devinfo"); */ |
wini | 0:10b4212318d4 | 862 | baAssert( ! strcmp("devinfo", (char*)msg) ); |
wini | 0:10b4212318d4 | 863 | baAssert(deviceTid); /* acks are in sequence */ |
wini | 0:10b4212318d4 | 864 | devInfoSubTid = smq->ptid; |
wini | 0:10b4212318d4 | 865 | /* We have sufficient info for publishing the device |
wini | 0:10b4212318d4 | 866 | info message. All connected browsers will |
wini | 0:10b4212318d4 | 867 | receive this message and update their UI accordingly. |
wini | 0:10b4212318d4 | 868 | */ |
wini | 0:10b4212318d4 | 869 | sendDevInfo(smq, ipaddr, deviceTid, devInfoSubTid); |
wini | 0:10b4212318d4 | 870 | } |
wini | 0:10b4212318d4 | 871 | break; |
wini | 0:10b4212318d4 | 872 | |
wini | 0:10b4212318d4 | 873 | case SMQ_SUBCHANGE: |
wini | 0:10b4212318d4 | 874 | xprintf(("Connected browsers: %d\n", smq->status)); |
wini | 0:10b4212318d4 | 875 | break; |
wini | 0:10b4212318d4 | 876 | |
wini | 0:10b4212318d4 | 877 | /* Error codes */ |
wini | 0:10b4212318d4 | 878 | |
wini | 0:10b4212318d4 | 879 | case SMQE_DISCONNECT: |
wini | 0:10b4212318d4 | 880 | xprintf(("Disconnect request from server\n")); |
wini | 0:10b4212318d4 | 881 | setProgramStatus(ProgramStatus_CloseCommandReceived); |
wini | 0:10b4212318d4 | 882 | return -1; |
wini | 0:10b4212318d4 | 883 | |
wini | 0:10b4212318d4 | 884 | case SMQE_BUF_OVERFLOW: |
wini | 0:10b4212318d4 | 885 | xprintf(("Increase buffer size\n")); |
wini | 0:10b4212318d4 | 886 | setProgramStatus(ProgramStatus_MemoryError); |
wini | 0:10b4212318d4 | 887 | return -1; /* Must exit */ |
wini | 0:10b4212318d4 | 888 | |
wini | 0:10b4212318d4 | 889 | default: |
wini | 0:10b4212318d4 | 890 | xprintf(("Rec Error: %d.\n",smq->status)); |
wini | 0:10b4212318d4 | 891 | setProgramStatus(ProgramStatus_InvalidCommandError); |
wini | 0:10b4212318d4 | 892 | return 0; |
wini | 0:10b4212318d4 | 893 | } |
wini | 0:10b4212318d4 | 894 | } |
wini | 0:10b4212318d4 | 895 | else if(len > 0) |
wini | 0:10b4212318d4 | 896 | { |
wini | 0:10b4212318d4 | 897 | if(smq->tid == displayTid) /* topic "display" */ |
wini | 0:10b4212318d4 | 898 | { |
wini | 0:10b4212318d4 | 899 | /* Send device info to the new display unit: Send to |
wini | 0:10b4212318d4 | 900 | * browser's ephemeral ID (ptid). |
wini | 0:10b4212318d4 | 901 | */ |
wini | 0:10b4212318d4 | 902 | sendDevInfo(smq, ipaddr, smq->ptid, devInfoSubTid); |
wini | 0:10b4212318d4 | 903 | } |
wini | 0:10b4212318d4 | 904 | else if(smq->tid == smq->clientTid) /* sent to our ephemeral tid */ |
wini | 0:10b4212318d4 | 905 | { |
wini | 0:10b4212318d4 | 906 | if(setLed(msg[0], msg[1])) |
wini | 0:10b4212318d4 | 907 | { |
wini | 0:10b4212318d4 | 908 | xprintf(("ptid %X attempting to set invalid LED %d\n", |
wini | 0:10b4212318d4 | 909 | smq->ptid, msg[0])); |
wini | 0:10b4212318d4 | 910 | return 0; |
wini | 0:10b4212318d4 | 911 | } |
wini | 0:10b4212318d4 | 912 | /* Update all display units */ |
wini | 0:10b4212318d4 | 913 | outData[0] = msg[0]; |
wini | 0:10b4212318d4 | 914 | outData[1] = msg[1]; |
wini | 0:10b4212318d4 | 915 | /* Publish to "/m2m/led/device", sub-topic "led" */ |
wini | 0:10b4212318d4 | 916 | SharkMQ_publish(smq, outData, 2, deviceTid, ledSubTid); |
wini | 0:10b4212318d4 | 917 | } |
wini | 0:10b4212318d4 | 918 | else |
wini | 0:10b4212318d4 | 919 | { |
wini | 0:10b4212318d4 | 920 | xprintf(("Received unknown tid %X\n", smq->tid)); |
wini | 0:10b4212318d4 | 921 | return 0; |
wini | 0:10b4212318d4 | 922 | } |
wini | 0:10b4212318d4 | 923 | } |
wini | 0:10b4212318d4 | 924 | else /* timeout */ |
wini | 0:10b4212318d4 | 925 | { |
wini | 0:10b4212318d4 | 926 | int x; /* used for storing ledId and temperature */ |
wini | 0:10b4212318d4 | 927 | int on; |
wini | 0:10b4212318d4 | 928 | if(setLedFromDevice(&x,&on)) /* If a local button was pressed */ |
wini | 0:10b4212318d4 | 929 | { /* Publish to all subscribed browsers and set the LED on/off */ |
wini | 0:10b4212318d4 | 930 | outData[0] = (U8)x; /* x is ledId */ |
wini | 0:10b4212318d4 | 931 | outData[1] = (U8)on; |
wini | 0:10b4212318d4 | 932 | /* Publish to "/m2m/led/device", sub-topic "led" */ |
wini | 0:10b4212318d4 | 933 | SharkMQ_publish(smq, outData, 2, deviceTid, ledSubTid); |
wini | 0:10b4212318d4 | 934 | setLed(x, on); /* set the LED on/off */ |
wini | 0:10b4212318d4 | 935 | } |
wini | 0:10b4212318d4 | 936 | #ifdef ENABLE_TEMP |
wini | 0:10b4212318d4 | 937 | x = getTemp(); |
wini | 0:10b4212318d4 | 938 | if(x != (int)temperature) |
wini | 0:10b4212318d4 | 939 | { |
wini | 0:10b4212318d4 | 940 | temperature = (S16)x; |
wini | 0:10b4212318d4 | 941 | outData[0] = (U8)(temperature >> 8); |
wini | 0:10b4212318d4 | 942 | outData[1] = (U8)temperature; |
wini | 0:10b4212318d4 | 943 | SharkMQ_publish(smq, outData, 2, tempTid, 0); |
wini | 0:10b4212318d4 | 944 | } |
wini | 0:10b4212318d4 | 945 | #endif |
wini | 0:10b4212318d4 | 946 | } |
wini | 0:10b4212318d4 | 947 | } |
wini | 0:10b4212318d4 | 948 | } |
wini | 0:10b4212318d4 | 949 | |
wini | 0:10b4212318d4 | 950 | |
wini | 0:10b4212318d4 | 951 | |
wini | 0:10b4212318d4 | 952 | #if SHARKSSL_ENABLE_SELECT_CIPHERSUITE == 1 |
wini | 0:10b4212318d4 | 953 | static void |
wini | 0:10b4212318d4 | 954 | setChaChaCipher(SharkSslCon* scon) |
wini | 0:10b4212318d4 | 955 | { |
wini | 0:10b4212318d4 | 956 | if(scon) |
wini | 0:10b4212318d4 | 957 | SharkSslCon_selectCiphersuite( |
wini | 0:10b4212318d4 | 958 | scon, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256); |
wini | 0:10b4212318d4 | 959 | } |
wini | 0:10b4212318d4 | 960 | #else |
wini | 0:10b4212318d4 | 961 | #define setChaChaCipher(scon) |
wini | 0:10b4212318d4 | 962 | #endif |
wini | 0:10b4212318d4 | 963 | |
wini | 0:10b4212318d4 | 964 | |
wini | 0:10b4212318d4 | 965 | void |
wini | 0:10b4212318d4 | 966 | mainTask(SeCtx* ctx) |
wini | 0:10b4212318d4 | 967 | { |
wini | 0:10b4212318d4 | 968 | static SharkSsl sharkSsl; |
wini | 0:10b4212318d4 | 969 | static SharkSslCon* scon; |
wini | 0:10b4212318d4 | 970 | static SharkMQ smq; |
wini | 0:10b4212318d4 | 971 | static U8 buf[127]; |
wini | 0:10b4212318d4 | 972 | |
wini | 0:10b4212318d4 | 973 | const char* smqUniqueId; |
wini | 0:10b4212318d4 | 974 | int smqUniqueIdLen; |
wini | 0:10b4212318d4 | 975 | smqUniqueIdLen = getUniqueId(&smqUniqueId); |
wini | 0:10b4212318d4 | 976 | if(smqUniqueIdLen < 1) |
wini | 0:10b4212318d4 | 977 | { |
wini | 0:10b4212318d4 | 978 | xprintf(("Cannot get unique ID: aborting.\n")); |
wini | 0:10b4212318d4 | 979 | setProgramStatus(ProgramStatus_SocketError); |
wini | 0:10b4212318d4 | 980 | return; |
wini | 0:10b4212318d4 | 981 | } |
wini | 0:10b4212318d4 | 982 | |
wini | 0:10b4212318d4 | 983 | SharkSsl_constructor(&sharkSsl, |
wini | 0:10b4212318d4 | 984 | SharkSsl_Client, /* Two options: client or server */ |
wini | 0:10b4212318d4 | 985 | 0, /* Not using SSL cache */ |
wini | 0:10b4212318d4 | 986 | 2000, /* initial inBuf size: Can grow */ |
wini | 0:10b4212318d4 | 987 | 2000); /* outBuf size: Fixed */ |
wini | 0:10b4212318d4 | 988 | |
wini | 0:10b4212318d4 | 989 | |
wini | 0:10b4212318d4 | 990 | /* (Ref-CA) |
wini | 0:10b4212318d4 | 991 | The following construction force the server to authenticate itself by |
wini | 0:10b4212318d4 | 992 | using an Elliptic Curve Certificate. |
wini | 0:10b4212318d4 | 993 | |
wini | 0:10b4212318d4 | 994 | CA_RTL_EC_256.pem is a Certificate Authority (CA) certificate |
wini | 0:10b4212318d4 | 995 | and we use this certificate to validate that we are in fact |
wini | 0:10b4212318d4 | 996 | connecting to simplemq.com and not someone pretending to |
wini | 0:10b4212318d4 | 997 | be this server. |
wini | 0:10b4212318d4 | 998 | |
wini | 0:10b4212318d4 | 999 | The online server simplemq.com has two certificates installed: |
wini | 0:10b4212318d4 | 1000 | one standard RSA certificate, which you can see if you navigate |
wini | 0:10b4212318d4 | 1001 | to https://simplemq.com, and one Elliptic Curve Certificate |
wini | 0:10b4212318d4 | 1002 | (ECC). |
wini | 0:10b4212318d4 | 1003 | |
wini | 0:10b4212318d4 | 1004 | The online server is configured to favor the RSA certificate |
wini | 0:10b4212318d4 | 1005 | which will be presented to the client unless the client tells |
wini | 0:10b4212318d4 | 1006 | the server that it can only use ECC, at which point the server |
wini | 0:10b4212318d4 | 1007 | is forced to send its ECC certificate to the client. |
wini | 0:10b4212318d4 | 1008 | |
wini | 0:10b4212318d4 | 1009 | The following construction makes sure we only use ECC by either |
wini | 0:10b4212318d4 | 1010 | using a SharkSSL library compiled with ECC support only (no RSA) |
wini | 0:10b4212318d4 | 1011 | or by specifically setting a cipher using ECC. |
wini | 0:10b4212318d4 | 1012 | |
wini | 0:10b4212318d4 | 1013 | See the following link for more information: |
wini | 0:10b4212318d4 | 1014 | realtimelogic.com/ba/doc/en/C/shark/md_md_Certificate_Management.html |
wini | 0:10b4212318d4 | 1015 | */ |
wini | 0:10b4212318d4 | 1016 | SharkSsl_setCAList(&sharkSsl, sharkSslCAList); |
wini | 0:10b4212318d4 | 1017 | |
wini | 0:10b4212318d4 | 1018 | SharkMQ_constructor(&smq, buf, sizeof(buf)); |
wini | 0:10b4212318d4 | 1019 | SharkMQ_setCtx(&smq, ctx); /* Required for non RTOS env. */ |
wini | 0:10b4212318d4 | 1020 | |
wini | 0:10b4212318d4 | 1021 | /* It is very important to seed the SharkSSL RNG generator */ |
wini | 0:10b4212318d4 | 1022 | sharkssl_entropy(baGetUnixTime() ^ (U32)&sharkSsl); |
wini | 0:10b4212318d4 | 1023 | scon = SharkSsl_createCon(&sharkSsl); |
wini | 0:10b4212318d4 | 1024 | setChaChaCipher(scon); |
wini | 0:10b4212318d4 | 1025 | setProgramStatus(ProgramStatus_Starting); |
wini | 0:10b4212318d4 | 1026 | while(scon && ! m2mled(&smq, scon, smqUniqueId, smqUniqueIdLen) ) |
wini | 0:10b4212318d4 | 1027 | { |
wini | 0:10b4212318d4 | 1028 | xprintf(("Closing connection; status: %d\n",smq.status)); |
wini | 0:10b4212318d4 | 1029 | SharkMQ_disconnect(&smq); |
wini | 0:10b4212318d4 | 1030 | SharkSsl_terminateCon(&sharkSsl, scon); |
wini | 0:10b4212318d4 | 1031 | scon = SharkSsl_createCon(&sharkSsl); |
wini | 0:10b4212318d4 | 1032 | setChaChaCipher(scon); |
wini | 0:10b4212318d4 | 1033 | setProgramStatus(ProgramStatus_Restarting); |
wini | 0:10b4212318d4 | 1034 | } |
wini | 0:10b4212318d4 | 1035 | SharkMQ_destructor(&smq); |
wini | 0:10b4212318d4 | 1036 | if(scon) |
wini | 0:10b4212318d4 | 1037 | SharkSsl_terminateCon(&sharkSsl, scon); |
wini | 0:10b4212318d4 | 1038 | else |
wini | 0:10b4212318d4 | 1039 | setProgramStatus(ProgramStatus_MemoryError); |
wini | 0:10b4212318d4 | 1040 | SharkSsl_destructor(&sharkSsl); |
wini | 0:10b4212318d4 | 1041 | } |
wini | 0:10b4212318d4 | 1042 |