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

M2XStreamClient.cpp

Committer:
citrusbyte
Date:
2015-12-28
Revision:
17:9db4a86b876a
Parent:
16:7903152de19f
Child:
19:4dfa28d37b8f

File content as of revision 17:9db4a86b876a:

#include "M2XStreamClient.h"

static int fill_iso8601_timestamp(int32_t seconds, int32_t milli,
                                  char* buffer, int* length);

TimeService::TimeService(M2XStreamClient* client) : _client(client) {
}

int TimeService::init() {
  _timer.start();
  return reset();
}

int TimeService::reset() {
  int32_t ts;
  int status = _client->getTimestamp32(&ts);

  if (m2x_status_is_success(status)) {
    _server_timestamp = ts;
    _local_last_milli = _timer.read_ms();
  }

  return status;
}

int TimeService::getTimestamp(char* buffer, int* length) {
  uint32_t now = _timer.read_ms();
  if (now < _local_last_milli) {
    // In case of a timestamp overflow, we reset the server timestamp recorded.
    // Notice that unlike Arduino, mbed would overflow every 30 minutes,
    // so if 2 calls to this API are more than 30 minutes apart, we are
    // likely to run into troubles. This is a limitation of the current
    // mbed platform. However, we argue that it might be a rare case that
    // 2 calls to this are 30 minutes apart. In most cases, we would call
    // this API every few seconds or minutes, this won't be a huge problem.
    // However, if you have a use case that would require 2 intervening
    // calls to this be 30 minutes apart, you might want to leverage a RTC
    // clock instead of the simple ticker here.
    int status = reset();
    if (!m2x_status_is_success(status)) { return status; }
    now = _timer.read_ms();
  }
  if (now < _local_last_milli) {
    // We have already reseted the timestamp, so this cannot happen,
    // an HTTP request cannot last 30 minutes, something else must be wrong
    // here.
    return E_TIMESTAMP_ERROR;
  }
  uint32_t diff = now - _local_last_milli;
  _local_last_milli = now;
  _server_timestamp += (int32_t) (diff / 1000); // Milliseconds to seconds
  return fill_iso8601_timestamp(_server_timestamp, (int32_t) (diff % 1000),
                                buffer, length);
}

#define SIZE_ISO_8601 25
static inline bool is_leap_year(int16_t y) {
  return ((1970 + y) > 0) &&
      !((1970 + y) % 4) &&
      (((1970 + y) % 100) || !((1970 + y) % 400));
}
static inline int32_t days_in_year(int16_t y) {
  return is_leap_year(y) ? 366 : 365;
}
static const uint8_t MONTH_DAYS[]={31,28,31,30,31,30,31,31,30,31,30,31};

static int fill_iso8601_timestamp(int32_t timestamp, int32_t milli,
                                  char* buffer, int* length) {
  int16_t year;
  int8_t month, month_length;
  int32_t day;
  int8_t hour, minute, second;

  if (*length < SIZE_ISO_8601) {
    *length = SIZE_ISO_8601;
    return E_BUFFER_TOO_SMALL;
  }

  second = timestamp % 60;
  timestamp /= 60; // now it is minutes

  minute = timestamp % 60;
  timestamp /= 60; // now it is hours

  hour = timestamp % 24;
  timestamp /= 24; // now it is days

  year = 0;
  day = 0;
  while ((day += days_in_year(year)) <= timestamp) {
    year++;
  }
  day -= days_in_year(year);
  timestamp -= day; // now it is days in this year, starting at 0

  day = 0;
  month_length = 0;
  for (month = 0; month < 12; month++) {
    if (month == 1) {
      // February
      month_length = is_leap_year(year) ? 29 : 28;
    } else {
      month_length = MONTH_DAYS[month];
    }

    if (timestamp >= month_length) {
      timestamp -= month_length;
    } else {
      break;
    }
  }
  year = 1970 + year;
  month++; // offset by 1
  day = timestamp + 1;

  int i = 0, j = 0;

  // NOTE: It seems the snprintf implementation in Arduino has bugs,
  // we have to manually piece the string together here.
#define INT_TO_STR(v_, width_) \
  for (j = 0; j < (width_); j++) { \
    buffer[i + (width_) - 1 - j] = '0' + ((v_) % 10); \
    (v_) /= 10; \
  } \
  i += (width_)

  INT_TO_STR(year, 4);
  buffer[i++] = '-';
  INT_TO_STR(month, 2);
  buffer[i++] = '-';
  INT_TO_STR(day, 2);
  buffer[i++] = 'T';
  INT_TO_STR(hour, 2);
  buffer[i++] = ':';
  INT_TO_STR(minute, 2);
  buffer[i++] = ':';
  INT_TO_STR(second, 2);
  buffer[i++] = '.';
  INT_TO_STR(milli, 3);
  buffer[i++] = 'Z';
  buffer[i++] = '\0';

#undef INT_TO_STR

  *length = i;
  return E_OK;
}