AWS IoT demonstration using the Avnet Shield (AT&T LTE) and the FRDM-K64F target board.

Dependencies:   K64F_FATFileSystem

Fork of mbed-os-example-tls-tls-client by mbed-os-examples

Committer:
ampembeng
Date:
Mon Dec 19 20:52:28 2016 +0000
Revision:
25:91d771247ac8
Parent:
24:224c07ec3bd0
Updated the look/feel of the Python GUI to match the AT&T locker demo S3 page.  Added "assets" folder to support this.  Updated the README.

Who changed what in which revision?

UserRevisionLine numberNew contents of line
Janos Follath 0:fc70c47eecb4 1 /*
ampembeng 15:6f2798e45099 2 * AT&T IoT Starter Kit example using Amazon Web Service
mbed_official 12:1ae41c231014 3 */
ampembeng 15:6f2798e45099 4 #include "mbed.h"
ampembeng 15:6f2798e45099 5
ampembeng 18:6370da1de572 6 // SD File System
ampembeng 18:6370da1de572 7 #include "SDFileSystem.h"
ampembeng 18:6370da1de572 8
ampembeng 15:6f2798e45099 9 // Serial extension
ampembeng 15:6f2798e45099 10 #include "MODSERIAL.h"
Janos Follath 0:fc70c47eecb4 11
ampembeng 15:6f2798e45099 12 // Network includes
ampembeng 15:6f2798e45099 13 #include "WNCInterface.h"
ampembeng 15:6f2798e45099 14 #include "network_interface.h"
Janos Follath 0:fc70c47eecb4 15
ampembeng 15:6f2798e45099 16 // AWS includes
ampembeng 15:6f2798e45099 17 #include "aws_iot_log.h"
ampembeng 15:6f2798e45099 18 #include "aws_iot_version.h"
ampembeng 15:6f2798e45099 19 #include "aws_iot_shadow_interface.h"
ampembeng 15:6f2798e45099 20 #include "aws_iot_shadow_json_data.h"
ampembeng 15:6f2798e45099 21 #include "aws_iot_config.h"
ampembeng 15:6f2798e45099 22 #include "aws_iot_mqtt_interface.h"
mbed_official 12:1ae41c231014 23
ampembeng 20:ee34856ae510 24 // Sensors
ampembeng 20:ee34856ae510 25 #include "HTS221.h"
ampembeng 20:ee34856ae510 26
Janos Follath 0:fc70c47eecb4 27 #if DEBUG_LEVEL > 0
Janos Follath 0:fc70c47eecb4 28 #include "mbedtls/debug.h"
Janos Follath 0:fc70c47eecb4 29 #endif
Janos Follath 0:fc70c47eecb4 30
ampembeng 15:6f2798e45099 31 //=====================================================================================================================
ampembeng 15:6f2798e45099 32 //
ampembeng 15:6f2798e45099 33 // Defines
ampembeng 15:6f2798e45099 34 //
ampembeng 15:6f2798e45099 35 //=====================================================================================================================
ampembeng 15:6f2798e45099 36 // LED Colors
ampembeng 15:6f2798e45099 37 #define COLOR_OFF 0x00
ampembeng 15:6f2798e45099 38 #define COLOR_RED 0x01
ampembeng 15:6f2798e45099 39 #define COLOR_GREEN 0x02
ampembeng 15:6f2798e45099 40 #define COLOR_BLUE 0x04
ampembeng 15:6f2798e45099 41 #define COLOR_WHITE 0x07
ampembeng 15:6f2798e45099 42 #define NUM_COLORS 5
Janos Follath 0:fc70c47eecb4 43
ampembeng 15:6f2798e45099 44 // AWS defines
ampembeng 18:6370da1de572 45 #define PATH_MAX 1024
ampembeng 15:6f2798e45099 46 #define MAX_LENGTH_OF_UPDATE_JSON_BUFFER 200 // NOTE: Be wary of this if your JSON doc grows
ampembeng 15:6f2798e45099 47 #define SHADOW_SYNC_INTERVAL 3.0 // How often we sync with AWS Shadow (in seconds)
Janos Follath 0:fc70c47eecb4 48
ampembeng 15:6f2798e45099 49 // Comment out the following line if color is not supported on the terminal
ampembeng 15:6f2798e45099 50 //#define USE_COLOR
ampembeng 15:6f2798e45099 51 #ifdef USE_COLOR
ampembeng 15:6f2798e45099 52 #define BLK "\033[30m"
ampembeng 15:6f2798e45099 53 #define RED "\033[31m"
ampembeng 15:6f2798e45099 54 #define GRN "\033[32m"
ampembeng 15:6f2798e45099 55 #define YEL "\033[33m"
ampembeng 15:6f2798e45099 56 #define BLU "\033[34m"
ampembeng 15:6f2798e45099 57 #define MAG "\033[35m"
ampembeng 15:6f2798e45099 58 #define CYN "\033[36m"
ampembeng 15:6f2798e45099 59 #define WHT "\033[37m"
ampembeng 15:6f2798e45099 60 #define DEF "\033[39m"
ampembeng 15:6f2798e45099 61 #else
ampembeng 15:6f2798e45099 62 #define BLK
ampembeng 15:6f2798e45099 63 #define RED
ampembeng 15:6f2798e45099 64 #define GRN
ampembeng 15:6f2798e45099 65 #define YEL
ampembeng 15:6f2798e45099 66 #define BLU
ampembeng 15:6f2798e45099 67 #define MAG
ampembeng 15:6f2798e45099 68 #define CYN
ampembeng 15:6f2798e45099 69 #define WHT
ampembeng 15:6f2798e45099 70 #define DEF
Janos Follath 0:fc70c47eecb4 71 #endif
Janos Follath 0:fc70c47eecb4 72
ampembeng 20:ee34856ae510 73 // Sensor defines
ampembeng 20:ee34856ae510 74 #define CTOF(x) ((x)*1.8+32) // Temperature
ampembeng 20:ee34856ae510 75
ampembeng 15:6f2798e45099 76 //=====================================================================================================================
ampembeng 15:6f2798e45099 77 //
ampembeng 15:6f2798e45099 78 // Globals
ampembeng 15:6f2798e45099 79 //
ampembeng 15:6f2798e45099 80 //=====================================================================================================================
ampembeng 15:6f2798e45099 81 // Controls LED color
ampembeng 15:6f2798e45099 82 unsigned char ledColor = COLOR_OFF;
ampembeng 15:6f2798e45099 83
ampembeng 15:6f2798e45099 84 // Color cycle array (used with SW3 button presses)
ampembeng 15:6f2798e45099 85 unsigned char colorCycle[NUM_COLORS] = {COLOR_OFF, COLOR_RED, COLOR_GREEN, COLOR_BLUE, COLOR_WHITE};
Janos Follath 0:fc70c47eecb4 86
ampembeng 15:6f2798e45099 87 // Button interrupts
ampembeng 15:6f2798e45099 88 bool buttonOverride = false;
ampembeng 15:6f2798e45099 89 InterruptIn Interrupt(SW3);
ampembeng 15:6f2798e45099 90
ampembeng 18:6370da1de572 91 // These defines are pulled from aws_iot_config.h
ampembeng 15:6f2798e45099 92 char HostAddress[255] = AWS_IOT_MQTT_HOST;
ampembeng 18:6370da1de572 93 char MqttClientID[32] = AWS_IOT_MQTT_CLIENT_ID;
ampembeng 18:6370da1de572 94 char ThingName[32] = AWS_IOT_MY_THING_NAME;
ampembeng 18:6370da1de572 95 char PortString[5] = "8883";
ampembeng 15:6f2798e45099 96 uint32_t port = AWS_IOT_MQTT_PORT;
ampembeng 23:b9ff83dc965f 97 char iccidName[21] = "12345678901234567890";
Janos Follath 0:fc70c47eecb4 98
ampembeng 20:ee34856ae510 99 // Sensor data
ampembeng 20:ee34856ae510 100 float temperature = 0.0;
ampembeng 20:ee34856ae510 101 int humidity = 0;
ampembeng 20:ee34856ae510 102
ampembeng 23:b9ff83dc965f 103 // Temp/humidity object
ampembeng 23:b9ff83dc965f 104 HTS221 hts221;
ampembeng 23:b9ff83dc965f 105
ampembeng 15:6f2798e45099 106 //=====================================================================================================================
ampembeng 15:6f2798e45099 107 //
ampembeng 15:6f2798e45099 108 // Devices
ampembeng 15:6f2798e45099 109 //
ampembeng 15:6f2798e45099 110 //=====================================================================================================================
ampembeng 15:6f2798e45099 111 // GPIOs for RGB LED
ampembeng 15:6f2798e45099 112 DigitalOut led_green(LED_GREEN);
ampembeng 15:6f2798e45099 113 DigitalOut led_red(LED_RED);
ampembeng 15:6f2798e45099 114 DigitalOut led_blue(LED_BLUE);
Janos Follath 0:fc70c47eecb4 115
ampembeng 15:6f2798e45099 116 // USB Serial port (to PC)
ampembeng 15:6f2798e45099 117 MODSERIAL pc(USBTX,USBRX,256,256);
Janos Follath 0:fc70c47eecb4 118
ampembeng 18:6370da1de572 119 // SD card access (MOSI, MISO, SCK, CS)
ampembeng 18:6370da1de572 120 SDFileSystem sd(PTE3, PTE1, PTE2, PTE4, "sd");
ampembeng 18:6370da1de572 121
ampembeng 20:ee34856ae510 122 // I2C bus (SDA, SCL)
ampembeng 20:ee34856ae510 123 I2C i2c(PTC11, PTC10);
ampembeng 20:ee34856ae510 124
ampembeng 15:6f2798e45099 125 //=====================================================================================================================
ampembeng 15:6f2798e45099 126 //
ampembeng 15:6f2798e45099 127 // Functions
ampembeng 15:6f2798e45099 128 //
ampembeng 15:6f2798e45099 129 //=====================================================================================================================
ampembeng 15:6f2798e45099 130 //*********************************************************************************************************************
ampembeng 15:6f2798e45099 131 //* Prints the given format to the PC serial port. Exposed to all files via aws_iot_log.h
ampembeng 15:6f2798e45099 132 //*********************************************************************************************************************
ampembeng 15:6f2798e45099 133 void pc_print(const char * format, ...)
ampembeng 15:6f2798e45099 134 {
ampembeng 15:6f2798e45099 135 va_list vl;
ampembeng 15:6f2798e45099 136 va_start(vl, format);
ampembeng 15:6f2798e45099 137 pc.vprintf(format, vl);
ampembeng 15:6f2798e45099 138 va_end(vl);
ampembeng 15:6f2798e45099 139 }
Janos Follath 0:fc70c47eecb4 140
ampembeng 15:6f2798e45099 141 //*********************************************************************************************************************
ampembeng 15:6f2798e45099 142 //* Set the RGB LED's Color
ampembeng 15:6f2798e45099 143 //* LED Color 0=Off to 7=White. 3 bits represent BGR (bit0=Red, bit1=Green, bit2=Blue)
ampembeng 15:6f2798e45099 144 //*********************************************************************************************************************
ampembeng 15:6f2798e45099 145 void SetLedColor(unsigned char ucColor)
ampembeng 18:6370da1de572 146 {
ampembeng 15:6f2798e45099 147 //Note that when an LED is on, you write a 0 to it:
ampembeng 15:6f2798e45099 148 led_red = !(ucColor & 0x1); //bit 0
ampembeng 15:6f2798e45099 149 led_green = !(ucColor & 0x2); //bit 1
ampembeng 15:6f2798e45099 150 led_blue = !(ucColor & 0x4); //bit 2
ampembeng 15:6f2798e45099 151 }
Janos Follath 0:fc70c47eecb4 152
ampembeng 15:6f2798e45099 153 //*********************************************************************************************************************
ampembeng 15:6f2798e45099 154 //* SW3 Button handler. Finds the current LED color and sets the button to the next color in colorCycle[]
ampembeng 15:6f2798e45099 155 //*********************************************************************************************************************
ampembeng 15:6f2798e45099 156 void sw3ButtonHandler()
ampembeng 15:6f2798e45099 157 {
ampembeng 15:6f2798e45099 158 int i;
ampembeng 15:6f2798e45099 159 for(i=0; i < NUM_COLORS; i++) {
ampembeng 15:6f2798e45099 160 if (ledColor == colorCycle[i])
ampembeng 15:6f2798e45099 161 break;
ampembeng 15:6f2798e45099 162 }
ampembeng 15:6f2798e45099 163
ampembeng 15:6f2798e45099 164 // (circular-queue)
ampembeng 15:6f2798e45099 165 if (++i == NUM_COLORS)
ampembeng 15:6f2798e45099 166 i = 0;
ampembeng 15:6f2798e45099 167
ampembeng 15:6f2798e45099 168 ledColor = colorCycle[i];
ampembeng 15:6f2798e45099 169 SetLedColor(ledColor);
ampembeng 15:6f2798e45099 170 buttonOverride = true;
ampembeng 15:6f2798e45099 171 }
Janos Follath 0:fc70c47eecb4 172
ampembeng 23:b9ff83dc965f 173 //*********************************************************************************************************************
ampembeng 23:b9ff83dc965f 174 //* Print LED and sensor data
ampembeng 23:b9ff83dc965f 175 //*********************************************************************************************************************
ampembeng 23:b9ff83dc965f 176 void printData()
ampembeng 23:b9ff83dc965f 177 {
ampembeng 23:b9ff83dc965f 178 INFO("Temperature is: %0.2f F", temperature);
ampembeng 23:b9ff83dc965f 179 INFO("Humidity is: %02d", humidity);
ampembeng 23:b9ff83dc965f 180 switch (ledColor) {
ampembeng 23:b9ff83dc965f 181 case COLOR_OFF:
ampembeng 23:b9ff83dc965f 182 INFO("LED: Off");
ampembeng 23:b9ff83dc965f 183 break;
ampembeng 23:b9ff83dc965f 184 case COLOR_RED:
ampembeng 23:b9ff83dc965f 185 INFO("LED: Red");
ampembeng 23:b9ff83dc965f 186 break;
ampembeng 23:b9ff83dc965f 187 case COLOR_GREEN:
ampembeng 23:b9ff83dc965f 188 INFO("LED: Green");
ampembeng 23:b9ff83dc965f 189 break;
ampembeng 23:b9ff83dc965f 190 case COLOR_BLUE:
ampembeng 23:b9ff83dc965f 191 INFO("LED: Blue");
ampembeng 23:b9ff83dc965f 192 break;
ampembeng 23:b9ff83dc965f 193 case COLOR_WHITE:
ampembeng 23:b9ff83dc965f 194 INFO("LED: White");
ampembeng 23:b9ff83dc965f 195 break;
ampembeng 23:b9ff83dc965f 196 }
ampembeng 23:b9ff83dc965f 197 }
ampembeng 23:b9ff83dc965f 198
ampembeng 15:6f2798e45099 199 //=====================================================================================================================
ampembeng 15:6f2798e45099 200 //
ampembeng 15:6f2798e45099 201 // AWS Shadow Callbacks
ampembeng 15:6f2798e45099 202 //
ampembeng 15:6f2798e45099 203 //=====================================================================================================================
ampembeng 15:6f2798e45099 204 //*********************************************************************************************************************
ampembeng 15:6f2798e45099 205 //* This is the callback function that fires when an update is sent. It will print the update response status.
ampembeng 15:6f2798e45099 206 //*********************************************************************************************************************
ampembeng 15:6f2798e45099 207 void ShadowUpdateStatusCallback(const char *pThingName, ShadowActions_t action, Shadow_Ack_Status_t status,
ampembeng 15:6f2798e45099 208 const char *pReceivedJsonDocument, void *pContextData) {
Janos Follath 0:fc70c47eecb4 209
ampembeng 15:6f2798e45099 210 INFO("Shadow Update Status Callback");
ampembeng 15:6f2798e45099 211
ampembeng 15:6f2798e45099 212 if (status == SHADOW_ACK_TIMEOUT) {
ampembeng 15:6f2798e45099 213 INFO("Update Timeout--");
ampembeng 15:6f2798e45099 214 } else if (status == SHADOW_ACK_REJECTED) {
ampembeng 15:6f2798e45099 215 INFO("Update RejectedXX");
ampembeng 15:6f2798e45099 216 } else if (status == SHADOW_ACK_ACCEPTED) {
ampembeng 15:6f2798e45099 217 INFO("Update Accepted!!"); // Good
ampembeng 15:6f2798e45099 218 }
ampembeng 15:6f2798e45099 219 }
Janos Follath 0:fc70c47eecb4 220
ampembeng 15:6f2798e45099 221 //*********************************************************************************************************************
ampembeng 15:6f2798e45099 222 //* This is the callback function that fires when AWS has sends out a shadow update.
ampembeng 15:6f2798e45099 223 //*********************************************************************************************************************
ampembeng 15:6f2798e45099 224 void ledControl_Callback(const char *pJsonString, uint32_t JsonStringDataLen, jsonStruct_t *pContext) {
ampembeng 15:6f2798e45099 225
ampembeng 15:6f2798e45099 226 INFO("LED Callback Detected.");
ampembeng 15:6f2798e45099 227
ampembeng 15:6f2798e45099 228 if (pContext != NULL) {
ampembeng 15:6f2798e45099 229 switch (*(unsigned char *)(pContext->pData)){
ampembeng 15:6f2798e45099 230 case COLOR_OFF:
ampembeng 15:6f2798e45099 231 INFO("LED -> OFF (%d)", *(unsigned char *)(pContext->pData));
ampembeng 15:6f2798e45099 232 break;
ampembeng 15:6f2798e45099 233 case COLOR_RED:
ampembeng 15:6f2798e45099 234 INFO("LED -> RED (%d)", *(unsigned char *)(pContext->pData));
ampembeng 15:6f2798e45099 235 break;
ampembeng 15:6f2798e45099 236 case COLOR_GREEN:
ampembeng 15:6f2798e45099 237 INFO("LED -> GREEN (%d)", *(unsigned char *)(pContext->pData));
ampembeng 15:6f2798e45099 238 break;
ampembeng 15:6f2798e45099 239 case COLOR_BLUE:
ampembeng 15:6f2798e45099 240 INFO("LED -> BLUE (%d)", *(unsigned char *)(pContext->pData));
ampembeng 15:6f2798e45099 241 break;
ampembeng 15:6f2798e45099 242 case COLOR_WHITE:
ampembeng 15:6f2798e45099 243 INFO("LED -> WHITE (%d)", *(unsigned char *)(pContext->pData));
ampembeng 15:6f2798e45099 244 break;
Janos Follath 0:fc70c47eecb4 245 }
ampembeng 15:6f2798e45099 246 }
ampembeng 15:6f2798e45099 247 else {
ampembeng 15:6f2798e45099 248 INFO("pContext was detected as NULL");
Janos Follath 0:fc70c47eecb4 249 }
ampembeng 15:6f2798e45099 250 }
ampembeng 23:b9ff83dc965f 251
ampembeng 23:b9ff83dc965f 252 //*********************************************************************************************************************
ampembeng 23:b9ff83dc965f 253 //* Subscribe callback (used with alternate demo)
ampembeng 23:b9ff83dc965f 254 //*********************************************************************************************************************
ampembeng 23:b9ff83dc965f 255 int MQTTcallbackHandler(MQTTCallbackParams params) {
ampembeng 23:b9ff83dc965f 256
ampembeng 23:b9ff83dc965f 257 INFO("Subscribe callback");
ampembeng 23:b9ff83dc965f 258 INFO("%.*s\t%.*s",
ampembeng 23:b9ff83dc965f 259 (int)params.TopicNameLen, params.pTopicName,
ampembeng 23:b9ff83dc965f 260 (int)params.MessageParams.PayloadLen, (char*)params.MessageParams.pPayload);
ampembeng 23:b9ff83dc965f 261
ampembeng 23:b9ff83dc965f 262 return 0;
ampembeng 23:b9ff83dc965f 263 }
ampembeng 23:b9ff83dc965f 264
ampembeng 23:b9ff83dc965f 265 //*********************************************************************************************************************
ampembeng 23:b9ff83dc965f 266 //* Disconnect handling (used with alternate demo)
ampembeng 23:b9ff83dc965f 267 //*********************************************************************************************************************
ampembeng 23:b9ff83dc965f 268 void disconnectCallbackHandler(void) {
ampembeng 23:b9ff83dc965f 269 WARN("MQTT Disconnect");
ampembeng 23:b9ff83dc965f 270 IoT_Error_t rc = NONE_ERROR;
ampembeng 23:b9ff83dc965f 271 if(aws_iot_is_autoreconnect_enabled()){
ampembeng 23:b9ff83dc965f 272 INFO("Auto Reconnect is enabled, Reconnecting attempt will start now");
ampembeng 23:b9ff83dc965f 273 }else{
ampembeng 23:b9ff83dc965f 274 WARN("Auto Reconnect not enabled. Starting manual reconnect...");
ampembeng 23:b9ff83dc965f 275 rc = aws_iot_mqtt_attempt_reconnect();
ampembeng 23:b9ff83dc965f 276 if(RECONNECT_SUCCESSFUL == rc){
ampembeng 23:b9ff83dc965f 277 WARN("Manual Reconnect Successful");
ampembeng 23:b9ff83dc965f 278 }else{
ampembeng 23:b9ff83dc965f 279 WARN("Manual Reconnect Failed - %d", rc);
ampembeng 23:b9ff83dc965f 280 }
ampembeng 23:b9ff83dc965f 281 }
ampembeng 23:b9ff83dc965f 282 }
ampembeng 23:b9ff83dc965f 283
ampembeng 23:b9ff83dc965f 284 //=====================================================================================================================
ampembeng 23:b9ff83dc965f 285 //
ampembeng 23:b9ff83dc965f 286 // Out-of-Box Demo: This function is used as part of the binary that comes with the Starter Kit. Instead of using an
ampembeng 23:b9ff83dc965f 287 // AWS device shadow, it publishes to an AWS Rule. The Rule is setup to store data to a DynamoDB, and
ampembeng 23:b9ff83dc965f 288 // the demo S3 website pulls that data from the DynamoDB and displays it.
ampembeng 23:b9ff83dc965f 289 //
ampembeng 23:b9ff83dc965f 290 //=====================================================================================================================
ampembeng 23:b9ff83dc965f 291 int outOfBoxDemo() {
ampembeng 23:b9ff83dc965f 292 INFO("Running Out-of-Box Function (alternate demo).");
ampembeng 23:b9ff83dc965f 293
ampembeng 23:b9ff83dc965f 294 IoT_Error_t rc = NONE_ERROR;
ampembeng 23:b9ff83dc965f 295 int32_t i = 0;
ampembeng 23:b9ff83dc965f 296 int publishCount = 0;
ampembeng 23:b9ff83dc965f 297 bool infinitePublishFlag = true;
ampembeng 23:b9ff83dc965f 298 char cPayload[100];
ampembeng 23:b9ff83dc965f 299 char cTopic[100];
ampembeng 23:b9ff83dc965f 300 const string colorStrings[] = {"Off", "Red", "Green", "", "Blue", "", "", "White"};
ampembeng 24:224c07ec3bd0 301 float updateInterval = 1.0; // seconds
ampembeng 23:b9ff83dc965f 302
ampembeng 23:b9ff83dc965f 303 MQTTConnectParams connectParams = MQTTConnectParamsDefault;
ampembeng 23:b9ff83dc965f 304 connectParams.KeepAliveInterval_sec = 10;
ampembeng 23:b9ff83dc965f 305 connectParams.isCleansession = true;
ampembeng 23:b9ff83dc965f 306 connectParams.MQTTVersion = MQTT_3_1_1;
ampembeng 23:b9ff83dc965f 307 connectParams.pClientID = iccidName; // Using ICCID for unique Client ID
ampembeng 23:b9ff83dc965f 308 connectParams.pHostURL = HostAddress;
ampembeng 23:b9ff83dc965f 309 connectParams.port = port;
ampembeng 23:b9ff83dc965f 310 connectParams.isWillMsgPresent = false;
ampembeng 23:b9ff83dc965f 311 connectParams.pRootCALocation = AWS_IOT_ROOT_CA_FILENAME;
ampembeng 23:b9ff83dc965f 312 connectParams.pDeviceCertLocation = AWS_IOT_CERTIFICATE_FILENAME;
ampembeng 23:b9ff83dc965f 313 connectParams.pDevicePrivateKeyLocation = AWS_IOT_PRIVATE_KEY_FILENAME;
ampembeng 23:b9ff83dc965f 314 connectParams.mqttCommandTimeout_ms = 10000;
ampembeng 23:b9ff83dc965f 315 connectParams.tlsHandshakeTimeout_ms = 10000;
ampembeng 23:b9ff83dc965f 316 connectParams.isSSLHostnameVerify = true; // ensure this is set to true for production
ampembeng 23:b9ff83dc965f 317 connectParams.disconnectHandler = disconnectCallbackHandler;
ampembeng 23:b9ff83dc965f 318
ampembeng 23:b9ff83dc965f 319 INFO("Connecting...");
ampembeng 23:b9ff83dc965f 320 rc = aws_iot_mqtt_connect(&connectParams);
ampembeng 23:b9ff83dc965f 321 if (NONE_ERROR != rc) {
ampembeng 23:b9ff83dc965f 322 ERROR("Error(%d) connecting to %s:%d", rc, connectParams.pHostURL, connectParams.port);
ampembeng 23:b9ff83dc965f 323 }
ampembeng 23:b9ff83dc965f 324
ampembeng 23:b9ff83dc965f 325 /*
ampembeng 23:b9ff83dc965f 326 * Enable Auto Reconnect functionality. Minimum and Maximum time of Exponential backoff are set in aws_iot_config.h
ampembeng 23:b9ff83dc965f 327 * #AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL
ampembeng 23:b9ff83dc965f 328 * #AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL
ampembeng 23:b9ff83dc965f 329 */
ampembeng 23:b9ff83dc965f 330 INFO("Set Auto Reconnect...");
ampembeng 23:b9ff83dc965f 331 rc = aws_iot_mqtt_autoreconnect_set_status(true);
ampembeng 23:b9ff83dc965f 332 if (NONE_ERROR != rc) {
ampembeng 23:b9ff83dc965f 333 ERROR("Unable to set Auto Reconnect to true - %d", rc);
ampembeng 23:b9ff83dc965f 334 return rc;
ampembeng 23:b9ff83dc965f 335 }
ampembeng 23:b9ff83dc965f 336
ampembeng 23:b9ff83dc965f 337 // Comment this in if you want to subscribe
ampembeng 23:b9ff83dc965f 338 /*MQTTSubscribeParams subParams = MQTTSubscribeParamsDefault;
ampembeng 23:b9ff83dc965f 339 subParams.mHandler = MQTTcallbackHandler;
ampembeng 23:b9ff83dc965f 340 subParams.pTopic = "sdkTest/sub";
ampembeng 23:b9ff83dc965f 341 subParams.qos = QOS_0;
ampembeng 23:b9ff83dc965f 342
ampembeng 23:b9ff83dc965f 343 if (NONE_ERROR == rc) {
ampembeng 23:b9ff83dc965f 344 INFO("Subscribing...");
ampembeng 23:b9ff83dc965f 345 rc = aws_iot_mqtt_subscribe(&subParams);
ampembeng 23:b9ff83dc965f 346 if (NONE_ERROR != rc) {
ampembeng 23:b9ff83dc965f 347 ERROR("Error subscribing");
ampembeng 23:b9ff83dc965f 348 }
ampembeng 23:b9ff83dc965f 349 }*/
ampembeng 23:b9ff83dc965f 350
ampembeng 23:b9ff83dc965f 351 // Initializ the payload
ampembeng 23:b9ff83dc965f 352 MQTTMessageParams Msg = MQTTMessageParamsDefault;
ampembeng 23:b9ff83dc965f 353 Msg.qos = QOS_0;
ampembeng 23:b9ff83dc965f 354 Msg.pPayload = (void *) cPayload;
ampembeng 23:b9ff83dc965f 355
ampembeng 23:b9ff83dc965f 356 MQTTPublishParams Params = MQTTPublishParamsDefault;
ampembeng 23:b9ff83dc965f 357
ampembeng 23:b9ff83dc965f 358 // Sets up the topic to publish to
ampembeng 23:b9ff83dc965f 359 sprintf(cTopic, AWS_IOT_MY_TOPIC, iccidName);
ampembeng 23:b9ff83dc965f 360 Params.pTopic = cTopic;
ampembeng 23:b9ff83dc965f 361
ampembeng 23:b9ff83dc965f 362 if (publishCount != 0) {
ampembeng 23:b9ff83dc965f 363 infinitePublishFlag = false;
ampembeng 23:b9ff83dc965f 364 }
ampembeng 23:b9ff83dc965f 365
ampembeng 23:b9ff83dc965f 366 INFO("READY TO PUBLISH! Press SW3 button to publish current data.");
ampembeng 23:b9ff83dc965f 367 while ((NETWORK_ATTEMPTING_RECONNECT == rc || RECONNECT_SUCCESSFUL == rc || NONE_ERROR == rc)
ampembeng 23:b9ff83dc965f 368 && (publishCount > 0 || infinitePublishFlag)) {
ampembeng 23:b9ff83dc965f 369
ampembeng 23:b9ff83dc965f 370 // Max time the yield function will wait for read messages
ampembeng 23:b9ff83dc965f 371 rc = aws_iot_mqtt_yield(100);
ampembeng 23:b9ff83dc965f 372 if(NETWORK_ATTEMPTING_RECONNECT == rc){
ampembeng 23:b9ff83dc965f 373 INFO("--> sleep (attempting to reconnect)");
ampembeng 23:b9ff83dc965f 374 wait(1);
ampembeng 23:b9ff83dc965f 375 // If the client is attempting to reconnect we will skip the rest of the loop.
ampembeng 23:b9ff83dc965f 376 continue;
ampembeng 23:b9ff83dc965f 377 }
ampembeng 23:b9ff83dc965f 378
ampembeng 23:b9ff83dc965f 379 // Whenever the software button (SW3) is pressed the LED will changes color and this will
ampembeng 23:b9ff83dc965f 380 // trigger a publish to the AWS topic specified.
ampembeng 23:b9ff83dc965f 381 if (buttonOverride) {
ampembeng 23:b9ff83dc965f 382 buttonOverride = false;
ampembeng 23:b9ff83dc965f 383
ampembeng 23:b9ff83dc965f 384 // Get temp/humidity values
ampembeng 23:b9ff83dc965f 385 temperature = CTOF(hts221.readTemperature());
ampembeng 23:b9ff83dc965f 386 humidity = hts221.readHumidity();
ampembeng 23:b9ff83dc965f 387
ampembeng 23:b9ff83dc965f 388 // Loading data into JSON format
ampembeng 23:b9ff83dc965f 389 sprintf(cPayload, "{\"color\":\"%s\",\"temperature\":%f,\"humidity\":%d}", colorStrings[ledColor], temperature, humidity);
ampembeng 23:b9ff83dc965f 390 Msg.PayloadLen = strlen(cPayload) + 1;
ampembeng 23:b9ff83dc965f 391 Params.MessageParams = Msg;
ampembeng 23:b9ff83dc965f 392
ampembeng 23:b9ff83dc965f 393 // Publish
ampembeng 23:b9ff83dc965f 394 rc = aws_iot_mqtt_publish(&Params);
ampembeng 23:b9ff83dc965f 395 if (publishCount > 0) {
ampembeng 23:b9ff83dc965f 396 publishCount--;
ampembeng 23:b9ff83dc965f 397 }
ampembeng 23:b9ff83dc965f 398
ampembeng 23:b9ff83dc965f 399 printData();
ampembeng 23:b9ff83dc965f 400 INFO("--> Update sent. Sleep for %f seconds", updateInterval);
ampembeng 23:b9ff83dc965f 401 wait(updateInterval-.02);
ampembeng 23:b9ff83dc965f 402 }
ampembeng 23:b9ff83dc965f 403 else {
ampembeng 23:b9ff83dc965f 404 wait(.3); // 300 ms
ampembeng 23:b9ff83dc965f 405 }
ampembeng 23:b9ff83dc965f 406 }
ampembeng 23:b9ff83dc965f 407
ampembeng 23:b9ff83dc965f 408 if (NONE_ERROR != rc) {
ampembeng 23:b9ff83dc965f 409 ERROR("An error occurred in the loop.\n");
ampembeng 23:b9ff83dc965f 410 } else {
ampembeng 23:b9ff83dc965f 411 INFO("Publish done\n");
ampembeng 23:b9ff83dc965f 412 }
ampembeng 23:b9ff83dc965f 413
ampembeng 23:b9ff83dc965f 414 return rc;
ampembeng 23:b9ff83dc965f 415 }
ampembeng 15:6f2798e45099 416
ampembeng 15:6f2798e45099 417 //=====================================================================================================================
ampembeng 15:6f2798e45099 418 //
ampembeng 15:6f2798e45099 419 // Main
ampembeng 15:6f2798e45099 420 //
ampembeng 15:6f2798e45099 421 //=====================================================================================================================
ampembeng 15:6f2798e45099 422 int main() {
ampembeng 15:6f2798e45099 423
ampembeng 15:6f2798e45099 424 // Set baud rate for PC Serial
ampembeng 15:6f2798e45099 425 pc.baud(115200);
ampembeng 15:6f2798e45099 426 INFO("Hello World from AT&T IoT Start Kit demo!");
ampembeng 20:ee34856ae510 427
ampembeng 20:ee34856ae510 428 int i;
ampembeng 23:b9ff83dc965f 429 IoT_Error_t rc = NONE_ERROR;
ampembeng 15:6f2798e45099 430 char JsonDocumentBuffer[MAX_LENGTH_OF_UPDATE_JSON_BUFFER];
ampembeng 15:6f2798e45099 431 size_t sizeOfJsonDocumentBuffer = sizeof(JsonDocumentBuffer) / sizeof(JsonDocumentBuffer[0]);
ampembeng 15:6f2798e45099 432
ampembeng 15:6f2798e45099 433 // JSON struct for LED control
ampembeng 15:6f2798e45099 434 jsonStruct_t ledController;
ampembeng 15:6f2798e45099 435 ledController.cb = ledControl_Callback;
ampembeng 15:6f2798e45099 436 ledController.pData = &ledColor;
ampembeng 15:6f2798e45099 437 ledController.pKey = "ledColor";
ampembeng 15:6f2798e45099 438 ledController.type = SHADOW_JSON_UINT8;
ampembeng 15:6f2798e45099 439
ampembeng 20:ee34856ae510 440 // JSON struct for temperature\humidity readings
ampembeng 15:6f2798e45099 441 jsonStruct_t temperatureHandler;
ampembeng 15:6f2798e45099 442 temperatureHandler.cb = NULL;
ampembeng 15:6f2798e45099 443 temperatureHandler.pKey = "temperature";
ampembeng 15:6f2798e45099 444 temperatureHandler.pData = &temperature;
ampembeng 15:6f2798e45099 445 temperatureHandler.type = SHADOW_JSON_FLOAT;
ampembeng 20:ee34856ae510 446
ampembeng 20:ee34856ae510 447 jsonStruct_t humidityHandler;
ampembeng 20:ee34856ae510 448 humidityHandler.cb = NULL;
ampembeng 20:ee34856ae510 449 humidityHandler.pKey = "humidity";
ampembeng 20:ee34856ae510 450 humidityHandler.pData = &humidity;
ampembeng 20:ee34856ae510 451 humidityHandler.type = SHADOW_JSON_INT16;
ampembeng 15:6f2798e45099 452
ampembeng 15:6f2798e45099 453 INFO("AWS IoT SDK Version(dev) %d.%d.%d-%s", VERSION_MAJOR, VERSION_MINOR, VERSION_PATCH, VERSION_TAG);
ampembeng 15:6f2798e45099 454
ampembeng 18:6370da1de572 455 #ifdef USING_SD_CARD
ampembeng 18:6370da1de572 456 // Paths for certs from SD card
ampembeng 18:6370da1de572 457 INFO("Using SD card files for AWS config.");
ampembeng 18:6370da1de572 458 DEBUG("- mqtt config path: %s", AWS_MQTT_CONFIG_FILENAME);
ampembeng 18:6370da1de572 459 DEBUG("- rootCA path: %s", AWS_IOT_ROOT_CA_FILENAME);
ampembeng 18:6370da1de572 460 DEBUG("- clientCRT path: %s", AWS_IOT_CERTIFICATE_FILENAME);
ampembeng 18:6370da1de572 461 DEBUG("- clientKey path: %s", AWS_IOT_PRIVATE_KEY_FILENAME);
ampembeng 18:6370da1de572 462 #else
ampembeng 18:6370da1de572 463 INFO("Using #defines in aws_iot_config.h and certs from certs.cpp for AWS config.");
ampembeng 18:6370da1de572 464 #endif
ampembeng 15:6f2798e45099 465
ampembeng 16:02008a2a2569 466 // Startup signal - blinks through RGBW then turns off
ampembeng 15:6f2798e45099 467 SetLedColor(COLOR_RED);
ampembeng 15:6f2798e45099 468 wait(.5);
ampembeng 15:6f2798e45099 469 SetLedColor(COLOR_GREEN);
ampembeng 15:6f2798e45099 470 wait(.5);
ampembeng 15:6f2798e45099 471 SetLedColor(COLOR_BLUE);
ampembeng 15:6f2798e45099 472 wait(.5);
ampembeng 16:02008a2a2569 473 SetLedColor(COLOR_WHITE);
ampembeng 16:02008a2a2569 474 wait(.5);
ampembeng 16:02008a2a2569 475 SetLedColor(COLOR_OFF);
ampembeng 20:ee34856ae510 476
ampembeng 20:ee34856ae510 477 // Initialize sensors
ampembeng 23:b9ff83dc965f 478 INFO("Init sensors...");
ampembeng 20:ee34856ae510 479 void hts221_init(void);
ampembeng 20:ee34856ae510 480 i = hts221.begin();
ampembeng 20:ee34856ae510 481 if(!i) {
ampembeng 20:ee34856ae510 482 WARN(RED "HTS221 NOT DETECTED!!\n\r");
ampembeng 20:ee34856ae510 483 }
ampembeng 18:6370da1de572 484
ampembeng 15:6f2798e45099 485 // Setup SW3 button to falling edge interrupt
ampembeng 23:b9ff83dc965f 486 INFO("Init interrupts...");
ampembeng 15:6f2798e45099 487 Interrupt.fall(&sw3ButtonHandler);
ampembeng 15:6f2798e45099 488
ampembeng 15:6f2798e45099 489 // Boot the Avnet Shield before any other operations
ampembeng 23:b9ff83dc965f 490 INFO("Net Boot...");
ampembeng 15:6f2798e45099 491 net_modem_boot();
ampembeng 23:b9ff83dc965f 492
ampembeng 23:b9ff83dc965f 493 //==========================================================================
ampembeng 23:b9ff83dc965f 494 // NOTE: You can comment in the following line for an alternate demo that
ampembeng 23:b9ff83dc965f 495 // is used as the out-of-box demo binary that comes with the AT&T IoT
ampembeng 23:b9ff83dc965f 496 // Starter Kit. It loops instead of the rest of Main()
ampembeng 23:b9ff83dc965f 497 //return outOfBoxDemo();
ampembeng 23:b9ff83dc965f 498 //==========================================================================
ampembeng 23:b9ff83dc965f 499
ampembeng 18:6370da1de572 500 // Intialize MQTT/Cert parameters
ampembeng 15:6f2798e45099 501 ShadowParameters_t sp = ShadowParametersDefault;
ampembeng 18:6370da1de572 502 #ifdef USING_SD_CARD
ampembeng 18:6370da1de572 503 rc = (IoT_Error_t)mbedtls_mqtt_config_parse_file(&sp, AWS_MQTT_CONFIG_FILENAME);
ampembeng 18:6370da1de572 504 if (NONE_ERROR != rc) {
ampembeng 18:6370da1de572 505 ERROR("Failed to initialize mqtt parameters %d", rc);
ampembeng 18:6370da1de572 506 return rc;
ampembeng 18:6370da1de572 507 }
ampembeng 18:6370da1de572 508 sp.pClientCRT = AWS_IOT_CERTIFICATE_FILENAME;
ampembeng 18:6370da1de572 509 sp.pClientKey = AWS_IOT_PRIVATE_KEY_FILENAME;
ampembeng 18:6370da1de572 510 sp.pRootCA = AWS_IOT_ROOT_CA_FILENAME;
ampembeng 18:6370da1de572 511 #else
ampembeng 15:6f2798e45099 512 sp.pMyThingName = AWS_IOT_MY_THING_NAME;
ampembeng 15:6f2798e45099 513 sp.pMqttClientId = AWS_IOT_MQTT_CLIENT_ID;
ampembeng 15:6f2798e45099 514 sp.pHost = HostAddress;
ampembeng 15:6f2798e45099 515 sp.port = port;
ampembeng 23:b9ff83dc965f 516
ampembeng 23:b9ff83dc965f 517 sp.pClientCRT = AWS_IOT_CERTIFICATE_FILENAME;
ampembeng 23:b9ff83dc965f 518 sp.pClientKey = AWS_IOT_PRIVATE_KEY_FILENAME;
ampembeng 23:b9ff83dc965f 519 sp.pRootCA = AWS_IOT_ROOT_CA_FILENAME;
ampembeng 18:6370da1de572 520 #endif
ampembeng 20:ee34856ae510 521
ampembeng 18:6370da1de572 522 INFO("Initialize the MQTT client...");
ampembeng 18:6370da1de572 523 MQTTClient_t mqttClient;
ampembeng 18:6370da1de572 524 aws_iot_mqtt_init(&mqttClient);
ampembeng 15:6f2798e45099 525
ampembeng 15:6f2798e45099 526 INFO("Shadow Init...");
ampembeng 15:6f2798e45099 527 rc = aws_iot_shadow_init(&mqttClient);
ampembeng 15:6f2798e45099 528 if (NONE_ERROR != rc) {
ampembeng 15:6f2798e45099 529 ERROR("Shadow Init Error %d", rc);
ampembeng 15:6f2798e45099 530 return rc;
Janos Follath 0:fc70c47eecb4 531 }
ampembeng 15:6f2798e45099 532
ampembeng 15:6f2798e45099 533 INFO("Shadow Connect...");
ampembeng 15:6f2798e45099 534 rc = aws_iot_shadow_connect(&mqttClient, &sp);
ampembeng 15:6f2798e45099 535 if (NONE_ERROR != rc) {
ampembeng 15:6f2798e45099 536 ERROR("Shadow Connection Error %d", rc);
ampembeng 15:6f2798e45099 537 return rc;
Janos Follath 0:fc70c47eecb4 538 }
Janos Follath 0:fc70c47eecb4 539
ampembeng 15:6f2798e45099 540 // Enable Auto Reconnect functionality. Minimum and Maximum time of Exponential backoff are set in aws_iot_config.h
ampembeng 15:6f2798e45099 541 // #AWS_IOT_MQTT_MIN_RECONNECT_WAIT_INTERVAL
ampembeng 15:6f2798e45099 542 // #AWS_IOT_MQTT_MAX_RECONNECT_WAIT_INTERVAL
ampembeng 15:6f2798e45099 543 rc = mqttClient.setAutoReconnectStatus(true);
ampembeng 15:6f2798e45099 544 if (NONE_ERROR != rc) {
ampembeng 15:6f2798e45099 545 ERROR("Unable to set Auto Reconnect to true - %d", rc);
ampembeng 15:6f2798e45099 546 return rc;
ampembeng 15:6f2798e45099 547 }
ampembeng 15:6f2798e45099 548
ampembeng 15:6f2798e45099 549 // Example line of how to delete a shadow (not used in this demo)
ampembeng 15:6f2798e45099 550 //aws_iot_shadow_delete(&mqttClient, AWS_IOT_MY_THING_NAME, ShadowUpdateStatusCallback, NULL, 8, true);
Janos Follath 0:fc70c47eecb4 551
ampembeng 15:6f2798e45099 552 INFO("Shadow Register Delta...");
ampembeng 15:6f2798e45099 553 rc = aws_iot_shadow_register_delta(&mqttClient, &ledController);
ampembeng 15:6f2798e45099 554 if (NONE_ERROR != rc) {
ampembeng 15:6f2798e45099 555 ERROR("Shadow Register Delta Error");
ampembeng 15:6f2798e45099 556 return rc;
ampembeng 15:6f2798e45099 557 }
ampembeng 15:6f2798e45099 558
ampembeng 15:6f2798e45099 559 INFO("Will attempt to sync with device shadow every %f seconds.", SHADOW_SYNC_INTERVAL);
ampembeng 15:6f2798e45099 560 // Loop and publish changes from the FRDM board
ampembeng 15:6f2798e45099 561 while (NETWORK_ATTEMPTING_RECONNECT == rc || RECONNECT_SUCCESSFUL == rc || NONE_ERROR == rc) {
ampembeng 15:6f2798e45099 562
ampembeng 15:6f2798e45099 563 // Looks for incoming socket messages
ampembeng 15:6f2798e45099 564 rc = aws_iot_shadow_yield(&mqttClient, 200);
ampembeng 15:6f2798e45099 565 if (NETWORK_ATTEMPTING_RECONNECT == rc) {
ampembeng 15:6f2798e45099 566 // If the client is attempting to reconnect we will skip the rest of the loop.
ampembeng 15:6f2798e45099 567 INFO("Attempting to reconnect...");
ampembeng 15:6f2798e45099 568 wait(1);
ampembeng 15:6f2798e45099 569 continue;
ampembeng 15:6f2798e45099 570 }
ampembeng 20:ee34856ae510 571
ampembeng 20:ee34856ae510 572 // Read sensor data
ampembeng 20:ee34856ae510 573 temperature = CTOF(hts221.readTemperature());
ampembeng 20:ee34856ae510 574 humidity = hts221.readHumidity();
ampembeng 20:ee34856ae510 575
ampembeng 15:6f2798e45099 576 INFO("\n=======================================================================================\n");
ampembeng 15:6f2798e45099 577 // Initialize JSON shadow document
ampembeng 15:6f2798e45099 578 rc = aws_iot_shadow_init_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer);
ampembeng 15:6f2798e45099 579 if (rc == NONE_ERROR) {
ampembeng 15:6f2798e45099 580
ampembeng 15:6f2798e45099 581 // If there has been a SW3 button press update the 'desired' color
ampembeng 15:6f2798e45099 582 if (buttonOverride) {
ampembeng 23:b9ff83dc965f 583 rc = aws_iot_shadow_add_desired(JsonDocumentBuffer, sizeOfJsonDocumentBuffer, 1, &ledController);
ampembeng 15:6f2798e45099 584 buttonOverride = false;
Janos Follath 0:fc70c47eecb4 585 }
ampembeng 15:6f2798e45099 586
ampembeng 23:b9ff83dc965f 587 // Updates the 'reported' color/temp/humidity
ampembeng 20:ee34856ae510 588 rc = aws_iot_shadow_add_reported(JsonDocumentBuffer, sizeOfJsonDocumentBuffer, 3, &ledController,
ampembeng 20:ee34856ae510 589 &temperatureHandler,
ampembeng 20:ee34856ae510 590 &humidityHandler);
ampembeng 15:6f2798e45099 591
ampembeng 15:6f2798e45099 592 if (rc == NONE_ERROR) {
ampembeng 15:6f2798e45099 593 rc = aws_iot_finalize_json_document(JsonDocumentBuffer, sizeOfJsonDocumentBuffer);
ampembeng 15:6f2798e45099 594
ampembeng 15:6f2798e45099 595 if (rc == NONE_ERROR) {
ampembeng 15:6f2798e45099 596 INFO("Update Shadow: %s", JsonDocumentBuffer);
ampembeng 18:6370da1de572 597 rc = aws_iot_shadow_update(&mqttClient, sp.pMyThingName, JsonDocumentBuffer,
ampembeng 15:6f2798e45099 598 ShadowUpdateStatusCallback, NULL, 8, true);
ampembeng 15:6f2798e45099 599 }
ampembeng 15:6f2798e45099 600 }
ampembeng 20:ee34856ae510 601 }
ampembeng 20:ee34856ae510 602
ampembeng 20:ee34856ae510 603 // Print data
ampembeng 23:b9ff83dc965f 604 printData();
ampembeng 18:6370da1de572 605 INFO("*****************************************************************************************");
ampembeng 20:ee34856ae510 606
ampembeng 20:ee34856ae510 607 // Set the LED color
ampembeng 15:6f2798e45099 608 SetLedColor(ledColor);
ampembeng 15:6f2798e45099 609 wait(SHADOW_SYNC_INTERVAL);
Janos Follath 0:fc70c47eecb4 610 }
Janos Follath 0:fc70c47eecb4 611
ampembeng 15:6f2798e45099 612 if (NONE_ERROR != rc) {
ampembeng 15:6f2798e45099 613 ERROR("An error occurred in the loop %d", rc);
Janos Follath 0:fc70c47eecb4 614 }
Janos Follath 0:fc70c47eecb4 615
ampembeng 15:6f2798e45099 616 INFO("Disconnecting");
ampembeng 15:6f2798e45099 617 rc = aws_iot_shadow_disconnect(&mqttClient);
ampembeng 15:6f2798e45099 618
ampembeng 15:6f2798e45099 619 if (NONE_ERROR != rc) {
ampembeng 15:6f2798e45099 620 ERROR("Disconnect error %d", rc);
Janos Follath 0:fc70c47eecb4 621 }
Janos Follath 0:fc70c47eecb4 622
ampembeng 15:6f2798e45099 623 return rc;
ampembeng 15:6f2798e45099 624 }