ARM mbed M2X API Client: The ARM mbed client library is used to send/receive data to/from AT&T's M2X service from mbed LPC1768 microcontrollers.

Dependents:   m2x-demo-all M2X_MTS_ACCEL_DEMO M2X_MTS_Accel M2X_K64F_ACCEL ... more

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers m2x-mbed.h Source File

m2x-mbed.h

00001 #include "mbed.h"
00002 #define USER_AGENT "User-Agent: M2X Mbed Client/" M2X_VERSION
00003 
00004 #ifdef DEBUG
00005 #define DBG(fmt_, data_) printf((fmt_), (data_))
00006 #define DBGLN(fmt_, data_) printf((fmt_), (data_)); printf("\n")
00007 #define DBGLNEND printf("\n")
00008 #endif  /* DEBUG */
00009 
00010 class M2XTimer {
00011 public:
00012   void start() { _timer.start(); }
00013 
00014   unsigned long read_ms() {
00015     // In case of a timestamp overflow, we reset the server timestamp recorded.
00016     // Notice that unlike Arduino, mbed would overflow every 30 minutes,
00017     // so if 2 calls to this API are more than 30 minutes apart, we are
00018     // likely to run into troubles. This is a limitation of the current
00019     // mbed platform. However, we argue that it might be a rare case that
00020     // 2 calls to this are 30 minutes apart. In most cases, we would call
00021     // this API every few seconds or minutes, this won't be a huge problem.
00022     // However, if you have a use case that would require 2 intervening
00023     // calls to this be 30 minutes apart, you might want to leverage a RTC
00024     // clock instead of the simple ticker here, or call TimeService::reset()
00025     // before making an API call to sync current time.
00026     return _timer.read_ms();
00027   }
00028 private:
00029   Timer _timer;
00030 };
00031 
00032 #include "TCPSocketConnection.h"
00033 
00034 #include <stddef.h>
00035 #include <stdint.h>
00036 #include <stdio.h>
00037 #include <string.h>
00038 
00039 #ifdef __cplusplus
00040 extern "C" {
00041 #endif
00042 
00043 void delay(int ms)
00044 {
00045   wait_ms(ms);
00046 }
00047 
00048 char* strdup(const char* s)
00049 {
00050   char* ret = (char*) malloc(strlen(s) + 1);
00051   if (ret == NULL) { return ret;}
00052   return strcpy(ret, s);
00053 }
00054 
00055 #ifdef __cplusplus
00056 }
00057 #endif
00058 
00059 class Print {
00060 public:
00061   size_t print(const char* s);
00062   size_t print(char c);
00063   size_t print(int n);
00064   size_t print(long n);
00065   size_t print(double n, int digits = 2);
00066 
00067   size_t println(const char* s);
00068   size_t println(char c);
00069   size_t println(int n);
00070   size_t println(long n);
00071   size_t println(double n, int digits = 2);
00072   size_t println();
00073 
00074   virtual size_t write(uint8_t c) = 0;
00075   virtual size_t write(const uint8_t* buf, size_t size);
00076 };
00077 
00078 size_t Print::write(const uint8_t* buf, size_t size) {
00079   size_t ret = 0;
00080   while (size--) {
00081     ret += write(*buf++);
00082   }
00083   return ret;
00084 }
00085 
00086 size_t Print::print(const char* s) {
00087   return write((const uint8_t*)s, strlen(s));
00088 }
00089 
00090 size_t Print::print(char c) {
00091   return write(c);
00092 }
00093 
00094 size_t Print::print(int n) {
00095   return print((long) n);
00096 }
00097 
00098 size_t Print::print(long n) {
00099   char buf[8 * sizeof(long) + 1];
00100   snprintf(buf, sizeof(buf), "%ld", n);
00101   return print(buf);
00102 }
00103 
00104 // Digits are ignored for now
00105 size_t Print::print(double n, int digits) {
00106   char buf[65];
00107   snprintf(buf, sizeof(buf), "%g", n);
00108   return print(buf);
00109 }
00110 
00111 size_t Print::println(const char* s) {
00112   return print(s) + println();
00113 }
00114 
00115 size_t Print::println(char c) {
00116   return print(c) + println();
00117 }
00118 
00119 size_t Print::println(int n) {
00120   return print(n) + println();
00121 }
00122 
00123 size_t Print::println(long n) {
00124   return print(n) + println();
00125 }
00126 
00127 size_t Print::println(double n, int digits) {
00128   return print(n, digits) + println();
00129 }
00130 
00131 size_t Print::println() {
00132   return print('\r') + print('\n');
00133 }
00134 
00135 /*
00136  * TCP Client
00137  */
00138 class Client : public Print {
00139 public:
00140   Client();
00141   ~Client();
00142 
00143   virtual int connect(const char *host, uint16_t port);
00144   virtual size_t write(uint8_t);
00145   virtual size_t write(const uint8_t *buf, size_t size);
00146   virtual int available();
00147   virtual int read();
00148   virtual void flush();
00149   virtual void stop();
00150   virtual uint8_t connected();
00151 private:
00152   virtual int read(uint8_t *buf, size_t size);
00153   void _fillin(void);
00154   uint8_t _inbuf[128];
00155   uint8_t _incnt;
00156   void _flushout(void);
00157   uint8_t _outbuf[128];
00158   uint8_t _outcnt;
00159   TCPSocketConnection _sock;
00160 };
00161 
00162 Client::Client() : _incnt(0), _outcnt(0), _sock() {
00163     _sock.set_blocking(false, 1500);
00164 }
00165 
00166 Client::~Client() {
00167 }
00168 
00169 int Client::connect(const char *host, uint16_t port) {
00170   return _sock.connect(host, port) == 0;
00171 }
00172 
00173 size_t Client::write(uint8_t b) {
00174   return write(&b, 1);
00175 }
00176 
00177 size_t Client::write(const uint8_t *buf, size_t size) {
00178   size_t cnt = 0;
00179   while (size) {
00180     int tmp = sizeof(_outbuf) - _outcnt;
00181     if (tmp > size) tmp = size;
00182     memcpy(_outbuf + _outcnt, buf, tmp);
00183     _outcnt += tmp;
00184     buf += tmp;
00185     size -= tmp;
00186     cnt += tmp;
00187     // if no space flush it
00188     if (_outcnt == sizeof(_outbuf))
00189         _flushout();
00190   }
00191   return cnt;
00192 }
00193 
00194 void Client::_flushout(void)
00195 {
00196   if (_outcnt > 0) {
00197     // NOTE: we know it's dangerous to cast from (const uint8_t *) to (char *),
00198     // but we are trying to maintain a stable interface between the Arduino
00199     // one and the mbed one. What's more, while TCPSocketConnection has no
00200     // intention of modifying the data here, it requires us to send a (char *)
00201     // typed data. So we belive it's safe to do the cast here.
00202     _sock.send_all(const_cast<char*>((const char*) _outbuf), _outcnt);
00203     _outcnt = 0;
00204   }
00205 }
00206 
00207 void Client::_fillin(void)
00208 {
00209   int tmp = sizeof(_inbuf) - _incnt;
00210   if (tmp) {
00211     tmp = _sock.receive_all((char*)_inbuf + _incnt, tmp);
00212     if (tmp > 0)
00213       _incnt += tmp;
00214   }
00215 }
00216 
00217 void Client::flush() {
00218   _flushout();
00219 }
00220 
00221 int Client::available() {
00222   if (_incnt == 0) {
00223     _flushout();
00224     _fillin();
00225   }
00226   return (_incnt > 0) ? 1 : 0;
00227 }
00228 
00229 int Client::read() {
00230   uint8_t ch;
00231   return (read(&ch, 1) == 1) ? ch : -1;
00232 }
00233 
00234 int Client::read(uint8_t *buf, size_t size) {
00235   int cnt = 0;
00236   while (size) {
00237     // need more
00238     if (size > _incnt) {
00239       _flushout();
00240       _fillin();
00241     }
00242     if (_incnt > 0) {
00243       int tmp = _incnt;
00244       if (tmp > size) tmp = size;
00245       memcpy(buf, _inbuf, tmp);
00246       if (tmp != _incnt)
00247           memmove(_inbuf, _inbuf + tmp, _incnt - tmp);
00248       _incnt -= tmp;
00249       size -= tmp;
00250       buf += tmp;
00251       cnt += tmp;
00252     } else // no data
00253         break;
00254   }
00255   return cnt;
00256 }
00257 
00258 void Client::stop() {
00259   _sock.close();
00260 }
00261 
00262 uint8_t Client::connected() {
00263   return _sock.is_connected() ? 1 : 0;
00264 }