source: azure_iot_hub_f767zi/trunk/asp_baseplatform/gdic/ble_shield2.1/utility/hal_aci_tl.c@ 457

Last change on this file since 457 was 457, checked in by coas-nagasima, 4 years ago

ファイルを追加

  • Property svn:eol-style set to native
  • Property svn:mime-type set to text/x-csrc;charset=UTF-8
File size: 13.2 KB
Line 
1/* Copyright (c) 2014, Nordic Semiconductor ASA
2 *
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to deal
5 * in the Software without restriction, including without limitation the rights
6 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7 * copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
9 *
10 * The above copyright notice and this permission notice shall be included in all
11 * copies or substantial portions of the Software.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 * SOFTWARE.
20 */
21
22/** @file
23@brief Implementation of the ACI transport layer module
24*/
25
26#include "hal_platform.h"
27#include "hal_aci_tl.h"
28#include "aci_queue.h"
29
30/*
31PIC32 supports only MSbit transfer on SPI and the nRF8001 uses LSBit
32Use the REVERSE_BITS macro to convert from MSBit to LSBit
33The outgoing command and the incoming event needs to be converted
34*/
35//Board dependent defines
36//For ChipKit as the transmission has to be reversed, the next definitions have to be added
37#ifdef __STM32__
38#define REVERSE_BITS(byte) (byte)
39#else
40#define REVERSE_BITS(byte) (((reverse_lookup[(byte & 0x0F)]) << 4) + reverse_lookup[((byte & 0xF0) >> 4)])
41static const uint8_t reverse_lookup[] = { 0, 8, 4, 12, 2, 10, 6, 14,1, 9, 5, 13,3, 11, 7, 15 };
42#endif
43
44static void m_aci_data_print(hal_aci_data_t *p_data);
45static void m_aci_event_check(void);
46static void m_aci_pins_set(aci_pins_t *a_pins_ptr);
47static inline void m_aci_reqn_disable (void);
48static inline void m_aci_reqn_enable (void);
49static void m_aci_q_flush(void);
50static bool m_aci_spi_transfer(hal_aci_data_t * data_to_send, hal_aci_data_t * received_data);
51
52static uint8_t spi_readwrite(uint8_t aci_byte);
53
54
55static bool aci_debug_print = false;
56
57aci_queue_t aci_tx_q;
58aci_queue_t aci_rx_q;
59
60static aci_pins_t *a_pins_local_ptr;
61
62static SPI_Handle_t *hspi;
63static int evt_taskid;
64static int aci_activate;
65
66/* Buffer used for transmission */
67uint8_t aTxBuffer[4];
68
69/* Buffer used for reception */
70uint8_t aRxBuffer[4];
71
72static uint8_t spi_transfer(uint8_t a)
73{
74 ER ercd;
75
76 aTxBuffer[0] = a;
77#if SPI_WAIT_TIME != 0
78 ercd = spi_transrecv(hspi, (uint8_t*)aTxBuffer, (uint8_t *)aRxBuffer, 1);
79#else
80 if((ercd = spi_transrecv(hspi, (uint8_t*)aTxBuffer, (uint8_t *)aRxBuffer, 1)) == E_OK)
81 ercd = spi_wait(hspi, 100);
82#endif
83 if(ercd != E_OK){
84 /* Transfer error in transmission process */
85 syslog_1(LOG_NOTICE, "## call Error_Handler(2)(%d) ##", ercd);
86 }
87 return aRxBuffer[0];
88}
89
90/*
91 * GPIO設定関数
92 */
93static void pinMode(uint32_t no, int mode)
94{
95 Arduino_PortControlBlock *ppcb = getGpioTable(DIGITAL_PIN, no);
96 GPIO_Init_t GPIO_Init_Data;
97
98 syslog_2(LOG_NOTICE, "## pinMode(%d, %d) ##", no, mode);
99 syslog_2(LOG_NOTICE, "## [%08x](%d) ##", ppcb->giobase, ppcb->giopin);
100 if(ppcb == NULL)
101 return;
102 pinClock(no);
103 if(mode == OUTPUT){
104 GPIO_Init_Data.mode = GPIO_MODE_OUTPUT;
105 GPIO_Init_Data.pull = GPIO_PULLUP;
106 GPIO_Init_Data.otype = GPIO_OTYPE_PP;
107#ifdef TOPPERS_BASE_PLATFORM_RV
108 GPIO_Init_Data.oxor = GPIO_OUTPUT_NORMAL;
109 GPIO_Init_Data.iof = GPIO_NOIOF;
110#else
111 GPIO_Init_Data.speed = GPIO_SPEED_FAST;
112#endif
113 gpio_setup(ppcb->giobase, &GPIO_Init_Data, ppcb->giopin);
114 }
115 else{
116 GPIO_Init_Data.mode = GPIO_MODE_IT_RISING_FALLING;
117 if(mode == INPUT_PULLUP)
118 GPIO_Init_Data.pull = GPIO_PULLUP;
119 else
120 GPIO_Init_Data.pull = GPIO_NOPULL;
121 gpio_setup(ppcb->giobase, &GPIO_Init_Data, ppcb->giopin);
122 }
123}
124
125void m_aci_data_print(hal_aci_data_t *p_data)
126{
127 const uint8_t length = p_data->buffer[0];
128 uint8_t i, j, len, data[5];
129
130 len = length % 5;
131 if(len == 0)
132 len = length;
133 else
134 len = length + 5 - len;
135 for (i=j=0; i< len; i++){
136 if(i < length)
137 data[j] = p_data->buffer[i+1];
138 else
139 data[j] = 0xff;
140 if(j == 4){
141 syslog_5(LOG_NOTICE, "%02x, %02x, %02x, %02x, %02x,", data[0], data[1], data[2], data[3], data[4]);
142 j = 0;
143 }
144 else
145 j++;
146 }
147}
148
149/*
150 Interrupt service routine called when the RDYN line goes low. Runs the SPI transfer.
151*/
152void
153m_aci_isr(void)
154{
155 if(aci_activate == 0){
156 if(evt_taskid != 0)
157 iact_tsk(evt_taskid);
158 else
159 aci_task(0);
160 }
161}
162
163void aci_task(int arg)
164{
165 hal_aci_data_t data_to_send;
166 hal_aci_data_t received_data;
167#ifdef NOACT_TASK /* ROI DEBUG */
168 syslog_1(LOG_NOTICE, "## aci_task(%d) ##", arg);
169#endif /* ROI DEBUG */
170
171 aci_activate = 1;
172 // Receive from queue
173 if (!aci_queue_dequeue/*_from_isr*/(&aci_tx_q, &data_to_send))
174 {
175 /* queue was empty, nothing to send */
176 data_to_send.status_byte = 0;
177 data_to_send.buffer[0] = 0;
178 }
179
180 // Receive and/or transmit data
181 if(!m_aci_spi_transfer(&data_to_send, &received_data)){
182 m_aci_reqn_enable();
183 aci_activate = 0;
184 return;
185 }
186
187 if (!aci_queue_is_full/*_from_isr*/(&aci_rx_q) && !aci_queue_is_empty/*_from_isr*/(&aci_tx_q))
188 {
189 m_aci_reqn_enable();
190 }
191
192 // Check if we received data
193 if (received_data.buffer[0] > 0)
194 {
195 if (!aci_queue_enqueue/*_from_isr*/(&aci_rx_q, &received_data))
196 {
197 /* Receive Buffer full.
198 Should never happen.
199 Spin in a while loop.
200 */
201 syslog_0(LOG_ERROR, "aci_task Buffer full !");
202 while(1);
203 }
204 }
205 aci_activate = 0;
206
207 return;
208}
209
210/*
211 Checks the RDYN line and runs the SPI transfer if required.
212*/
213static void m_aci_event_check(void)
214{
215 hal_aci_data_t data_to_send;
216 hal_aci_data_t received_data;
217
218 // No room to store incoming messages
219 if (aci_queue_is_full(&aci_rx_q))
220 {
221 return;
222 }
223
224 // If the ready line is disabled and we have pending messages outgoing we enable the request line
225 if (HIGH == digitalRead(a_pins_local_ptr->rdyn_pin))
226 {
227 if (!aci_queue_is_empty(&aci_tx_q))
228 {
229 m_aci_reqn_enable();
230 }
231
232 return;
233 }
234
235 // Receive from queue
236 if (!aci_queue_dequeue(&aci_tx_q, &data_to_send))
237 {
238 /* queue was empty, nothing to send */
239 data_to_send.status_byte = 0;
240 data_to_send.buffer[0] = 0;
241 }
242
243 // Receive and/or transmit data
244 m_aci_spi_transfer(&data_to_send, &received_data);
245
246 /* If there are messages to transmit, and we can store the reply, we request a new transfer */
247 if (!aci_queue_is_full(&aci_rx_q) && !aci_queue_is_empty(&aci_tx_q))
248 {
249 m_aci_reqn_enable();
250 }
251
252 // Check if we received data
253 if (received_data.buffer[0] > 0)
254 {
255 if (!aci_queue_enqueue(&aci_rx_q, &received_data))
256 {
257 /* Receive Buffer full.
258 Should never happen.
259 Spin in a while loop.
260 */
261 syslog_0(LOG_ERROR, "m_aci_event_check Buffer full !");
262 while(1);
263 }
264 }
265
266 return;
267}
268
269/** @brief Point the low level library at the ACI pins specified
270 * @details
271 * The ACI pins are specified in the application and a pointer is made available for
272 * the low level library to use
273 */
274static void m_aci_pins_set(aci_pins_t *a_pins_ptr)
275{
276 a_pins_local_ptr = a_pins_ptr;
277}
278
279static inline void m_aci_reqn_disable (void)
280{
281 digitalWrite(a_pins_local_ptr->reqn_pin, 1);
282}
283
284static inline void m_aci_reqn_enable (void)
285{
286 digitalWrite(a_pins_local_ptr->reqn_pin, 0);
287}
288
289static void m_aci_q_flush(void)
290{
291 noInterrupts();
292 /* re-initialize aci cmd queue and aci event queue to flush them*/
293 aci_queue_init(&aci_tx_q);
294 aci_queue_init(&aci_rx_q);
295 interrupts();
296}
297
298static bool m_aci_spi_transfer(hal_aci_data_t * data_to_send, hal_aci_data_t * received_data)
299{
300 uint8_t byte_cnt;
301 uint8_t byte_sent_cnt;
302 uint8_t max_bytes;
303
304 m_aci_reqn_enable();
305
306 // Send length, receive header
307 byte_sent_cnt = 0;
308 received_data->status_byte = spi_readwrite(data_to_send->buffer[byte_sent_cnt++]);
309 // Send first byte, receive length from slave
310 received_data->buffer[0] = spi_readwrite(data_to_send->buffer[byte_sent_cnt++]);
311 if(received_data->buffer[0] == 0xff)
312 return false;
313 if (0 == data_to_send->buffer[0])
314 {
315 max_bytes = received_data->buffer[0];
316 }
317 else
318 {
319 // Set the maximum to the biggest size. One command byte is already sent
320 max_bytes = (received_data->buffer[0] > (data_to_send->buffer[0] - 1))
321 ? received_data->buffer[0]
322 : (data_to_send->buffer[0] - 1);
323 }
324
325 if (max_bytes > HAL_ACI_MAX_LENGTH)
326 {
327 max_bytes = HAL_ACI_MAX_LENGTH;
328 }
329
330 // Transmit/receive the rest of the packet
331 for (byte_cnt = 0; byte_cnt < max_bytes; byte_cnt++)
332 {
333 received_data->buffer[byte_cnt+1] = spi_readwrite(data_to_send->buffer[byte_sent_cnt++]);
334 }
335
336 // RDYN should follow the REQN line in approx 100ns
337 m_aci_reqn_disable();
338
339 return (max_bytes > 0);
340}
341
342void hal_aci_tl_debug_print(bool enable)
343{
344 aci_debug_print = enable;
345}
346
347void hal_aci_tl_pin_reset(void)
348{
349 if (UNUSED != a_pins_local_ptr->reset_pin)
350 {
351 pinMode(a_pins_local_ptr->reset_pin, OUTPUT);
352
353 if ((REDBEARLAB_SHIELD_V1_1 == a_pins_local_ptr->board_name) ||
354 (REDBEARLAB_SHIELD_V2012_07 == a_pins_local_ptr->board_name))
355 {
356 //The reset for the Redbearlab v1.1 and v2012.07 boards are inverted and has a Power On Reset
357 //circuit that takes about 100ms to trigger the reset
358 digitalWrite(a_pins_local_ptr->reset_pin, 1);
359 delay(100);
360 digitalWrite(a_pins_local_ptr->reset_pin, 0);
361 }
362 else
363 {
364 digitalWrite(a_pins_local_ptr->reset_pin, 1);
365 digitalWrite(a_pins_local_ptr->reset_pin, 0);
366 digitalWrite(a_pins_local_ptr->reset_pin, 1);
367 }
368 }
369}
370
371bool hal_aci_tl_event_peek(hal_aci_data_t *p_aci_data)
372{
373 if (!a_pins_local_ptr->interface_is_interrupt)
374 {
375 m_aci_event_check();
376 }
377
378 if (aci_queue_peek(&aci_rx_q, p_aci_data))
379 {
380 return true;
381 }
382
383 return false;
384}
385
386bool hal_aci_tl_event_get(hal_aci_data_t *p_aci_data)
387{
388 bool was_full;
389
390 if (!a_pins_local_ptr->interface_is_interrupt && !aci_queue_is_full(&aci_rx_q))
391 {
392 m_aci_event_check();
393 }
394
395 was_full = aci_queue_is_full(&aci_rx_q);
396
397 if (aci_queue_dequeue(&aci_rx_q, p_aci_data))
398 {
399 if (aci_debug_print)
400 {
401 syslog_1(LOG_NOTICE, "EVT %d:", p_aci_data->buffer[0]);
402 m_aci_data_print(p_aci_data);
403 }
404
405 /* Attempt to pull REQN LOW since we've made room for new messages */
406 if (!aci_queue_is_full(&aci_rx_q) && !aci_queue_is_empty(&aci_tx_q))
407 {
408 m_aci_reqn_enable();
409 }
410
411 return true;
412 }
413
414 (void)(was_full);
415 return false;
416}
417
418void hal_aci_tl_init(aci_pins_t *a_pins, bool debug)
419{
420 aci_debug_print = debug;
421
422 /* Needs to be called as the first thing for proper intialization*/
423 m_aci_pins_set(a_pins);
424
425 /*
426 The SPI lines used are mapped directly to the hardware SPI
427 MISO MOSI and SCK
428 Change here if the pins are mapped differently
429
430 The SPI library assumes that the hardware pins are used
431 */
432 hspi = a_pins->spihandle;
433 evt_taskid = a_pins->event_taskid;
434
435 /* Initialize the ACI Command queue. This must be called after the delay above. */
436 aci_queue_init(&aci_tx_q);
437 aci_queue_init(&aci_rx_q);
438
439 //Configure the IO lines
440 pinMode(a_pins->rdyn_pin, INPUT_PULLUP);
441 pinMode(a_pins->reqn_pin, OUTPUT);
442
443 if (UNUSED != a_pins->active_pin)
444 {
445 pinMode(a_pins->active_pin, INPUT);
446 }
447 /* Pin reset the nRF8001, required when the nRF8001 setup is being changed */
448 hal_aci_tl_pin_reset();
449
450 /* Set the nRF8001 to a known state as required by the datasheet*/
451 digitalWrite(a_pins->reqn_pin, 1);
452
453 dly_tsk(30); //Wait for the nRF8001 to get hold of its lines - the lines float for a few ms after the reset
454}
455
456bool hal_aci_tl_send(hal_aci_data_t *p_aci_cmd)
457{
458 const uint8_t length = p_aci_cmd->buffer[0];
459 bool ret_val = false;
460
461 if (length > HAL_ACI_MAX_LENGTH)
462 {
463 return false;
464 }
465
466 ret_val = aci_queue_enqueue(&aci_tx_q, p_aci_cmd);
467 if (ret_val)
468 {
469 if(!aci_queue_is_full(&aci_rx_q))
470 {
471 // Lower the REQN only when successfully enqueued
472 m_aci_reqn_enable();
473 }
474
475 if (aci_debug_print)
476 {
477 syslog_1(LOG_NOTICE, "CMD %d:", p_aci_cmd->buffer[0]);
478 m_aci_data_print(p_aci_cmd);
479 }
480 }
481
482 return ret_val;
483}
484
485static uint8_t spi_readwrite(const uint8_t aci_byte)
486{
487 //Board dependent defines
488 //For ChipKit the transmission has to be reversed
489 uint8_t tmp_bits;
490 tmp_bits = spi_transfer(REVERSE_BITS(aci_byte));
491#if 0 /* ROI DEBUG */
492 {
493 uint32_t tim;
494 get_tim(&tim);
495 syslog_5(LOG_NOTICE, "## spi_readwrite in1[%02x] in2[%02x] out1[%02x] out2[%02x] tim(%d) ##", aci_byte, REVERSE_BITS(aci_byte), tmp_bits, REVERSE_BITS(tmp_bits), tim);
496 }
497#endif /* ROI DEBUG */
498 return REVERSE_BITS(tmp_bits);
499}
500
501bool hal_aci_tl_rx_q_empty (void)
502{
503 return aci_queue_is_empty(&aci_rx_q);
504}
505
506bool hal_aci_tl_rx_q_full (void)
507{
508 return aci_queue_is_full(&aci_rx_q);
509}
510
511bool hal_aci_tl_tx_q_empty (void)
512{
513 return aci_queue_is_empty(&aci_tx_q);
514}
515
516bool hal_aci_tl_tx_q_full (void)
517{
518 return aci_queue_is_full(&aci_tx_q);
519}
520
521void hal_aci_tl_q_flush (void)
522{
523 m_aci_q_flush();
524}
525
Note: See TracBrowser for help on using the repository browser.