arduino stuffs
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
/*
  BLEStream.h

  Based on BLESerial.cpp by Voita Molda
  https://github.com/sandeepmistry/arduino-BLEPeripheral/blob/master/examples/serial/BLESerial.h

  Last updated April 4th, 2016
 */

#ifndef _BLE_STREAM_H_
#define _BLE_STREAM_H_

#include <Arduino.h>
#if defined(_VARIANT_ARDUINO_101_X_)
#include <CurieBLE.h>
#define _MAX_ATTR_DATA_LEN_ BLE_MAX_ATTR_DATA_LEN
#else
#include <BLEPeripheral.h>
#define _MAX_ATTR_DATA_LEN_ BLE_ATTRIBUTE_MAX_VALUE_LENGTH
#endif

#define BLESTREAM_TXBUFFER_FLUSH_INTERVAL 80
#define BLESTREAM_MIN_FLUSH_INTERVAL 8 // minimum interval for flushing the TX buffer

// #define BLE_SERIAL_DEBUG

class BLEStream : public BLEPeripheral, public Stream
{
  public:
    BLEStream(unsigned char req = 0, unsigned char rdy = 0, unsigned char rst = 0);

    void begin(...);
    bool poll();
    void end();
    void setFlushInterval(int);

    virtual int available(void);
    virtual int peek(void);
    virtual int read(void);
    virtual void flush(void);
    virtual size_t write(uint8_t byte);
    using Print::write;
    virtual operator bool();

  private:
    bool _connected;
    unsigned long _flushed;
    int _flushInterval;
    static BLEStream* _instance;

    size_t _rxHead;
    size_t _rxTail;
    size_t _rxCount() const;
    unsigned char _rxBuffer[256];
    size_t _txCount;
    unsigned char _txBuffer[_MAX_ATTR_DATA_LEN_];

    BLEService _uartService = BLEService("6E400001-B5A3-F393-E0A9-E50E24DCCA9E");
    BLEDescriptor _uartNameDescriptor = BLEDescriptor("2901", "UART");
    BLECharacteristic _rxCharacteristic = BLECharacteristic("6E400002-B5A3-F393-E0A9-E50E24DCCA9E", BLEWriteWithoutResponse, _MAX_ATTR_DATA_LEN_);
    BLEDescriptor _rxNameDescriptor = BLEDescriptor("2901", "RX - Receive Data (Write)");
    BLECharacteristic _txCharacteristic = BLECharacteristic("6E400003-B5A3-F393-E0A9-E50E24DCCA9E", BLENotify, _MAX_ATTR_DATA_LEN_);
    BLEDescriptor _txNameDescriptor = BLEDescriptor("2901", "TX - Transfer Data (Notify)");

    void _received(const unsigned char* data, size_t size);
    static void _received(BLECentral& /*central*/, BLECharacteristic& rxCharacteristic);
};


/*
 * BLEStream.cpp
 * Copied here as a hack to avoid having to install the BLEPeripheral libarary even if it's
 * not needed.
 */

BLEStream* BLEStream::_instance = NULL;

BLEStream::BLEStream(unsigned char req, unsigned char rdy, unsigned char rst) :
#if defined(_VARIANT_ARDUINO_101_X_)
  BLEPeripheral()
#else
  BLEPeripheral(req, rdy, rst)
#endif
{
  this->_txCount = 0;
  this->_rxHead = this->_rxTail = 0;
  this->_flushed = 0;
  this->_flushInterval = BLESTREAM_TXBUFFER_FLUSH_INTERVAL;
  BLEStream::_instance = this;

  addAttribute(this->_uartService);
  addAttribute(this->_uartNameDescriptor);
  setAdvertisedServiceUuid(this->_uartService.uuid());
  addAttribute(this->_rxCharacteristic);
  addAttribute(this->_rxNameDescriptor);
  this->_rxCharacteristic.setEventHandler(BLEWritten, BLEStream::_received);
  addAttribute(this->_txCharacteristic);
  addAttribute(this->_txNameDescriptor);
}

void BLEStream::begin(...)
{
  BLEPeripheral::begin();
#ifdef BLE_SERIAL_DEBUG
  Serial.println(F("BLEStream::begin()"));
#endif
}

bool BLEStream::poll()
{
  // BLEPeripheral::poll is called each time connected() is called
  this->_connected = BLEPeripheral::connected();
  if (millis() > this->_flushed + this->_flushInterval) {
    flush();
  }
  return this->_connected;
}

void BLEStream::end()
{
  this->_rxCharacteristic.setEventHandler(BLEWritten, (void(*)(BLECentral&, BLECharacteristic&))NULL);
  this->_rxHead = this->_rxTail = 0;
  flush();
  BLEPeripheral::disconnect();
}

int BLEStream::available(void)
{
// BLEPeripheral::poll only calls delay(1) in CurieBLE so skipping it here to avoid the delay
#ifndef _VARIANT_ARDUINO_101_X_
  // TODO Need to do more testing to determine if all of these calls to BLEPeripheral::poll are
  // actually necessary. Seems to run fine without them, but only minimal testing so far.
  BLEPeripheral::poll();
#endif
  int retval = (this->_rxHead - this->_rxTail + sizeof(this->_rxBuffer)) % sizeof(this->_rxBuffer);
#ifdef BLE_SERIAL_DEBUG
  if (retval > 0) {
    Serial.print(F("BLEStream::available() = "));
    Serial.println(retval);
  }
#endif
  return retval;
}

int BLEStream::peek(void)
{
#ifndef _VARIANT_ARDUINO_101_X_
  BLEPeripheral::poll();
#endif
  if (this->_rxTail == this->_rxHead) return -1;
  uint8_t byte = this->_rxBuffer[this->_rxTail];
#ifdef BLE_SERIAL_DEBUG
  Serial.print(F("BLEStream::peek() = 0x"));
  Serial.println(byte, HEX);
#endif
  return byte;
}

int BLEStream::read(void)
{
#ifndef _VARIANT_ARDUINO_101_X_
  BLEPeripheral::poll();
#endif
  if (this->_rxTail == this->_rxHead) return -1;
  this->_rxTail = (this->_rxTail + 1) % sizeof(this->_rxBuffer);
  uint8_t byte = this->_rxBuffer[this->_rxTail];
#ifdef BLE_SERIAL_DEBUG
  Serial.print(F("BLEStream::read() = 0x"));
  Serial.println(byte, HEX);
#endif
  return byte;
}

void BLEStream::flush(void)
{
  if (this->_txCount == 0) return;
#ifndef _VARIANT_ARDUINO_101_X_
  // ensure there are available packets before sending
  while(!this->_txCharacteristic.canNotify()) {
    BLEPeripheral::poll();
  }
#endif
  this->_txCharacteristic.setValue(this->_txBuffer, this->_txCount);
  this->_flushed = millis();
  this->_txCount = 0;
#ifdef BLE_SERIAL_DEBUG
  Serial.println(F("BLEStream::flush()"));
#endif
}

size_t BLEStream::write(uint8_t byte)
{
#ifndef _VARIANT_ARDUINO_101_X_
  BLEPeripheral::poll();
#endif
  if (this->_txCharacteristic.subscribed() == false) return 0;
  this->_txBuffer[this->_txCount++] = byte;
  if (this->_txCount == sizeof(this->_txBuffer)) flush();
#ifdef BLE_SERIAL_DEBUG
  Serial.print(F("BLEStream::write( 0x"));
  Serial.print(byte, HEX);
  Serial.println(F(") = 1"));
#endif
  return 1;
}

BLEStream::operator bool()
{
  bool retval = this->_connected = BLEPeripheral::connected();
#ifdef BLE_SERIAL_DEBUG
  Serial.print(F("BLEStream::operator bool() = "));
  Serial.println(retval);
#endif
  return retval;
}

void BLEStream::setFlushInterval(int interval)
{
  if (interval > BLESTREAM_MIN_FLUSH_INTERVAL) {
    this->_flushInterval = interval;
  }
}

void BLEStream::_received(const unsigned char* data, size_t size)
{
  for (size_t i = 0; i < size; i++) {
    this->_rxHead = (this->_rxHead + 1) % sizeof(this->_rxBuffer);
    this->_rxBuffer[this->_rxHead] = data[i];
  }
#ifdef BLE_SERIAL_DEBUG
  Serial.print(F("BLEStream::received("));
  for (int i = 0; i < size; i++) Serial.print(data[i], HEX);
  Serial.println(F(")"));
#endif
}

void BLEStream::_received(BLECentral& /*central*/, BLECharacteristic& rxCharacteristic)
{
  BLEStream::_instance->_received(rxCharacteristic.value(), rxCharacteristic.valueLength());
}


#endif // _BLE_STREAM_H_