1765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang/* Copyright (c) 2014, Nordic Semiconductor ASA 2765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * 3765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * Permission is hereby granted, free of charge, to any person obtaining a copy 4765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * of this software and associated documentation files (the "Software"), to deal 5765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * in the Software without restriction, including without limitation the rights 6765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * copies of the Software, and to permit persons to whom the Software is 8765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * furnished to do so, subject to the following conditions: 9765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * 10765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * The above copyright notice and this permission notice shall be included in all 11765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * copies or substantial portions of the Software. 12765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * 13765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * SOFTWARE. 20765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang */ 21765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 22765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 23765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang#include "aci.h" 24765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang#include "hal_aci_tl.h" 25765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang#include <lib_aci.h> 26765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang#include "aci_setup.h" 27765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 28765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 29765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// aci_struct that will contain 30765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// total initial credits 31765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// current credit 32765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// current state of the aci (setup/standby/active/sleep) 33765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// open remote pipe pending 34765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// close remote pipe pending 35765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// Current pipe available bitmap 36765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// Current pipe closed bitmap 37765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// Current connection interval, slave latency and link supervision timeout 38765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// Current State of the the GATT client (Service Discovery status) 39765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 40765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 41765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang// hal_aci_data_t msg_to_send; 42765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangextern hal_aci_data_t msg_to_send; 43765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 44765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 45765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang/************************************************************************** */ 46765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang/* Utility function to fill the the ACI command queue */ 47765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang/* aci_stat Pointer to the ACI state */ 48765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang/* num_cmd_offset(in/out) Offset in the Setup message array to start from */ 49765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang/* offset is updated to the new index after the queue is filled */ 50765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang/* or the last message us placed in the queue */ 51765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang/* Returns true if at least one message was transferred */ 52765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang/***************************************************************************/ 53765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhangbool aci_setup_fill(aci_state_t *aci_stat, uint8_t *num_cmd_offset) 54765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{ 55765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang bool ret_val = false; 56765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 57765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang while (*num_cmd_offset < aci_stat->aci_setup_info.num_setup_msgs) 58765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 59765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang //Board dependent defines 60765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang /*#if defined (__AVR__) 61765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang //For Arduino copy the setup ACI message from Flash to RAM. 62765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang memcpy_P(&msg_to_send, &(aci_stat->aci_setup_info.setup_msgs[*num_cmd_offset]), 63765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang pgm_read_byte_near(&(aci_stat->aci_setup_info.setup_msgs[*num_cmd_offset].buffer[0]))+2); 64765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang #elif defined(__PIC32MX__) 65765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang //In ChipKit we store the setup messages in RAM 66765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang //Add 2 bytes to the length byte for status byte, length for the total number of bytes 67765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang memcpy(&msg_to_send, &(aci_stat->aci_setup_info.setup_msgs[*num_cmd_offset]), 68765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang (aci_stat->aci_setup_info.setup_msgs[*num_cmd_offset].buffer[0]+2)); 69765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang #endif*/ 70765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 71765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang memcpy(&msg_to_send, &(aci_stat->aci_setup_info.setup_msgs[*num_cmd_offset]), 72765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang (aci_stat->aci_setup_info.setup_msgs[*num_cmd_offset].buffer[0]+2)); 73765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 74765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang //Put the Setup ACI message in the command queue 75765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (!hal_aci_tl_send(&msg_to_send)) 76765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 77765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang //ACI Command Queue is full 78765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang // *num_cmd_offset is now pointing to the index of the Setup command that did not get sent 79765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return ret_val; 80765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 81765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 82765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang ret_val = true; 83765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 84765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang (*num_cmd_offset)++; 85765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 86765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 87765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return ret_val; 88765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang} 89765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 90765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhanguint8_t do_aci_setup(aci_state_t *aci_stat) 91765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang{ 92765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang uint8_t setup_offset = 0; 93765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang uint32_t i = 0x0000; 94765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang aci_evt_t * aci_evt = NULL; 95765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang aci_status_code_t cmd_status = ACI_STATUS_ERROR_CRC_MISMATCH; 96765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 97765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang /* 98765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang We are using the same buffer since we are copying the contents of the buffer 99765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang when queuing and immediately processing the buffer when receiving 100765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang */ 101765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang hal_aci_evt_t *aci_data = (hal_aci_evt_t *)&msg_to_send; 102765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 103765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang /* Messages in the outgoing queue must be handled before the Setup routine can run. 104765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * If it is non-empty we return. The user should then process the messages before calling 105765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * do_aci_setup() again. 106765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang */ 107765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (!lib_aci_command_queue_empty()) 108765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 109765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return SETUP_FAIL_COMMAND_QUEUE_NOT_EMPTY; 110765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 111765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 112765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang /* If there are events pending from the device that are not relevant to setup, we return false 113765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * so that the user can handle them. At this point we don't care what the event is, 114765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * as any event is an error. 115765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang */ 116765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (lib_aci_event_peek(aci_data)) 117765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 118765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return SETUP_FAIL_EVENT_QUEUE_NOT_EMPTY; 119765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 120765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 121765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang /* Fill the ACI command queue with as many Setup messages as it will hold. */ 122765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang aci_setup_fill(aci_stat, &setup_offset); 123765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 124765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang while (cmd_status != ACI_STATUS_TRANSACTION_COMPLETE) 125765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 126765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang /* This counter is used to ensure that this function does not loop forever. When the device 127765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * returns a valid response, we reset the counter. 128765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang */ 129765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (i++ > 0xFFFFE) 130765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 131765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return SETUP_FAIL_TIMEOUT; 132765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 133765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 134765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (lib_aci_event_peek(aci_data)) 135765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 136765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang aci_evt = &(aci_data->evt); 137765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 138765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang if (ACI_EVT_CMD_RSP != aci_evt->evt_opcode) 139765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 140765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang //Receiving something other than a Command Response Event is an error. 141765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return SETUP_FAIL_NOT_COMMAND_RESPONSE; 142765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 143765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 144765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang cmd_status = (aci_status_code_t) aci_evt->params.cmd_rsp.cmd_status; 145765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang switch (cmd_status) 146765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang { 147765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang case ACI_STATUS_TRANSACTION_CONTINUE: 148765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang //As the device is responding, reset guard counter 149765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang i = 0; 150765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 151765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang /* As the device has processed the Setup messages we put in the command queue earlier, 152765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * we can proceed to fill the queue with new messages 153765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang */ 154765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang aci_setup_fill(aci_stat, &setup_offset); 155765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang break; 156765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 157765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang case ACI_STATUS_TRANSACTION_COMPLETE: 158765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang //Break out of the while loop when this status code appears 159765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang break; 160765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 161765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang default: 162765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang //An event with any other status code should be handled by the application 163765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return SETUP_FAIL_NOT_SETUP_EVENT; 164765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 165765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 166765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang /* If we haven't returned at this point, the event was either ACI_STATUS_TRANSACTION_CONTINUE 167765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * or ACI_STATUS_TRANSACTION_COMPLETE. We don't need the event itself, so we simply 168765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang * remove it from the queue. 169765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang */ 170765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang lib_aci_event_get (aci_stat, aci_data); 171765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 172765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang } 173765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 174765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang return SETUP_SUCCESS; 175765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang} 176765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 177765adb95dc941c32690d6c43bc08b9d07d197fcbJianxun Zhang 178