libraries / Bridge / src / Bridge.cppon commit Added link to project report (97a3ba0)
   1/*
   2  Copyright (c) 2013 Arduino LLC. All right reserved.
   3
   4  This library is free software; you can redistribute it and/or
   5  modify it under the terms of the GNU Lesser General Public
   6  License as published by the Free Software Foundation; either
   7  version 2.1 of the License, or (at your option) any later version.
   8
   9  This library is distributed in the hope that it will be useful,
  10  but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  12  Lesser General Public License for more details.
  13
  14  You should have received a copy of the GNU Lesser General Public
  15  License along with this library; if not, write to the Free Software
  16  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
  17*/
  18
  19#include "Bridge.h"
  20
  21BridgeClass::BridgeClass(Stream &_stream) :
  22  index(0), stream(_stream), started(false), max_retries(0) {
  23  // Empty
  24}
  25
  26void BridgeClass::begin() {
  27  if (started)
  28    return;
  29  started = true;
  30
  31  // Wait for U-boot to finish startup
  32  do {
  33    dropAll();
  34    delay(1000);
  35  } while (stream.available() > 0);
  36
  37  while (true) {
  38    // Bridge interrupt:
  39    // - Ask the bridge to close itself
  40    uint8_t quit_cmd[] = {'X', 'X', 'X', 'X', 'X'};
  41    max_retries = 1;
  42    transfer(quit_cmd, 5);
  43
  44    // Bridge startup:
  45    // - If the bridge is not running starts it safely
  46    stream.print(CTRL_C);
  47    delay(250);
  48    stream.print(F("\n"));
  49    delay(250);
  50    stream.print(F("\n"));
  51    delay(500);
  52    // Wait for OpenWRT message
  53    // "Press enter to activate console"
  54    stream.print(F("run-bridge\n"));
  55    delay(500);
  56    dropAll();
  57
  58    // Reset the brigde to check if it is running
  59    uint8_t cmd[] = {'X', 'X', '1', '0', '0'};
  60    uint8_t res[4];
  61    max_retries = 50;
  62    uint16_t l = transfer(cmd, 5, res, 4);
  63    if (l == TRANSFER_TIMEOUT) {
  64      // Bridge didn't start...
  65      // Maybe the board is starting-up?
  66
  67      // Wait and retry
  68      delay(1000);
  69      continue;
  70    }
  71    if (res[0] != 0)
  72      while (true);
  73
  74    // Detect bridge version
  75    if (l == 4) {
  76      bridgeVersion = (res[1]-'0')*100 + (res[2]-'0')*10 + (res[3]-'0');
  77    } else {
  78      // Bridge v1.0.0 didn't send any version info
  79      bridgeVersion = 100;
  80    }
  81
  82    max_retries = 50;
  83    return;
  84  }
  85}
  86
  87void BridgeClass::put(const char *key, const char *value) {
  88  // TODO: do it in a more efficient way
  89  String cmd = "D";
  90  uint8_t res[1];
  91  cmd += key;
  92  cmd += "\xFE";
  93  cmd += value;
  94  transfer((uint8_t*)cmd.c_str(), cmd.length(), res, 1);
  95}
  96
  97unsigned int BridgeClass::get(const char *key, uint8_t *value, unsigned int maxlen) {
  98  uint8_t cmd[] = {'d'};
  99  unsigned int l = transfer(cmd, 1, (uint8_t *)key, strlen(key), value, maxlen);
 100  if (l < maxlen)
 101    value[l] = 0; // Zero-terminate string
 102  return l;
 103}
 104
 105#if defined(ARDUINO_ARCH_AVR)
 106// AVR use an optimized implementation of CRC
 107#include <util/crc16.h>
 108#else
 109// Generic implementation for non-AVR architectures
 110uint16_t _crc_ccitt_update(uint16_t crc, uint8_t data)
 111{
 112  data ^= crc & 0xff;
 113  data ^= data << 4;
 114  return ((((uint16_t)data << 8) | ((crc >> 8) & 0xff)) ^
 115          (uint8_t)(data >> 4) ^
 116          ((uint16_t)data << 3));
 117}
 118#endif
 119
 120void BridgeClass::crcUpdate(uint8_t c) {
 121  CRC = _crc_ccitt_update(CRC, c);
 122}
 123
 124void BridgeClass::crcReset() {
 125  CRC = 0xFFFF;
 126}
 127
 128void BridgeClass::crcWrite() {
 129  stream.write((char)(CRC >> 8));
 130  stream.write((char)(CRC & 0xFF));
 131}
 132
 133bool BridgeClass::crcCheck(uint16_t _CRC) {
 134  return CRC == _CRC;
 135}
 136
 137uint16_t BridgeClass::transfer(const uint8_t *buff1, uint16_t len1,
 138                               const uint8_t *buff2, uint16_t len2,
 139                               const uint8_t *buff3, uint16_t len3,
 140                               uint8_t *rxbuff, uint16_t rxlen)
 141{
 142  uint16_t len = len1 + len2 + len3;
 143  uint8_t retries = 0;
 144  for ( ; retries < max_retries; retries++, delay(100), dropAll() /* Delay for retransmission */) {
 145    // Send packet
 146    crcReset();
 147    stream.write((char)0xFF);                // Start of packet (0xFF)
 148    crcUpdate(0xFF);
 149    stream.write((char)index);               // Message index
 150    crcUpdate(index);
 151    stream.write((char)((len >> 8) & 0xFF)); // Message length (hi)
 152    crcUpdate((len >> 8) & 0xFF);
 153    stream.write((char)(len & 0xFF));        // Message length (lo)
 154    crcUpdate(len & 0xFF);
 155    for (uint16_t i = 0; i < len1; i++) { // Payload
 156      stream.write((char)buff1[i]);
 157      crcUpdate(buff1[i]);
 158    }
 159    for (uint16_t i = 0; i < len2; i++) { // Payload
 160      stream.write((char)buff2[i]);
 161      crcUpdate(buff2[i]);
 162    }
 163    for (uint16_t i = 0; i < len3; i++) { // Payload
 164      stream.write((char)buff3[i]);
 165      crcUpdate(buff3[i]);
 166    }
 167    crcWrite();                     // CRC
 168
 169    // Wait for ACK in 100ms
 170    if (timedRead(100) != 0xFF)
 171      continue;
 172    crcReset();
 173    crcUpdate(0xFF);
 174
 175    // Check packet index
 176    if (timedRead(5) != index)
 177      continue;
 178    crcUpdate(index);
 179
 180    // Recv len
 181    int lh = timedRead(10);
 182    if (lh < 0)
 183      continue;
 184    crcUpdate(lh);
 185    int ll = timedRead(10);
 186    if (ll < 0)
 187      continue;
 188    crcUpdate(ll);
 189    uint16_t l = lh;
 190    l <<= 8;
 191    l += ll;
 192
 193    // Recv data
 194    for (uint16_t i = 0; i < l; i++) {
 195      // Cut received data if rxbuffer is too small
 196      if (i >= rxlen)
 197          break;
 198      int c = timedRead(5);
 199      if (c < 0)
 200        continue;
 201      rxbuff[i] = c;
 202      crcUpdate(c);
 203    }
 204
 205    // Check CRC
 206    int crc_hi = timedRead(5);
 207    if (crc_hi < 0)
 208      continue;
 209    int crc_lo = timedRead(5);
 210    if (crc_lo < 0)
 211      continue;
 212    if (!crcCheck((crc_hi << 8) + crc_lo))
 213      continue;
 214
 215    // Increase index
 216    index++;
 217
 218    // Return bytes received
 219    if (l > rxlen)
 220      return rxlen;
 221    return l;
 222  }
 223
 224  // Max retries exceeded
 225  return TRANSFER_TIMEOUT;
 226}
 227
 228int BridgeClass::timedRead(unsigned int timeout) {
 229  int c;
 230  unsigned long _startMillis = millis();
 231  do {
 232    c = stream.read();
 233    if (c >= 0) return c;
 234  } while (millis() - _startMillis < timeout);
 235  return -1;     // -1 indicates timeout
 236}
 237
 238void BridgeClass::dropAll() {
 239  while (stream.available() > 0) {
 240    stream.read();
 241  }
 242}
 243
 244#if defined(ARDUINO_ARCH_SAM)
 245#include <Reset.h>
 246#endif
 247
 248#if defined(ARDUINO_ARCH_SAM)
 249void checkForRemoteSketchUpdate(uint8_t pin) {
 250  // The host force pin LOW to signal that a new sketch is coming
 251  pinMode(pin, INPUT_PULLUP);
 252  delay(50);
 253  if (digitalRead(pin) == LOW) {
 254    initiateReset(1);
 255    while (true)
 256      ; // Wait for reset to SAM-BA
 257  }
 258
 259  // Restore in standard state
 260  pinMode(pin, INPUT);
 261}
 262#else
 263void checkForRemoteSketchUpdate(uint8_t /* pin */) {
 264  // Empty, bootloader is enough.
 265}
 266#endif
 267
 268// Bridge instance
 269#if defined(SERIAL_PORT_LINUXBRIDGE)
 270SerialBridgeClass Bridge(SERIAL_PORT_LINUXBRIDGE);
 271#elif defined(SERIAL_PORT_HARDWARE)
 272SerialBridgeClass Bridge(SERIAL_PORT_HARDWARE);
 273#elif defined(SERIAL_PORT_HARDWARE_OPEN)
 274SerialBridgeClass Bridge(SERIAL_PORT_HARDWARE_OPEN);
 275#elif defined(__AVR_ATmega32U4__) // Legacy fallback
 276// Leonardo variants (where HardwareSerial is Serial1)
 277SerialBridgeClass Bridge(Serial1);
 278#else
 279SerialBridgeClass Bridge(Serial);
 280#endif
 281