1*75a994c4SMatthias Ringwald /* 2*75a994c4SMatthias Ringwald * Copyright (C) 2009-2012 by Matthias Ringwald 3*75a994c4SMatthias Ringwald * 4*75a994c4SMatthias Ringwald * Redistribution and use in source and binary forms, with or without 5*75a994c4SMatthias Ringwald * modification, are permitted provided that the following conditions 6*75a994c4SMatthias Ringwald * are met: 7*75a994c4SMatthias Ringwald * 8*75a994c4SMatthias Ringwald * 1. Redistributions of source code must retain the above copyright 9*75a994c4SMatthias Ringwald * notice, this list of conditions and the following disclaimer. 10*75a994c4SMatthias Ringwald * 2. Redistributions in binary form must reproduce the above copyright 11*75a994c4SMatthias Ringwald * notice, this list of conditions and the following disclaimer in the 12*75a994c4SMatthias Ringwald * documentation and/or other materials provided with the distribution. 13*75a994c4SMatthias Ringwald * 3. Neither the name of the copyright holders nor the names of 14*75a994c4SMatthias Ringwald * contributors may be used to endorse or promote products derived 15*75a994c4SMatthias Ringwald * from this software without specific prior written permission. 16*75a994c4SMatthias Ringwald * 17*75a994c4SMatthias Ringwald * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS 18*75a994c4SMatthias Ringwald * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 19*75a994c4SMatthias Ringwald * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS 20*75a994c4SMatthias Ringwald * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS 21*75a994c4SMatthias Ringwald * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 22*75a994c4SMatthias Ringwald * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 23*75a994c4SMatthias Ringwald * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS 24*75a994c4SMatthias Ringwald * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 25*75a994c4SMatthias Ringwald * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 26*75a994c4SMatthias Ringwald * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF 27*75a994c4SMatthias Ringwald * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 28*75a994c4SMatthias Ringwald * SUCH DAMAGE. 29*75a994c4SMatthias Ringwald * 30*75a994c4SMatthias Ringwald */ 31*75a994c4SMatthias Ringwald 32*75a994c4SMatthias Ringwald /* 33*75a994c4SMatthias Ringwald * ant_cmds.c 34*75a994c4SMatthias Ringwald * 35*75a994c4SMatthias Ringwald * See http://www.thisisant.com/ for more info on ANT(tm) 36*75a994c4SMatthias Ringwald * 37*75a994c4SMatthias Ringwald * Created by Matthias Ringwald on 2012-11-06. 38*75a994c4SMatthias Ringwald */ 39*75a994c4SMatthias Ringwald 40*75a994c4SMatthias Ringwald 41*75a994c4SMatthias Ringwald #include <string.h> 42*75a994c4SMatthias Ringwald 43*75a994c4SMatthias Ringwald #include "ant_cmds.h" 44*75a994c4SMatthias Ringwald #include "classic/sdp_util.h" 45*75a994c4SMatthias Ringwald #include "btstack-config.h" 46*75a994c4SMatthias Ringwald #include "hci.h" 47*75a994c4SMatthias Ringwald 48*75a994c4SMatthias Ringwald /** 49*75a994c4SMatthias Ringwald * construct ANT HCI Command based on template 50*75a994c4SMatthias Ringwald * 51*75a994c4SMatthias Ringwald * Format: 52*75a994c4SMatthias Ringwald * 0: adds a zero byte 53*75a994c4SMatthias Ringwald * 1,2,3,4: one to four byte value 54*75a994c4SMatthias Ringwald * D: pointer to 8 bytes of ANT data 55*75a994c4SMatthias Ringwald */ 56*75a994c4SMatthias Ringwald static uint16_t ant_cmd_create_from_template(uint8_t *hci_cmd_buffer, const ant_cmd_t *cmd, va_list argptr){ 57*75a994c4SMatthias Ringwald 58*75a994c4SMatthias Ringwald hci_cmd_buffer[0] = 0xd1; 59*75a994c4SMatthias Ringwald hci_cmd_buffer[1] = 0xfd; 60*75a994c4SMatthias Ringwald // hci packet lengh 2 61*75a994c4SMatthias Ringwald // ant packet length 3 62*75a994c4SMatthias Ringwald hci_cmd_buffer[4] = 0x00; 63*75a994c4SMatthias Ringwald hci_cmd_buffer[6] = cmd->message_id; 64*75a994c4SMatthias Ringwald int pos = 7; 65*75a994c4SMatthias Ringwald 66*75a994c4SMatthias Ringwald const char *format = cmd->format; 67*75a994c4SMatthias Ringwald uint16_t word; 68*75a994c4SMatthias Ringwald uint32_t longword; 69*75a994c4SMatthias Ringwald uint8_t * ptr; 70*75a994c4SMatthias Ringwald while (*format) { 71*75a994c4SMatthias Ringwald switch(*format) { 72*75a994c4SMatthias Ringwald case '0': // dummy 73*75a994c4SMatthias Ringwald hci_cmd_buffer[pos++] = 0; 74*75a994c4SMatthias Ringwald break; 75*75a994c4SMatthias Ringwald case '1': // 8 bit value 76*75a994c4SMatthias Ringwald case '2': // 16 bit value 77*75a994c4SMatthias Ringwald word = va_arg(argptr, int); // minimal va_arg is int: 2 bytes on 8+16 bit CPUs 78*75a994c4SMatthias Ringwald hci_cmd_buffer[pos++] = word & 0xff; 79*75a994c4SMatthias Ringwald if (*format == '2') { 80*75a994c4SMatthias Ringwald hci_cmd_buffer[pos++] = word >> 8; 81*75a994c4SMatthias Ringwald } else if (*format == 'H') { 82*75a994c4SMatthias Ringwald // TODO implement opaque client connection handles 83*75a994c4SMatthias Ringwald // pass module handle for now 84*75a994c4SMatthias Ringwald hci_cmd_buffer[pos++] = word >> 8; 85*75a994c4SMatthias Ringwald } 86*75a994c4SMatthias Ringwald break; 87*75a994c4SMatthias Ringwald case '3': 88*75a994c4SMatthias Ringwald case '4': 89*75a994c4SMatthias Ringwald longword = va_arg(argptr, uint32_t); 90*75a994c4SMatthias Ringwald // longword = va_arg(argptr, int); 91*75a994c4SMatthias Ringwald hci_cmd_buffer[pos++] = longword; 92*75a994c4SMatthias Ringwald hci_cmd_buffer[pos++] = longword >> 8; 93*75a994c4SMatthias Ringwald hci_cmd_buffer[pos++] = longword >> 16; 94*75a994c4SMatthias Ringwald if (*format == '4'){ 95*75a994c4SMatthias Ringwald hci_cmd_buffer[pos++] = longword >> 24; 96*75a994c4SMatthias Ringwald } 97*75a994c4SMatthias Ringwald break; 98*75a994c4SMatthias Ringwald case 'D': // 8 byte data block 99*75a994c4SMatthias Ringwald ptr = va_arg(argptr, uint8_t *); 100*75a994c4SMatthias Ringwald memcpy(&hci_cmd_buffer[pos], ptr, 8); 101*75a994c4SMatthias Ringwald pos += 8; 102*75a994c4SMatthias Ringwald break; 103*75a994c4SMatthias Ringwald 104*75a994c4SMatthias Ringwald default: 105*75a994c4SMatthias Ringwald break; 106*75a994c4SMatthias Ringwald } 107*75a994c4SMatthias Ringwald format++; 108*75a994c4SMatthias Ringwald }; 109*75a994c4SMatthias Ringwald 110*75a994c4SMatthias Ringwald hci_cmd_buffer[2] = pos - 3; 111*75a994c4SMatthias Ringwald hci_cmd_buffer[3] = pos - 5; 112*75a994c4SMatthias Ringwald hci_cmd_buffer[5] = pos - 7; 113*75a994c4SMatthias Ringwald return pos; 114*75a994c4SMatthias Ringwald } 115*75a994c4SMatthias Ringwald 116*75a994c4SMatthias Ringwald /** 117*75a994c4SMatthias Ringwald * construct ANT HCI Command based on template 118*75a994c4SMatthias Ringwald * 119*75a994c4SMatthias Ringwald * mainly calls ant_cmd_create_from_template 120*75a994c4SMatthias Ringwald */ 121*75a994c4SMatthias Ringwald uint16_t ant_create_cmd(uint8_t *hci_cmd_buffer, const ant_cmd_t *cmd, ...){ 122*75a994c4SMatthias Ringwald va_list argptr; 123*75a994c4SMatthias Ringwald va_start(argptr, cmd); 124*75a994c4SMatthias Ringwald uint16_t len = ant_cmd_create_from_template(hci_cmd_buffer, cmd, argptr); 125*75a994c4SMatthias Ringwald va_end(argptr); 126*75a994c4SMatthias Ringwald return len; 127*75a994c4SMatthias Ringwald } 128*75a994c4SMatthias Ringwald 129*75a994c4SMatthias Ringwald /** 130*75a994c4SMatthias Ringwald * pre: numcmds >= 0 - it's allowed to send a command to the controller 131*75a994c4SMatthias Ringwald */ 132*75a994c4SMatthias Ringwald uint8_t ant_packet_buffer[30]; 133*75a994c4SMatthias Ringwald int ant_send_cmd(const ant_cmd_t *cmd, ...){ 134*75a994c4SMatthias Ringwald va_list argptr; 135*75a994c4SMatthias Ringwald va_start(argptr, cmd); 136*75a994c4SMatthias Ringwald uint16_t size = ant_cmd_create_from_template(ant_packet_buffer, cmd, argptr); 137*75a994c4SMatthias Ringwald va_end(argptr); 138*75a994c4SMatthias Ringwald return hci_send_cmd_packet(ant_packet_buffer, size); 139*75a994c4SMatthias Ringwald } 140*75a994c4SMatthias Ringwald 141*75a994c4SMatthias Ringwald /** 142*75a994c4SMatthias Ringwald * ANT commands as found in http://www.thisisant.com/resources/ant-message-protocol-and-usage/ 143*75a994c4SMatthias Ringwald */ 144*75a994c4SMatthias Ringwald 145*75a994c4SMatthias Ringwald const ant_cmd_t ant_reset = { 146*75a994c4SMatthias Ringwald MESG_SYSTEM_RESET_ID, "0" 147*75a994c4SMatthias Ringwald }; 148*75a994c4SMatthias Ringwald 149*75a994c4SMatthias Ringwald const ant_cmd_t ant_assign_channel = { 150*75a994c4SMatthias Ringwald MESG_ASSIGN_CHANNEL_ID, "111" 151*75a994c4SMatthias Ringwald // channel number, channel type, network number 152*75a994c4SMatthias Ringwald }; 153*75a994c4SMatthias Ringwald 154*75a994c4SMatthias Ringwald const ant_cmd_t ant_un_assign_channel = { 155*75a994c4SMatthias Ringwald MESG_UNASSIGN_CHANNEL_ID, "1" 156*75a994c4SMatthias Ringwald // channel number 157*75a994c4SMatthias Ringwald }; 158*75a994c4SMatthias Ringwald 159*75a994c4SMatthias Ringwald const ant_cmd_t ant_search_timeout = { 160*75a994c4SMatthias Ringwald MESG_CHANNEL_SEARCH_TIMEOUT_ID, "11" 161*75a994c4SMatthias Ringwald // channel number, timeout 162*75a994c4SMatthias Ringwald }; 163*75a994c4SMatthias Ringwald 164*75a994c4SMatthias Ringwald const ant_cmd_t ant_lp_search_timeout = { 165*75a994c4SMatthias Ringwald MESG_SET_LP_SEARCH_TIMEOUT_ID, "11" 166*75a994c4SMatthias Ringwald // channel number, timeout 167*75a994c4SMatthias Ringwald }; 168*75a994c4SMatthias Ringwald 169*75a994c4SMatthias Ringwald const ant_cmd_t ant_network_key = { 170*75a994c4SMatthias Ringwald MESG_NETWORK_KEY_ID, "1D" 171*75a994c4SMatthias Ringwald // network number, pointer to 8 byte network key 172*75a994c4SMatthias Ringwald }; 173*75a994c4SMatthias Ringwald 174*75a994c4SMatthias Ringwald const ant_cmd_t ant_channel_id = { 175*75a994c4SMatthias Ringwald MESG_CHANNEL_ID_ID, "1211" 176*75a994c4SMatthias Ringwald // channel number, device number, device type, transmit type 177*75a994c4SMatthias Ringwald }; 178*75a994c4SMatthias Ringwald 179*75a994c4SMatthias Ringwald const ant_cmd_t ant_channel_power = { 180*75a994c4SMatthias Ringwald MESG_RADIO_TX_POWER_ID, "11" 181*75a994c4SMatthias Ringwald // channel number, power 182*75a994c4SMatthias Ringwald }; 183*75a994c4SMatthias Ringwald 184*75a994c4SMatthias Ringwald const ant_cmd_t ant_channel_period = { 185*75a994c4SMatthias Ringwald MESG_CHANNEL_MESG_PERIOD_ID, "12" 186*75a994c4SMatthias Ringwald // channel number, period 187*75a994c4SMatthias Ringwald }; 188*75a994c4SMatthias Ringwald 189*75a994c4SMatthias Ringwald const ant_cmd_t ant_prox_search_config = { 190*75a994c4SMatthias Ringwald MESG_PROX_SEARCH_CONFIG_ID, "11" 191*75a994c4SMatthias Ringwald // channel number, prox level 192*75a994c4SMatthias Ringwald }; 193*75a994c4SMatthias Ringwald 194*75a994c4SMatthias Ringwald const ant_cmd_t ant_broadcast = { 195*75a994c4SMatthias Ringwald MESG_BROADCAST_DATA_ID, "1D" 196*75a994c4SMatthias Ringwald // channel number, pointer to 8 byte data 197*75a994c4SMatthias Ringwald }; 198*75a994c4SMatthias Ringwald 199*75a994c4SMatthias Ringwald const ant_cmd_t ant_acknowledged = { 200*75a994c4SMatthias Ringwald MESG_ACKNOWLEDGED_DATA_ID, "1D" 201*75a994c4SMatthias Ringwald // channel number, pointer to 8 byte data 202*75a994c4SMatthias Ringwald }; 203*75a994c4SMatthias Ringwald 204*75a994c4SMatthias Ringwald const ant_cmd_t ant_burst_packet = { 205*75a994c4SMatthias Ringwald MESG_BURST_DATA_ID, "1D" 206*75a994c4SMatthias Ringwald // channel number, pointer to 8 byte data 207*75a994c4SMatthias Ringwald }; 208*75a994c4SMatthias Ringwald 209*75a994c4SMatthias Ringwald const ant_cmd_t ant_open_channel = { 210*75a994c4SMatthias Ringwald MESG_OPEN_CHANNEL_ID, "1" 211*75a994c4SMatthias Ringwald // channel number 212*75a994c4SMatthias Ringwald }; 213*75a994c4SMatthias Ringwald 214*75a994c4SMatthias Ringwald const ant_cmd_t ant_close_channel = { 215*75a994c4SMatthias Ringwald MESG_CLOSE_CHANNEL_ID, "1" 216*75a994c4SMatthias Ringwald // channel number 217*75a994c4SMatthias Ringwald }; 218*75a994c4SMatthias Ringwald 219*75a994c4SMatthias Ringwald const ant_cmd_t ant_request_message = { 220*75a994c4SMatthias Ringwald MESG_REQUEST_ID, "11" 221*75a994c4SMatthias Ringwald // channel number, requested message 222*75a994c4SMatthias Ringwald }; 223