Home | History | Annotate | Download | only in c++
      1 /*
      2  * Author: Yevgeniy Kiveisha <yevgeniy.kiveisha (at) intel.com>
      3  * Copyright (c) 2014 Intel Corporation.
      4  *
      5  * Permission is hereby granted, free of charge, to any person obtaining
      6  * a copy of this software and associated documentation files (the
      7  * "Software"), to deal in the Software without restriction, including
      8  * without limitation the rights to use, copy, modify, merge, publish,
      9  * distribute, sublicense, and/or sell copies of the Software, and to
     10  * permit persons to whom the Software is furnished to do so, subject to
     11  * the following conditions:
     12  *
     13  * The above copyright notice and this permission notice shall be
     14  * included in all copies or substantial portions of the Software.
     15  *
     16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
     17  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
     18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
     19  * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
     20  * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
     21  * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
     22  * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
     23  */
     24 
     25 #include <unistd.h>
     26 #include <iostream>
     27 #include "nrf8001.h"
     28 #include "nrf8001-helloworld.h"
     29 #include <lib_aci.h>
     30 #include <aci_setup.h>
     31 #include <signal.h>
     32 #include "uart_over_ble.h"
     33 
     34 /*
     35  * You can use the nRF UART app in the Apple iOS app store and Google Play for Android 4.3 for Samsung Galaxy S4
     36  * with this helloworld application
     37  */
     38 
     39 #ifdef SERVICES_PIPE_TYPE_MAPPING_CONTENT
     40     static services_pipe_type_mapping_t
     41         services_pipe_type_mapping[NUMBER_OF_PIPES] = SERVICES_PIPE_TYPE_MAPPING_CONTENT;
     42 #else
     43     #define NUMBER_OF_PIPES 0
     44     static services_pipe_type_mapping_t * services_pipe_type_mapping = NULL;
     45 #endif
     46 
     47 /**
     48  * Store the setup for the nRF8001 in the flash of the AVR to save on RAM
     49  */
     50 static hal_aci_data_t setup_msgs[NB_SETUP_MESSAGES] = SETUP_MESSAGES_CONTENT;
     51 
     52 /**
     53  * aci_struct that will contain
     54  * total initial credits
     55  * current credit
     56  * current state of the aci (setup/standby/active/sleep)
     57  * open remote pipe pending
     58  * close remote pipe pending
     59  * Current pipe available bitmap
     60  * Current pipe closed bitmap
     61  * Current connection interval, slave latency and link supervision timeout
     62  * Current State of the the GATT client (Service Discovery)
     63  * Status of the bond (R) Peer address
     64  */
     65 static struct aci_state_t aci_state;
     66 
     67 /**
     68  * Temporary buffers for sending ACI commands
     69  */
     70 static hal_aci_evt_t  aci_data;
     71 
     72 /*
     73 Timing change state variable
     74 */
     75 static bool timing_change_done          = false;
     76 
     77 /*
     78 Used to test the UART TX characteristic notification
     79 */
     80 static uart_over_ble_t uart_over_ble;
     81 static uint8_t         uart_buffer[20];
     82 static uint8_t         uart_buffer_len = 0;
     83 static uint8_t         dummychar = 0;
     84 
     85 void
     86 sig_handler(int signo)
     87 {
     88     printf("got signal\n");
     89     if (signo == SIGINT) {
     90         printf("exiting application\n");
     91     }
     92 }
     93 
     94 void
     95 init_aci_setup () {
     96     /**
     97      * Point ACI data structures to the the setup data that the nRFgo studio generated for the nRF8001
     98      */
     99     if (NULL != services_pipe_type_mapping) {
    100         aci_state.aci_setup_info.services_pipe_type_mapping = &services_pipe_type_mapping[0];
    101     } else {
    102         aci_state.aci_setup_info.services_pipe_type_mapping = NULL;
    103     }
    104 
    105     aci_state.aci_setup_info.number_of_pipes    = NUMBER_OF_PIPES;
    106     aci_state.aci_setup_info.setup_msgs         = setup_msgs;
    107     aci_state.aci_setup_info.num_setup_msgs     = NB_SETUP_MESSAGES;
    108 }
    109 
    110 void
    111 uart_over_ble_init (void) {
    112     uart_over_ble.uart_rts_local = true;
    113 }
    114 
    115 bool
    116 uart_tx (uint8_t *buffer, uint8_t buffer_len) {
    117     bool status = false;
    118 
    119     if  (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX) &&
    120         (aci_state.data_credit_available >= 1)) {
    121         status = lib_aci_send_data(PIPE_UART_OVER_BTLE_UART_TX_TX, buffer, buffer_len);
    122         if (status) {
    123             aci_state.data_credit_available--;
    124         }
    125     }
    126 
    127     return status;
    128 }
    129 
    130 bool
    131 uart_process_control_point_rx(uint8_t *byte, uint8_t length) {
    132     bool status = false;
    133     aci_ll_conn_params_t *conn_params;
    134 
    135     if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_CONTROL_POINT_TX) ) {
    136         switch (*byte) {
    137             /*
    138             Queues a ACI Disconnect to the nRF8001 when this packet is received.
    139             May cause some of the UART packets being sent to be dropped
    140             */
    141             case UART_OVER_BLE_DISCONNECT:
    142                 /*
    143                 Parameters:
    144                 None
    145                 */
    146                 lib_aci_disconnect(&aci_state, ACI_REASON_TERMINATE);
    147                 status = true;
    148                 break;
    149 
    150             /*
    151             Queues an ACI Change Timing to the nRF8001
    152             */
    153             case UART_OVER_BLE_LINK_TIMING_REQ:
    154                 /*
    155                 Parameters:
    156                 Connection interval min: 2 bytes
    157                 Connection interval max: 2 bytes
    158                 Slave latency:           2 bytes
    159                 Timeout:                 2 bytes
    160                 Same format as Peripheral Preferred Connection Parameters (See nRFgo studio -> nRF8001 Configuration -> GAP Settings
    161                 Refer to the ACI Change Timing Request in the nRF8001 Product Specifications
    162                 */
    163                 conn_params = (aci_ll_conn_params_t *)(byte+1);
    164                 lib_aci_change_timing( conn_params->min_conn_interval,
    165                                         conn_params->max_conn_interval,
    166                                         conn_params->slave_latency,
    167                                         conn_params->timeout_mult);
    168                 status = true;
    169                 break;
    170 
    171             /*
    172             Clears the RTS of the UART over BLE
    173             */
    174             case UART_OVER_BLE_TRANSMIT_STOP:
    175                 /*
    176                 Parameters:
    177                 None
    178                 */
    179                 uart_over_ble.uart_rts_local = false;
    180                 status = true;
    181                 break;
    182 
    183 
    184             /*
    185             Set the RTS of the UART over BLE
    186             */
    187             case UART_OVER_BLE_TRANSMIT_OK:
    188                 /*
    189                 Parameters:
    190                 None
    191                 */
    192                 uart_over_ble.uart_rts_local = true;
    193                 status = true;
    194                 break;
    195         }
    196     }
    197 
    198     return status;
    199 }
    200 
    201 int
    202 main(int argc, char **argv)
    203 {
    204     //! [Interesting]
    205 
    206     init_aci_setup ();
    207     init_local_interfaces (&aci_state, 10, 8, 4);
    208 
    209     while (1) {
    210         static bool setup_required = false;
    211 
    212         // We enter the if statement only when there is a ACI event available to be processed
    213         if (lib_aci_event_get(&aci_state, &aci_data)) {
    214             aci_evt_t * aci_evt;
    215             aci_evt = &aci_data.evt;
    216             switch(aci_evt->evt_opcode) {
    217                 /**
    218                 As soon as you reset the nRF8001 you will get an ACI Device Started Event
    219                 */
    220                 case ACI_EVT_DEVICE_STARTED: {
    221                     aci_state.data_credit_total = aci_evt->params.device_started.credit_available;
    222                     switch(aci_evt->params.device_started.device_mode) {
    223                         case ACI_DEVICE_SETUP:
    224                             /**
    225                             When the device is in the setup mode
    226                             */
    227                             printf ("Evt Device Started: Setup \n");
    228                             setup_required = true;
    229                             break;
    230 
    231                         case ACI_DEVICE_STANDBY:
    232                             printf ("Evt Device Started: Standby \n");
    233                             // Looking for an iPhone by sending radio advertisements
    234                             // When an iPhone connects to us we will get an ACI_EVT_CONNECTED event from the nRF8001
    235                             if (aci_evt->params.device_started.hw_error) {
    236                                 usleep (20000); //Handle the HW error event correctly.
    237                             } else {
    238                                 lib_aci_connect(0/* in seconds : 0 means forever */, 0x0050 /* advertising interval 50ms*/);
    239                                 printf ("Advertising started \n");
    240                             }
    241                             break;
    242                     }
    243                 }
    244                 break; // ACI Device Started Event
    245 
    246                 case ACI_EVT_CMD_RSP:
    247                     //If an ACI command response event comes with an error -> stop
    248                     if (ACI_STATUS_SUCCESS != aci_evt->params.cmd_rsp.cmd_status) {
    249                         //ACI ReadDynamicData and ACI WriteDynamicData will have status codes of
    250                         //TRANSACTION_CONTINUE and TRANSACTION_COMPLETE
    251                         //all other ACI commands will have status code of ACI_STATUS_SCUCCESS for a successful command
    252                         printf ("ACI_EVT_CMD_RSP \n");
    253                     }
    254                     if (ACI_CMD_GET_DEVICE_VERSION == aci_evt->params.cmd_rsp.cmd_opcode) {
    255                         //Store the version and configuration information of the nRF8001 in the Hardware Revision String Characteristic
    256                         lib_aci_set_local_data(&aci_state, PIPE_DEVICE_INFORMATION_HARDWARE_REVISION_STRING_SET,
    257                         (uint8_t *)&(aci_evt->params.cmd_rsp.params.get_device_version), sizeof(aci_evt_cmd_rsp_params_get_device_version_t));
    258                     }
    259                     break;
    260 
    261                 case ACI_EVT_CONNECTED:
    262                     printf ("ACI_EVT_CONNECTED");
    263                     uart_over_ble_init ();
    264                     timing_change_done = false;
    265                     aci_state.data_credit_available = aci_state.data_credit_total;
    266 
    267                     /*
    268                     Get the device version of the nRF8001 and store it in the Hardware Revision String
    269                     */
    270                     lib_aci_device_version();
    271                     break;
    272 
    273                 case ACI_EVT_PIPE_STATUS:
    274                     printf ("ACI_EVT_PIPE_STATUS \n");
    275                     if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX) && (false == timing_change_done)) {
    276                         lib_aci_change_timing_GAP_PPCP();   // change the timing on the link as specified in the nRFgo studio -> nRF8001 conf. -> GAP.
    277                                                             // Used to increase or decrease bandwidth
    278                         timing_change_done = true;
    279 
    280                         char hello[]="Hello World, works";
    281                         uart_tx((uint8_t *)&hello[0], strlen(hello));
    282                     }
    283                     break;
    284 
    285                 case ACI_EVT_TIMING:
    286                     printf ("Evt link connection interval changed \n");
    287                     lib_aci_set_local_data(&aci_state,
    288                                 PIPE_UART_OVER_BTLE_UART_LINK_TIMING_CURRENT_SET,
    289                                 (uint8_t *)&(aci_evt->params.timing.conn_rf_interval), /* Byte aligned */
    290                                 PIPE_UART_OVER_BTLE_UART_LINK_TIMING_CURRENT_SET_MAX_SIZE);
    291                     break;
    292 
    293                 case ACI_EVT_DISCONNECTED:
    294                     printf ("ACI_EVT_DISCONNECTED \n");
    295                     lib_aci_connect(0/* in seconds  : 0 means forever */, 0x0050 /* advertising interval 50ms*/);
    296                     printf ("Advertising started \n");
    297                     break;
    298 
    299                 case ACI_EVT_DATA_RECEIVED:
    300                     if (PIPE_UART_OVER_BTLE_UART_RX_RX == aci_evt->params.data_received.rx_data.pipe_number) {
    301                         for(int i=0; i<aci_evt->len - 2; i++) {
    302                           uart_buffer[i] = aci_evt->params.data_received.rx_data.aci_data[i];
    303                         }
    304 
    305                         uart_buffer_len = aci_evt->len - 2;
    306                         if (lib_aci_is_pipe_available(&aci_state, PIPE_UART_OVER_BTLE_UART_TX_TX)) {
    307                         }
    308                     }
    309 
    310                     if (PIPE_UART_OVER_BTLE_UART_CONTROL_POINT_RX == aci_evt->params.data_received.rx_data.pipe_number) {
    311                         //Subtract for Opcode and Pipe number
    312                         uart_process_control_point_rx(&aci_evt->params.data_received.rx_data.aci_data[0], aci_evt->len - 2);
    313                     }
    314 
    315                     printf ("Incomming data - %s\n", uart_buffer);
    316                     break;
    317 
    318                 case ACI_EVT_DATA_CREDIT:
    319                     printf ("ACI_EVT_DATA_CREDIT \n");
    320                     aci_state.data_credit_available = aci_state.data_credit_available + aci_evt->params.data_credit.credit;
    321                     break;
    322 
    323                 case ACI_EVT_PIPE_ERROR:
    324                     printf ("ACI_EVT_PIPE_ERROR \n");
    325                     //Increment the credit available as the data packet was not sent.
    326                     //The pipe error also represents the Attribute protocol Error Response sent from the peer and that should not be counted
    327                     //for the credit.
    328                     if (ACI_STATUS_ERROR_PEER_ATT_ERROR != aci_evt->params.pipe_error.error_code) {
    329                         aci_state.data_credit_available++;
    330                     }
    331                     break;
    332 
    333                 case ACI_EVT_HW_ERROR:
    334                     printf ("ACI_EVT_HW_ERROR \n");
    335                     lib_aci_connect(0/* in seconds, 0 means forever */, 0x0050 /* advertising interval 50ms*/);
    336                     printf ("Advertising started \n");
    337                 break;
    338 
    339             }
    340         }
    341 
    342         /* setup_required is set to true when the device starts up and enters setup mode.
    343         * It indicates that do_aci_setup() should be called. The flag should be cleared if
    344         * do_aci_setup() returns ACI_STATUS_TRANSACTION_COMPLETE.
    345         */
    346         if(setup_required) {
    347             if (SETUP_SUCCESS == do_aci_setup(&aci_state)) {
    348                 setup_required = false;
    349             }
    350         }
    351 
    352         usleep (100);
    353     }
    354 
    355     close_local_interfaces (&aci_state);
    356 
    357     //! [Interesting]
    358 
    359     std::cout << "exiting application" << std::endl;
    360 
    361     return 0;
    362 }
    363