a serial library to communicate with pebble time's smart strap interface

Dependents:   xadow_smartstrap_for_pebble

mbedPebbleSerial.cpp

Committer:
KillingJacky
Date:
2015-11-04
Revision:
0:e4dad9e53f06

File content as of revision 0:e4dad9e53f06:

/*
 * This is an Arduino library wrapper around the PebbleSerial library.
 */
#include "mbed.h"
#include "BufferedSerial.h"
#include "mbedPebbleSerial.h"

static uint8_t *s_buffer;
static size_t s_buffer_length;
static uint8_t s_pin;

extern BufferedSerial serial;

#define _BV(bit) (1<<(bit))
#define cbi(sfr, bit) ((sfr) &= ~_BV(bit))
#define sbi(sfr, bit) ((sfr) |= _BV(bit))


static void board_begin(void) {
}

static void board_set_tx_enabled(bool enabled) {
  if (enabled) {
    // enable transmitter
    sbi(LPC_USART->TER, 7);
    // disable receiver
    sbi(LPC_USART->RS485CTRL, 1);
  } else {
    // disable transmitter
    cbi(LPC_USART->TER, 7);
    // enable receiver
    cbi(LPC_USART->RS485CTRL, 1);
  }
}

static void board_set_even_parity(bool enabled) {
  if (enabled) {
    sbi(LPC_USART->LCR, 3);
    sbi(LPC_USART->LCR, 4);
  } else {
    cbi(LPC_USART->LCR, 3);
    cbi(LPC_USART->LCR, 4);
  }
}

static void board_flush_uart()
{
    while (serial._txbuf.available());
    while (!(LPC_USART->LSR & _BV(5)));
}

static void prv_cmd_cb(SmartstrapCmd cmd, uint32_t arg) {
  switch (cmd) {
  case SmartstrapCmdSetBaudRate:
    serial.baud(arg);
    break;
  case SmartstrapCmdSetTxEnabled:
    if (!arg) board_flush_uart();
    board_set_tx_enabled(arg);
    break;
  case SmartstrapCmdWriteByte:
    serial.putc((uint8_t)arg);
    break;
  case SmartstrapCmdWriteBreak:
    board_set_even_parity(true);
    serial.putc((uint8_t)0);
    // need to flush before changing parity
    board_flush_uart();
    board_set_even_parity(false);
    break;
  default:
    break;
  }
}

static void prv_begin(uint8_t *buffer, size_t length, Baud baud,
                      const uint16_t *services, uint8_t num_services) {
  s_buffer = buffer;
  s_buffer_length = length;

  pebble_init(prv_cmd_cb, (PebbleBaud)baud, services, num_services);
  pebble_prepare_for_read(s_buffer, s_buffer_length);
}

void mbedPebbleSerial::begin(uint8_t *buffer, size_t length, Baud baud,
                                         const uint16_t *services, uint8_t num_services) {
  prv_begin(buffer, length, baud, services, num_services);
}

static int prv_available_bytes(void) {
    return serial.readable();
}

static uint8_t prv_read_byte(void) {
    return (uint8_t)serial.getc();
}

bool mbedPebbleSerial::feed(uint16_t *service_id, uint16_t *attribute_id, size_t *length,
                               RequestType *type) {
  SmartstrapRequestType request_type;
  bool did_feed = false;
  while (prv_available_bytes()) {
    did_feed = true;
    if (pebble_handle_byte(prv_read_byte(), service_id, attribute_id, length, &request_type, us_ticker_read()/1000)) {
      // we have a full frame
      pebble_prepare_for_read(s_buffer, s_buffer_length);
      switch (request_type) {
      case SmartstrapRequestTypeRead:
        *type = RequestTypeRead;
        break;
      case SmartstrapRequestTypeWrite:
        *type = RequestTypeWrite;
        break;
      case SmartstrapRequestTypeWriteRead:
        *type = RequestTypeWriteRead;
        break;
      default:
        break;
      }
      return true;
    }
  }

  if (!did_feed) {
    // allow the pebble code to dicsonnect if we haven't gotten any messages recently
    pebble_is_connected(us_ticker_read()/1000);
  }
  return false;
}

bool mbedPebbleSerial::write(bool success, const uint8_t *payload, size_t length) {
  return pebble_write(success, payload, length);
}

void mbedPebbleSerial::notify(uint16_t service_id, uint16_t attribute_id) {
  pebble_notify(service_id, attribute_id);
}

bool mbedPebbleSerial::is_connected(void) {
  return pebble_is_connected(us_ticker_read()/1000);
}