phyphox BLE
Plot your Arduino's data in the phyphox app and control the board from the phone
Loading...
Searching...
No Matches
NinaB31Protocol.h
Go to the documentation of this file.
1// The text side of the u-connectXpress AT protocol the NINA-B31 transport speaks: line
2// classification, the events the module raises and the responses it gives. Plain C++ with no
3// Arduino dependency so the host tests can exercise every parse (tests/host/test_nina_protocol.cpp).
4// Formats from the u-connectXpress AT commands manual (UBX-14044127):
5// +UUBTACLC:<conn>,<type>,<addr> ACL connected +UUBTACLD:<conn> disconnected
6// +UUBTGRW:<conn>,<handle>,<hex>,<opt> attribute written +UUBTGRR:<conn>,<handle> read request
7// +UBTGSER:<handle> service created +UBTGCHA:<value>,<cccd> characteristic
8#ifndef PHYPHOX_BLE_TRANSPORT_NINAB31_PROTOCOL_H
9#define PHYPHOX_BLE_TRANSPORT_NINAB31_PROTOCOL_H
10
11#include <stdint.h>
12#include <string.h>
13#include <stdlib.h>
14
15namespace phyphox {
16namespace nina {
17
20static const uint16_t kLineMax = 128;
21
22inline int hexVal(char c) {
23 if (c >= '0' && c <= '9') return c - '0';
24 if (c >= 'a' && c <= 'f') return c - 'a' + 10;
25 if (c >= 'A' && c <= 'F') return c - 'A' + 10;
26 return -1;
27}
28
30inline uint16_t decodeHex(const char* s, uint8_t* out, uint16_t cap) {
31 uint16_t n = 0;
32 while (n < cap) {
33 int hi = hexVal(s[0]); if (hi < 0) break;
34 int lo = hexVal(s[1]); if (lo < 0) break;
35 out[n++] = (uint8_t)((hi << 4) | lo);
36 s += 2;
37 }
38 return n;
39}
40
41inline void encodeHex(const uint8_t* data, uint16_t len, char* out) {
42 static const char* h = "0123456789ABCDEF";
43 for (uint16_t i = 0; i < len; ++i) { *out++ = h[data[i] >> 4]; *out++ = h[data[i] & 15]; }
44 *out = 0;
45}
46
48inline bool isEvent(const char* line) { return strncmp(line, "+UU", 3) == 0; }
49inline bool startsWith(const char* line, const char* prefix) { return strncmp(line, prefix, strlen(prefix)) == 0; }
50
52inline int firstNumber(const char* line) {
53 const char* colon = strchr(line, ':');
54 if (!colon) return -1;
55 return atoi(colon + 1);
56}
57
59inline bool parseCharacteristicResponse(const char* line, int& valueHandle, int& cccdHandle) {
60 if (!startsWith(line, "+UBTGCHA:")) return false;
61 const char* p = line + 9;
62 valueHandle = atoi(p);
63 const char* comma = strchr(p, ',');
64 cccdHandle = comma ? atoi(comma + 1) : 0;
65 return true;
66}
67
69
70struct Event {
72 int conn = 0;
73 int handle = 0;
74 uint8_t data[64];
75 uint16_t len = 0;
76};
77
79inline Event parseEvent(const char* line) {
80 Event e;
81 if (startsWith(line, "+UUBTACLC:")) { e.kind = EV_CONNECTED; e.conn = atoi(line + 10); return e; }
82 if (startsWith(line, "+UUBTACLD:")) { e.kind = EV_DISCONNECTED; e.conn = atoi(line + 10); return e; }
83 if (startsWith(line, "+UUBTGRR:")) {
84 const char* p = line + 9; e.conn = atoi(p);
85 const char* c1 = strchr(p, ','); if (!c1) return e;
86 e.handle = atoi(c1 + 1); e.kind = EV_READ; return e;
87 }
88 if (startsWith(line, "+UUBTGRW:")) {
89 const char* p = line + 9; e.conn = atoi(p);
90 const char* c1 = strchr(p, ','); if (!c1) return e;
91 e.handle = atoi(c1 + 1);
92 const char* c2 = strchr(c1 + 1, ','); if (!c2) return e;
93 e.len = decodeHex(c2 + 1, e.data, sizeof(e.data));
94 e.kind = EV_WRITE; return e;
95 }
96 e.kind = EV_OTHER;
97 return e;
98}
99
103public:
105 bool feed(char c) {
106 if (c == '\r' || c == '\n') {
107 bool complete = len_ > 0 && !overflow_;
108 buf_[len_] = 0;
109 len_ = 0; overflow_ = false;
110 return complete;
111 }
112 if (len_ < kLineMax - 1) buf_[len_++] = c; else overflow_ = true;
113 return false;
114 }
115 const char* line() const { return buf_; }
116private:
117 char buf_[kLineMax] = {0};
118 uint16_t len_ = 0;
119 bool overflow_ = false;
120};
121
124template <uint8_t N>
126public:
127 bool push(const char* line) {
128 if (count_ >= N) { dropped_++; return false; }
129 strncpy(slots_[(head_ + count_) % N], line, kLineMax - 1);
130 slots_[(head_ + count_) % N][kLineMax - 1] = 0;
131 count_++;
132 return true;
133 }
134 bool pop(char* out) {
135 if (!count_) return false;
136 strcpy(out, slots_[head_]);
137 head_ = (head_ + 1) % N; count_--;
138 return true;
139 }
140 uint8_t size() const { return count_; }
141 uint32_t dropped() const { return dropped_; }
142private:
143 char slots_[N][kLineMax];
144 uint8_t head_ = 0, count_ = 0;
145 uint32_t dropped_ = 0;
146};
147
148} // namespace nina
149} // namespace phyphox
150
151#endif
Fixed ring of event lines, filled while a command waits for its response and drained from poll().
Definition NinaB31Protocol.h:125
bool pop(char *out)
Definition NinaB31Protocol.h:134
bool push(const char *line)
Definition NinaB31Protocol.h:127
uint8_t size() const
Definition NinaB31Protocol.h:140
uint32_t dropped() const
Definition NinaB31Protocol.h:141
Assembles lines from the byte stream.
Definition NinaB31Protocol.h:102
const char * line() const
Definition NinaB31Protocol.h:115
bool feed(char c)
Feed one byte; returns true when line() holds a complete line.
Definition NinaB31Protocol.h:105
void encodeHex(const uint8_t *data, uint16_t len, char *out)
Definition NinaB31Protocol.h:41
bool parseCharacteristicResponse(const char *line, int &valueHandle, int &cccdHandle)
"+UBTGCHA:<value_handle>,<cccd_handle>"; cccd is 0 when the characteristic has none.
Definition NinaB31Protocol.h:59
static const uint16_t kLineMax
Longest line kept: a 20-byte write is ~62 characters, a six-component sensor write ~70.
Definition NinaB31Protocol.h:20
bool startsWith(const char *line, const char *prefix)
Definition NinaB31Protocol.h:49
EventKind
Definition NinaB31Protocol.h:68
@ EV_DISCONNECTED
Definition NinaB31Protocol.h:68
@ EV_READ
Definition NinaB31Protocol.h:68
@ EV_NONE
Definition NinaB31Protocol.h:68
@ EV_CONNECTED
Definition NinaB31Protocol.h:68
@ EV_WRITE
Definition NinaB31Protocol.h:68
@ EV_OTHER
Definition NinaB31Protocol.h:68
Event parseEvent(const char *line)
Classify and parse one unsolicited line.
Definition NinaB31Protocol.h:79
int firstNumber(const char *line)
The integer after ':' (a handle), or -1 if the line has none.
Definition NinaB31Protocol.h:52
uint16_t decodeHex(const char *s, uint8_t *out, uint16_t cap)
Decode hex digits up to the first non-hex character; returns the byte count.
Definition NinaB31Protocol.h:30
int hexVal(char c)
Definition NinaB31Protocol.h:22
bool isEvent(const char *line)
Unsolicited result codes all start with "+UU"; everything else belongs to the command in flight.
Definition NinaB31Protocol.h:48
Definition ChannelStore.h:11
Definition NinaB31Protocol.h:70
int handle
Definition NinaB31Protocol.h:73
uint16_t len
Definition NinaB31Protocol.h:75
uint8_t data[64]
Definition NinaB31Protocol.h:74
int conn
Definition NinaB31Protocol.h:72
EventKind kind
Definition NinaB31Protocol.h:71