@RTL/

SMQ LED Demo

C

SMQ C client stack and LED demo Navigate to the following address after starting the code and control the LEDs: https://simplemq.com/m2m-led

fork
loading
Files
  • main.c
  • ledctrl.h
  • selib.c
  • selib.h
  • selibplat.h
  • SMQClient.c
  • SMQClient.h
main.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
/**
   COPYRIGHT:  Real Time Logic LLC, 2018
  
   SMQ LED example.

   LICENSE:
   The example and SMQ stack's source code is released under the
   Eclipse Public License:
   http://en.wikipedia.org/wiki/Eclipse_Public_License
   https://www.eclipse.org/legal/epl-v20.html

   NOTE: This example uses the SharkMQ (secure SMQ) compatibility API
         thus making it easy to upgraded to a secure version, if needed.

   This code is the device side for the SMQ LED controller, an example
   that enables LEDs in a device to be controlled from a browser and
   Java (including Android).

   When this code runs, it connects to our public SMQ test broker. The
   device will show up as a tab on the following page:
   http://simplemq.com/m2m-led/

   Introductory information on how the complete SMQ LED demo works
   (including the browser UI) can be found online. The device code
   details can be found under section " Device C code".
   https://goo.gl/phXnWp

   This online example code has been modified to run on Linux only.

   To set up your own SMQ broker (server), download the Mako Server
   and activate the tutorials. A ready to use broker is included in
   the tutorials. The following non active copy of the tutorials
   provide information on how the broker operates:
   https://embedded-app-server.info/bas-tutorials/IoT.lsp
 */


/* Change the domain/url if you are running your own broker
   Note: you can also set the domain at the command prompt when in
   simulation mode.
 */
#define SIMPLEMQ_DOMAIN "http://simplemq.com"
#define SIMPLEMQ_URL SIMPLEMQ_DOMAIN "/smq.lsp"

#include "SMQClient.h"
#include "ledctrl.h"
#include <ctype.h>
#include <stdlib.h>


static const char* simpleMqUrl; /* defaults to SIMPLEMQ_DOMAIN */

#include <stdio.h>


/* Enable simulated temperature */
#ifndef ENABLE_TEMP
#define ENABLE_TEMP
#endif

/*
  The following is used by the logic managing the simulated temperature.
 */
#define KEY_UP_ARROW 1000
#define KEY_DOWN_ARROW 1001
static int currentTemperature=0; /* simulated value */

/* Used by example for printing to console
 */
void
_xprintf(const char* fmt, ...)
{
   va_list varg;
   va_start(varg, fmt);
   vprintf(fmt, varg);
   va_end(varg);
}


/* Not needed on host with printf support. This function is designed for
 * embedded systems without console.
 */
void setProgramStatus(ProgramStatus s)
{
   (void)s;
}



/* The list of LEDs in the device, the name, color, and ID. Adapt this
   list to the LEDs on your evaluation board (Ref-LED).

   The LED name shows up in the UI, the LED type tells the UI the
   color of the LED, and the ID is used as a handle by the UI. The UI
   will send this handle to the device when sending LED control
   messages. You can use any number sequence for the ID. We use the
   sequence 1 to 4 so it's easy to map to a C array.

   This data is encoded as JSON and sent to the UI when a new UI
   requests the device capabilities.
*/
static const LedInfo ledInfo[] = {
   {
      "LED 1",
      LedColor_red,
      1
   },
   {
      "LED 2",
      LedColor_yellow,
      2
   },
   {
      "LED 3",
      LedColor_green,
      3
   },
   {
      "LED 4",
      LedColor_blue,
      4
   }
};

const LedInfo*
getLedInfo(int* len)
{
   *len = sizeof(ledInfo) / sizeof(ledInfo[0]);
   return ledInfo;
}

/* The LEDs: used by getLedState and setLed
 */
static int leds[sizeof(ledInfo)/sizeof(ledInfo[1])];

/* Returns the LED on/off state for led with ID 'ledId'. The 'ledId'
   is the 'handle' sent by the UI.
 */
int
getLedState(int ledId)
{
   baAssert(ledId >= 1 && ledId <= sizeof(ledInfo)/sizeof(ledInfo[1]));
   return leds[ledId-1];
} 


/* Set LED on device. The 'ledId' is the 'handle' sent by the UI.
 */
int
setLed(int ledId, int on)
{
   if(ledId >= 1 && ledId <= sizeof(ledInfo)/sizeof(ledInfo[1]))
   {
      printf("Set LED %d %s\n", ledId, on ? "on" : "off");
      leds[ledId-1] = on;
      return 0;
   }
   return -1;
}


#include <sys/socket.h>
#include <arpa/inet.h>
#include <netdb.h>
#include <sys/ioctl.h>
#include <net/if.h>
#include <termios.h>
/* UNIX kbhit and getch simulation */
static struct termios orgTs;

static void
resetTerminalMode()
{
   tcsetattr(0, TCSANOW, &orgTs);
}

static void
setConioTerminalMode()
{
   struct termios asyncTs;
   tcgetattr(0, &orgTs);
   memcpy(&asyncTs, &orgTs, sizeof(asyncTs));
   /* register cleanup handler, and set the new terminal mode */
   atexit(resetTerminalMode);
   cfmakeraw(&asyncTs);
   asyncTs.c_oflag=orgTs.c_oflag;
   tcsetattr(0, TCSANOW, &asyncTs);
}

static int
xkbhit()
{
   struct timeval tv = { 0L, 0L };
   fd_set fds;
   FD_ZERO(&fds);
   FD_SET(0, &fds);
   return select(1, &fds, NULL, NULL, &tv);
}

static int
xgetch()
{
   int r;
   unsigned char c;
   if ((r = read(0, &c, sizeof(c))) < 0)
      return r;
   if(c == 3) /* CTRL-C Linux */
      exit(0);
   if(c == 27)
   {
      U16 x;
      read(0, &x, sizeof(x));
      switch(x)
      {
         case 0x415B: return KEY_UP_ARROW;
         case 0x425B: return KEY_DOWN_ARROW;
      }
      return 'A'; /* dummy value */
   }
   return c;
}

static void
die(const char* fmt, ...)
{
   va_list varg;
   va_start(varg, fmt);
   vprintf(fmt, varg);
   va_end(varg);
   printf("\n");
   exit(1);
}

static void
getMacAddr(char macaddr[6], const char* ifname)
{
   char buf[8192] = {0};
   struct ifconf ifc = {0};
   struct ifreq *ifr = NULL;
   int sck = 0;
   int nInterfaces = 0;
   int i = 0;
   struct ifreq *item=0;
   struct sockaddr *addr;
   /* Get a socket handle. */
   sck = socket(PF_INET, SOCK_DGRAM, 0);
   if(sck < 0) 
      die("socket: %s",strerror(errno));
   /* Query available interfaces. */
   ifc.ifc_len = sizeof(buf);
   ifc.ifc_buf = buf;
   if(ioctl(sck, SIOCGIFCONF, &ifc) < 0) 
      die("ioctl(SIOCGIFCONF) %s", strerror(errno));
   /* Iterate through the list of interfaces. */
   ifr = ifc.ifc_req;
   nInterfaces = ifc.ifc_len / sizeof(struct ifreq);
   for(i = 0; i < nInterfaces; i++) 
   {
      unsigned long ipaddr;
      item = &ifr[i];
      addr = &(item->ifr_addr);
      /* Get the IP address*/
      if(ioctl(sck, SIOCGIFADDR, item) < 0) 
      {
         perror("ioctl(OSIOCGIFADDR)");
         continue;
      }
      ipaddr = ((struct sockaddr_in *)addr)->sin_addr.s_addr;
      if(0x100007F == ipaddr || 0 == ipaddr)
         continue;
      /* Get the MAC address */
      if(ioctl(sck, SIOCGIFHWADDR, item) < 0) {
         perror("ioctl(SIOCGIFHWADDR)");
         continue;
      }
      break;
   }
   close(sck);   
   if(i == nInterfaces)
      die("Cannot get a MAC address\n");
   memcpy(macaddr, item->ifr_hwaddr.sa_data, 6);
}


/* Optional function that can be used to turn an LED on/off from the
   device by using buttons. The function must return TRUE if a button
   was pressed, otherwise FALSE must be returned. The LED state on/off
   information is managed by the online web service. 
*/
int
setLedFromDevice(int* ledId, int* on)
{
   int ledLen;
   const LedInfo* ledInfo = getLedInfo(&ledLen);
   if(xkbhit())
   {
      int base,i;
      int c = xgetch();
      if(c == 10)
      {
         return 0; /* ignore '\n' */
      }
      if(c == KEY_UP_ARROW)
      {
         currentTemperature += 8; /* increment by 0.8 celcius */
         return 0;
      }
      if(c == KEY_DOWN_ARROW)
      {
         currentTemperature -= 8; /* decrement by 0.8 celcius */
         return 0;
      }
      if(isupper(c))
      {
         *on=1;
         base='A';
      }
      else
      {
         *on=0;
         base='a';
      }
      c -= base;
      base=0;
      for(i = 0 ; i < ledLen ; i++)
      {
         if(ledInfo[i].id == c)
         {
            base=1;
            break;
         }
      }
      if(base)
      {
         *ledId = c;
         return 1;
      }
      printf("Invalid LedId %d. Valid keys (upper/lower): ",c);
      for(i = 0 ; i < ledLen ; i++)
         printf("%c ",'A'+ledInfo[i].id);
      printf("\n");
   }

   { /* Print out usage info at startup */
      static int oneshot=0;
      if( ! oneshot )
      {
         oneshot = 1;
         xprintf(
            ("Set LED from keyboard. Uppercase = ON, lowercase = OFF.\n"
             "Switching LED state updates UI in all connected browsers.\n"));
      }
   }
   return 0;
}


int getTemp(void)
{
   return currentTemperature;
}


const char* getDevName(void)
{
   static char devInfo[100];
   char* ptr;
   strcpy(devInfo,"Repl (Simulated Device): ");
   ptr = devInfo + strlen(devInfo);
   gethostname(ptr, 100 - (ptr - devInfo));
   return devInfo;
}


static void printUniqueID(const char* uuid, int uuidLen)
{
   int i;
   printf("UUID: ");
   for(i = 0 ; i < uuidLen ; i++)
      printf("%X ", (unsigned int)((U8)uuid[i]));
   printf("\n");
}


int getUniqueId(const char** id)
{
   static char addr[6];
   getMacAddr(addr, "eth0");
   printUniqueID(addr, 6);
   *id = addr;
   return 6;
}

int main(int argc, char* argv[])
{
   setConioTerminalMode();

   if(argc > 1)
   {
      simpleMqUrl = argv[1];
      xprintf(("Overriding broker URL\n\tfrom %s\n\tto %s\n%s\n\n",
               SIMPLEMQ_URL,simpleMqUrl,
               "Note: error messages will include original broker name"));

   }
   else
   {
      simpleMqUrl = SIMPLEMQ_URL;
   }

   mainTask(0);
   printf("Press return key to exit\n");
   getchar();
   return 0;
}



static const char*
ledType2String(LedColor t)
{
   switch(t)
   {
      case LedColor_red: return "red";
      case LedColor_yellow: return "yellow";
      case LedColor_green: return "green";
      case LedColor_blue: return "blue";
   }
   baAssert(0);
   return "";
}


/* Send the device capabilities as JSON to the browser. Note: we could
   have used our JSON library for creating the JSON, but the library
   adds additional code. We have opted to manually craft the JSON
   instead of using the JSON library. This keeps the code size
   down. Manually crafting JSON data is easy, parsing JSON is not
   easy. However, we have no need for parsing JSON in this demo.

   You can optionally rewrite this code and use the following JSON
   library: https://realtimelogic.com/products/json/

   When you manually craft JSON, it can be good to use a JSON lint
   parser if you should get a parse error in the browser. The JSON
   lint parser will give you much better error reporting:
   http://jsonlint.com/ 
 */
static int
sendDevInfo(SharkMQ* smq, const char* ipaddr, U32 tid, U32 subtid)
{
   int i, ledLen;
   char buf[11];
   char *ptr;
   int val;
   const LedInfo* ledInfo = getLedInfo(&ledLen);

   SharkMQ_wrtstr(smq, "{\"ipaddr\":\"");
   SharkMQ_wrtstr(smq, ipaddr);
   SharkMQ_wrtstr(smq, "\",\"devname\":\"");
   SharkMQ_wrtstr(smq, getDevName());
   SharkMQ_wrtstr(smq, "\",\"leds\":[");

   /* Write JSON:
     {
        "id": number,
        "name": string,
        "color": string,
        "on": boolean
     }
   */
   for(i = 0 ; i < ledLen ; i++)
   {
      ptr = &buf[(sizeof buf) - 1];
      val = ledInfo[i].id;
      *ptr = 0; 
      if(i != 0)
         SharkMQ_wrtstr(smq,",");
      SharkMQ_wrtstr(smq, "{\"id\":");
      do { /* convert number to string */
         int r = val % 10U;
         val /= 10U;
         *--ptr = (char)('0' + r);
      } while (val && ptr > buf); 
      SharkMQ_wrtstr(smq, ptr); /* number converted to string */
      SharkMQ_wrtstr(smq, ",\"name\":\"");
      SharkMQ_wrtstr(smq, ledInfo[i].name);
      SharkMQ_wrtstr(smq, "\",\"color\":\"");
      SharkMQ_wrtstr(smq, ledType2String(ledInfo[i].color));
      SharkMQ_wrtstr(smq, "\",\"on\":");
      SharkMQ_wrtstr(smq, getLedState(ledInfo[i].id)?"true":"false");
      SharkMQ_wrtstr(smq, "}");
   }
#ifdef ENABLE_TEMP
   SharkMQ_wrtstr(smq, "],\"temp\":");
   ptr = &buf[(sizeof buf) - 1];
   *ptr = 0; 
   val = getTemp();
   if(val < 0)
   {
      val = -val;
      i=TRUE;
   }
   else
      i=FALSE;
   do { /* convert number to string */
      int r = val % 10U;
      val /= 10U;
      *--ptr = (char)('0' + r);
   } while (val && ptr > buf);
   if(i)
      *--ptr='-';
   SharkMQ_wrtstr(smq, ptr); /* number converted to string */
   SharkMQ_wrtstr(smq, "}");
#else
   SharkMQ_wrtstr(smq, "]}");
#endif
   return SharkMQ_pubflush(smq,tid,subtid);
}


/*
  The M2M-LED main function does not return unless the code cannot
  connect to the broker or the connection should break. The return
  value 0 means that the caller can attempt to reconnect by calling
  this function again.
 */
static int
m2mled(SharkMQ* smq, SharkSslCon* scon,
       const char* smqUniqueId, int smqUniqueIdLen)
{
   U32 displayTid=0;    /* Topic ID (Tid) for "/m2m/led/display" */
   U32 ledSubTid=0;     /* Sub Topic ID for "led" */
   U32 deviceTid=0;     /* Tid for "/m2m/led/device" */
   U32 devInfoSubTid=0; /* Sub Topic ID for "devinfo" */
#ifdef ENABLE_TEMP
   U32 tempTid=0;       /* Tid for "/m2m/temp" */
   S16 temperature = (S16)getTemp(); /* current temperature */
#endif
   char ipaddr[16];

/* We make it possible to override the URL at the command prompt when
 * in simulation mode.
 */
   const char* str=simpleMqUrl;

   xprintf(("Connecting to %s\n", str));
   smq->timeout = 3000; /* Bail out if the connection takes this long */
   setProgramStatus(ProgramStatus_Connecting);
   if(SharkMQ_init(smq, scon, str, 0) < 0)
   {
      xprintf(("Cannot establish connection, status: %d\n", smq->status));
      switch(smq->status)
      {
         case -1:
            str="Socket error!";
            setProgramStatus(ProgramStatus_SocketError);
            break;
         case -2:
            str="Cannot resolve IP address for " SIMPLEMQ_DOMAIN ".";
            setProgramStatus(ProgramStatus_DnsError);
            break;
         default:
            str="Cannot connect to " SIMPLEMQ_DOMAIN ".";
            setProgramStatus(ProgramStatus_ConnectionError);
            break;
      }
      xprintf(("%s\n", str));
      /* Cannot reconnect if any of the following are true: */
      return smq->status==SMQE_BUF_OVERFLOW || smq->status==SMQE_INVALID_URL;
   }

   /* Fetch the IP address sent by the broker. We use this for the
    * text shown in the left pane tab in the browser's user interface.
    */
   strncpy(ipaddr, (char*)smq->buf, 16);
   ipaddr[15]=0;
   if(SharkMQ_connect(smq,
                      smqUniqueId, smqUniqueIdLen,
                      0, 0, /* credentials */
                      getDevName(), strlen(getDevName())))
   {
      xprintf(("Connect failed, status: %d\n", smq->status));
      return smq->status == SMQE_BUF_OVERFLOW || smq->status > 0;
   }

   xprintf(("\nConnected to %s.\n"
            "Use a browser and navigate to this domain.\n\n",
            str));
   setProgramStatus(ProgramStatus_DeviceReady);

   /* Request broker to return a topic ID for "/m2m/led/device", the
    * topic where we publish the device capabilities as JSON data.
    */
   SharkMQ_create(smq, "/m2m/led/device");

#ifdef ENABLE_TEMP
   /* Request broker to return a topic ID for "/m2m/temp", the
    * topic where we publish the device temperature.
    */
   SharkMQ_create(smq, "/m2m/temp");
#endif


   /** Request broker to create two sub-topic IDs. We use the
    * sub-topic IDs to further refine the messages published to the
    * browser(s).
    */
   SharkMQ_createsub(smq, "devinfo");
   SharkMQ_createsub(smq, "led");

   /* Subscribe to browser "hello" messages. We send the device
    * capabilities as JSON data to the browser's ephemeral ID when we
    * receive a hello message from a browser.
    */
   SharkMQ_subscribe(smq, "/m2m/led/display");

   smq->timeout=50; /* Poll so we can locally update the LED buttons. */
   for(;;)
   {
      U8* msg;
      U8 outData[2];
      int len =  SharkMQ_getMessage(smq, &msg);
      if(len < 0) /* We received a control message or an error code */
      {
         switch(len)
         {  
            /* Control messages */

            /* Manage responses for create, createsub, and subscribe */
            case SMQ_SUBACK: /* ACK: "/m2m/led/display" */
               displayTid = smq->ptid;
               break;
            case SMQ_CREATEACK:  /* ACK: "/m2m/temp" or "/m2m/led/device" */
#ifdef ENABLE_TEMP
               if( ! strcmp("/m2m/temp", (char*)msg ) )
                  tempTid = smq->ptid;
               else
#endif
               {
                  deviceTid = smq->ptid;
                  SharkMQ_observe(smq, deviceTid);
               }
               break;
            case SMQ_CREATESUBACK: /* We get a total of two messages */
                /* We get two suback messages ("devinfo" and "led") */
               if( ! strcmp("led", (char*)msg ) )
               {  /* Ack for: SMQ_createsub(smq, "led"); */
                  ledSubTid = smq->ptid;
               }
               else /* Must be ACK for devinfo */
               {  /* Ack for: SMQ_createsub(smq, "devinfo"); */
                  baAssert( ! strcmp("devinfo", (char*)msg) );
                  baAssert(deviceTid); /* acks are in sequence */
                  devInfoSubTid = smq->ptid;
                  /* We have sufficient info for publishing the device
                     info message.  All connected browsers will
                     receive this message and update their UI accordingly.
                  */
                  sendDevInfo(smq, ipaddr, deviceTid, devInfoSubTid);
               }
               break;

            case SMQ_SUBCHANGE:
               xprintf(("Connected browsers: %d\n", smq->status));
               break;

            /* Error codes */

            case SMQE_DISCONNECT: 
               xprintf(("Disconnect request from server\n"));
               setProgramStatus(ProgramStatus_CloseCommandReceived);
               return -1;

            case SMQE_BUF_OVERFLOW:
               xprintf(("Increase buffer size\n"));
               setProgramStatus(ProgramStatus_MemoryError);
               return -1; /* Must exit */

            default:
               xprintf(("Rec Error: %d.\n",smq->status));
               setProgramStatus(ProgramStatus_InvalidCommandError);
               return 0;
         }
      }
      else if(len > 0)
      {
         if(smq->tid == displayTid) /* topic "display" */
         {
            /* Send device info to the new display unit: Send to
             * browser's ephemeral ID (ptid).
             */
            sendDevInfo(smq, ipaddr, smq->ptid, devInfoSubTid);
         }
         else if(smq->tid == smq->clientTid) /* sent to our ephemeral tid */
         {
            if(setLed(msg[0], msg[1]))
            {
               xprintf(("ptid %X attempting to set invalid LED %d\n",
                        smq->ptid, msg[0]));
               return 0;
            }
            /* Update all display units */
            outData[0] = msg[0];
            outData[1] = msg[1];
            /* Publish to "/m2m/led/device", sub-topic "led" */
            SharkMQ_publish(smq, outData, 2, deviceTid, ledSubTid);
         }
         else
         {
            xprintf(("Received unknown tid %X\n", smq->tid));
            return 0;
         }
      }
      else /* timeout */
      {
         int x; /* used for storing ledId and temperature */
         int on;
         if(setLedFromDevice(&x,&on)) /* If a local button was pressed */
         {  /* Publish to all subscribed browsers and set the LED on/off */
            outData[0] = (U8)x; /* x is ledId */
            outData[1] = (U8)on;
            /* Publish to "/m2m/led/device", sub-topic "led" */
            SharkMQ_publish(smq, outData, 2, deviceTid, ledSubTid);
            setLed(x, on); /* set the LED on/off */
         }
#ifdef ENABLE_TEMP
         x = getTemp();
         if(x != (int)temperature)
         {
            temperature = (S16)x;
            outData[0] = (U8)(temperature >> 8);
            outData[1] = (U8)temperature;
            SharkMQ_publish(smq, outData, 2, tempTid, 0);
         }
#endif
      }
   }
}


void
mainTask(SeCtx* ctx)
{
   static SharkSslCon* scon=0; /* not used with non secure version */
   static SharkMQ smq;
   static U8 buf[127];

   const char* smqUniqueId;
   int smqUniqueIdLen;
   smqUniqueIdLen = getUniqueId(&smqUniqueId);
   if(smqUniqueIdLen < 1)
   {
      xprintf(("Cannot get unique ID: aborting.\n"));
      return;
   }

   SharkMQ_constructor(&smq, buf, sizeof(buf));

   while(! m2mled(&smq, scon, smqUniqueId, smqUniqueIdLen) )
   {
      xprintf(("Closing connection; status: %d\n",smq.status));
      SharkMQ_disconnect(&smq);
   }
   SharkMQ_destructor(&smq);
}