COSA
An Object-Oriented Platform for Arduino Programming
HCI.cpp
Go to the documentation of this file.
1 
21 #include "HCI.hh"
22 #include "Cosa/RTT.hh"
23 
24 int
25 HCI::read(uint16_t &op, void* args, uint8_t len)
26 {
27  // Check that a message is available
28  if (!m_available) return (0);
29 
30  // Read the SPI message header (big-endian)
31  uint16_t payload = 0;
32  bool padding;
33  int res = EFAULT;
34  op = 0;
35 
36  // Check header type
37  spi.acquire(this);
38  spi.begin();
40  res = ENOMSG;
41  spi.transfer(0);
42  spi.transfer(0);
43  payload = spi.transfer(0);
44  payload = (payload << 8) | spi.transfer(0);
45 
46  // Sanity check the SPI payload
47  if (payload >= sizeof(HCI::cmnd_header_t)) {
48  cmnd_header_t header;
49  spi.read(&header, sizeof(header));
50  payload -= sizeof(header);
51  res = EINVAL;
52 
53  // Check the HCI header type and length
54  if (header.type == HCI_TYPE_EVNT || header.type == HCI_TYPE_DATA) {
55  if (header.len <= len) {
56  op = header.cmnd;
57  res = header.len;
58  padding = ((res & 1) == 0);
59  spi.read(args, res);
60  if (padding) spi.transfer(0);
61  }
62  }
63  }
64  }
65 
66  // Remove payload if illegal forma
67  if (res < 0) {
68  for (uint16_t i = 0; i < payload; i++) spi.transfer(0);
69  }
70 
71  // Mark the message as read
72  m_available = false;
73  spi.end();
74  spi.release();
75 
76  // Return HCI message lenght or negative error code
77  return (res);
78 }
79 
80 int
81 HCI::write(uint8_t type, uint16_t op, const void* args, uint8_t len, bool progmem)
82 {
83  // Calculate padding and payload size
84  bool padding = (len & 1) == 0;
85  int payload = sizeof(cmnd_header_t) + len + padding;
86  int res = EFAULT;
87 
88  // Check the SPI format and write the SPI in big-endian
89  spi.acquire(this);
90  spi.begin();
92  spi.transfer(payload >> 8);
93  spi.transfer(payload);
94  spi.transfer(0);
95  spi.transfer(0);
96 
97  // HCI header in little-endian
98  spi.transfer(type);
99  spi.transfer(op & 0xff);
100  spi.transfer(op >> 8);
101  spi.transfer(len);
102 
103  // Command block in program memory
104  if (progmem)
105  spi.write_P(args, len);
106  else
107  spi.write(args, len);
108 
109  // Possible padding for even number of bytes in message
110  if (padding) spi.transfer(0);
111 
112  // Return size of block written
113  res = len;
114  }
115  spi.end();
116  spi.release();
117 
118  // Return length of HCI payload
119  return (res);
120 }
121 
122 int
123 HCI::await(uint16_t op, void* args, uint8_t len)
124 {
125  uint32_t start = RTT::millis();
126  uint16_t event;
127  int res;
128 
129  // Wait for given event(op) for max timeout setting
130  while (1) {
131 
132  // Sleep while waiting for a message
133  do {
134  while (!m_available && (RTT::since(start) < m_timeout)) yield();
135  if (!m_available) return (ETIME);
136  res = read(event, m_evnt, EVNT_MAX);
137  } while (res == ENOMSG);
138 
139  // Return on negative error code
140  if (res < 0) return (res);
141 
142  // Check for event code and event size match
143  if (op == event && res == len) {
144  if (args != NULL) memcpy(args, m_evnt, res);
145  return (res);
146  }
147 
148  // Otherwise call the message handler
149  if (m_event_handler != NULL)
150  m_event_handler->on_event(event, m_evnt, res);
151  };
152 
153  // Should not come here
154  return (ENOMSG);
155 }
156 
157 int
158 HCI::read_data(uint8_t op, void* args, uint8_t args_len,
159  void* data, uint16_t data_len)
160 {
161  // Sanity check that a message is available
162  if (!m_available) return (0);
163  uint16_t payload = 0;
164  int res = EFAULT;
165 
166  // Check the SPI message header. Read in big-endian
167  spi.acquire(this);
168  spi.begin();
170  res = ENOMSG;
171  spi.transfer(0);
172  spi.transfer(0);
173  payload = spi.transfer(0);
174  payload = (payload << 8) | spi.transfer(0);
175 
176  // Santity check the SPI payload size and read HCI header
177  if (payload >= sizeof(HCI::data_header_t)) {
178  data_header_t header;
179  spi.read(&header, sizeof(header));
180  payload -= sizeof(header);
181  res = EINVAL;
182 
183  // Sanity check the HCI format
184  if (header.type == HCI_TYPE_DATA) {
185  if (header.cmnd == op && header.args_len == args_len) {
186  res = header.payload_len - args_len;
187  if ((uint16_t) res <= data_len) {
188 
189  // Read the event block
190  if (args != NULL)
191  spi.read(args, args_len);
192  else
193  for (uint8_t i = 0; i < args_len; i++) spi.transfer(0);
194 
195  // Read the data block
196  spi.read(data, res);
197 
198  // Read possible padding
199  if (header.payload_len & 1) spi.transfer(0);
200  }
201  }
202  }
203  }
204  }
205 
206  // Skip payload if a message error was detected
207  if (res < 0) {
208  for (uint16_t i = 0; i < payload; i++) spi.transfer(0);
209  }
210 
211  // Mark message read
212  m_available = false;
213  spi.end();
214  spi.release();
215 
216  // Return data block size or negative error code
217  return (res);
218 }
219 
220 int
221 HCI::write_data(uint8_t op, const void* args, uint8_t args_len,
222  const void* data, uint16_t data_len, bool progmem)
223 {
224  // Calculate total and payload size, and padding
225  int len = args_len + data_len;
226  int payload = sizeof(data_header_t) + len;
227  bool padding = (payload & 1) == 0;
228  if (padding) payload += 1;
229  int res = EFAULT;
230 
231  // Sanity check the SPI message header; SPI header in big-endian
232  spi.acquire(this);
233  spi.begin();
235  spi.transfer(payload >> 8);
236  spi.transfer(payload);
237  spi.transfer(0);
238  spi.transfer(0);
239 
240  // HCI header in little-endian
242  spi.transfer(op);
243  spi.transfer(args_len);
244  spi.transfer(len);
245  spi.transfer(len >> 8);
246  spi.write(args, args_len);
247 
248  // Data block in program memory
249  if (progmem)
250  spi.write_P(data, data_len);
251  else
252  spi.write(data, data_len);
253 
254  // Check for padding
255  if (padding) spi.transfer(0);
256  res = len;
257  }
258  spi.end();
259  spi.release();
260 
261  // Return total number of bytes written or a negative error code
262  return (res);
263 }
int read(uint16_t &op, void *args, uint8_t len)
Definition: HCI.cpp:25
#define EINVAL
Definition: Errno.h:49
uint16_t cmnd
HCI Operation Code (little-endian).
Definition: HCI.hh:316
uint8_t transfer(uint8_t data)
Definition: SOFT_SPI.cpp:87
SPI Read(0,Payload Length).
Definition: HCI.hh:308
HCI Event (SPI_OP_READ only).
Definition: HCI.hh:337
SPI Reply(device ready).
Definition: HCI.hh:307
void acquire(Driver *dev)
Definition: SOFT_SPI.cpp:43
#define NULL
Definition: Types.h:101
uint8_t type
HCI Message Type.
Definition: HCI.hh:324
int await(uint16_t op, void *args=NULL, uint8_t len=0)
Definition: HCI.cpp:123
#define ENOMSG
Definition: Errno.h:69
uint8_t len
HCI Arguments Length.
Definition: HCI.hh:317
int write_data(uint8_t op, const void *args, uint8_t args_len, const void *data, uint16_t data_len)
Definition: HCI.hh:181
uint8_t args_len
HCI Arguments Length.
Definition: HCI.hh:326
void read(void *buf, size_t count)
Definition: SPI.hh:308
uint8_t cmnd
HCI Data Operation Code.
Definition: HCI.hh:325
#define ETIME
Definition: Errno.h:89
static uint32_t since(uint32_t start)
Definition: RTT.hh:107
int read_data(uint8_t op, void *args, uint8_t args_len, void *data, uint16_t data_len)
Definition: HCI.cpp:158
static uint32_t millis()
Definition: RTT.cpp:121
uint16_t m_timeout
Definition: HCI.hh:347
void write(const void *buf, size_t count)
Definition: SPI.hh:321
void(* yield)()
int write(uint8_t type, uint16_t op, const void *args, uint8_t len)
Definition: HCI.hh:100
void begin()
Definition: SPI.hh:216
void end()
Definition: SPI.hh:226
uint16_t payload_len
HCI Payload Length.
Definition: HCI.hh:327
Event::Handler * m_event_handler
Definition: HCI.hh:350
volatile bool m_available
Definition: HCI.hh:344
SPI Write(Payload Length,0).
Definition: HCI.hh:306
void write_P(const uint8_t *buf, size_t count)
Definition: SPI.hh:334
HCI Data (both SPI_OP_WRITE/READ).
Definition: HCI.hh:335
SPI spi
Definition: SPI.cpp:29
void release()
Definition: SOFT_SPI.cpp:64
uint8_t m_evnt[EVNT_MAX]
Definition: HCI.hh:356
uint8_t type
HCI Message Type.
Definition: HCI.hh:315
static const uint8_t EVNT_MAX
Definition: HCI.hh:353
#define EFAULT
Definition: Errno.h:41
virtual void on_event(uint16_t event, void *args, size_t len)=0