Home | History | Annotate | Download | only in brfpatch
      1 /*
      2 ** Copyright 2007, The Android Open Source Project
      3 **
      4 ** Licensed under the Apache License, Version 2.0 (the "License");
      5 ** you may not use this file except in compliance with the License.
      6 ** You may obtain a copy of the License at
      7 **
      8 **     http://www.apache.org/licenses/LICENSE-2.0
      9 **
     10 ** Unless required by applicable law or agreed to in writing, software
     11 ** distributed under the License is distributed on an "AS IS" BASIS,
     12 ** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13 ** See the License for the specific language governing permissions and
     14 ** limitations under the License.
     15 */
     16 
     17 #include <stdio.h>
     18 #include <unistd.h>
     19 #include <stdlib.h>
     20 #include <string.h>
     21 #include <errno.h>
     22 #include <ctype.h>
     23 
     24 #define FAILIF(x, args...) do {          \
     25     if (x) {                             \
     26         fprintf(stderr, ##args);         \
     27         exit(1);                         \
     28     }                                    \
     29 } while(0)
     30 
     31 static void usage() {
     32     printf("Usage: brfpatch INPUT OUTPUT\n"
     33            "\n"
     34            "\tGenerates bluetooth firmware\n"
     35            "\n"
     36            "INPUT: Bluetooth script in ASCII format.\n"
     37            "       For TI BRF chips this can be generated from .bts files using the TI Bluetooth\n"
     38            "       script pad to save as .txt. This txt file can be used as input.\n"
     39            "       Alternately, run strings on the .bts and manually edit to change decimal\n"
     40            "       arguments into hex of the appropriate number of octets.\n"
     41            "       FORMAT: Send_HCI_xxxx OPCODE DATA1 DATA2 DATA3 ...\n"
     42            "       where OPCODE, DATA1 etc are one of:\n"
     43            "       0x12          (1 byte)\n"
     44            "       0x1234        (2 byte)\n"
     45            "       0x12345678    (4 byte)\n"
     46            "       \"0123456789ABCDEF0123\"            (multibyte)\n"
     47            "       \"01:23:45:67:89:AB:CD:EF:01:23\"   (multibyte)\n"
     48            "\n"
     49            "OUTPUT: Binary firmware\n"
     50            "        FORMAT: 0x01 OPCODE DATA_LEN DATA\n");
     51     exit(1);
     52 }
     53 
     54 static void dump_record(FILE *fpo, unsigned short opcode, unsigned char len,
     55                         unsigned char *data) {
     56 
     57     unsigned char prefix = 0x01;  // H4 UART command packet
     58     fwrite(&prefix, 1, 1, fpo);
     59     fwrite(&opcode, 2, 1, fpo);  // opcode
     60     fwrite(&len, 1, 1, fpo);     // data length
     61     fwrite(data, len, 1, fpo);   // data
     62 }
     63 
     64 // advance beyond next whitespace. Return -1 if end of string reached
     65 static int advance(char **buf) {
     66     char *b = *buf;
     67     while (*b && !isspace(*b))
     68         b++;
     69     while (*b && isspace(*b))
     70         b++;
     71     *buf = b;
     72     if (!(*b))
     73         return -1;
     74     return 0;
     75 }
     76 
     77 static void process_line(FILE *file_out, char *buf, char *buffer) {
     78     FAILIF(strncmp(buf, "Send_", 5) != 0, "Not expecting: %s\n", buffer);
     79 
     80 
     81     unsigned int opcode;
     82 
     83     FAILIF(advance(&buf), "Could not find opcode in: %s\n", buffer);
     84     FAILIF(sscanf(buf, "0x%04x\n", &opcode) != 1,
     85            "Could not find opcode in: %s\n", buffer);
     86 
     87 
     88     unsigned char data[1024];
     89     unsigned char *dp = data;
     90 
     91     while (!advance(&buf)) {
     92         switch (*buf) {
     93         case '"':
     94             buf++;
     95             while (*buf != '"' && *buf != 0) {
     96                 FAILIF(dp > data + sizeof(data),
     97                        "Too much data: %s\n", buffer);
     98                 FAILIF(sscanf(buf, "%02x", (unsigned int *)dp) != 1,
     99                        "Error parsing (%d): %s\n", __LINE__, buffer);
    100                 dp++;
    101                 buf += 2;
    102                 if (*buf == ':')
    103                     buf++;
    104             }
    105             break;
    106         case '0':
    107             buf++;
    108             FAILIF(*buf != 'x', "Error parsing: %s\n", buffer);
    109             buf++;
    110 
    111             // find length of this piece of data
    112             char *end = buf;
    113             while (isalnum(*end))
    114                 end++;
    115 
    116             // switch on length
    117             switch ((unsigned int)end - (unsigned int)buf) {
    118             case 2:
    119                 FAILIF(sscanf(buf, "%02x", (unsigned int *)dp) != 1,
    120                        "Error parsing (%d): %s\n", __LINE__, buffer);
    121                 buf += 2;
    122                 dp += 1;
    123                 break;
    124             case 4:
    125                 FAILIF(sscanf(buf, "%04x", (unsigned int *)dp) != 1,
    126                        "Error parsing (%d): %s\n", __LINE__, buffer);
    127                 buf += 4;
    128                 dp += 2;
    129                 break;
    130             case 6:
    131                 FAILIF(sscanf(buf, "%06x", (unsigned int *)dp) != 1,
    132                        "Error parsing (%d): %s\n", __LINE__, buffer);
    133                 buf += 6;
    134                 dp += 3;
    135                 break;
    136             case 8:
    137                 FAILIF(sscanf(buf, "%08x", (unsigned int *)dp) != 1,
    138                        "Error parsing (%d): %s\n", __LINE__, buffer);
    139                 buf += 8;
    140                 dp += 4;
    141                 break;
    142             case 16:
    143                 dp += 4;
    144                 FAILIF(sscanf(buf, "%08x", (unsigned int *)dp) != 1,
    145                        "Error parsing (%d): %s\n", __LINE__, buffer);
    146                 buf += 8;
    147                 dp -= 4;
    148                 FAILIF(sscanf(buf, "%08x", (unsigned int *)dp) != 1,
    149                        "Error parsing (%d): %s\n", __LINE__, buffer);
    150                 buf += 8;
    151                 dp += 8;
    152                 break;
    153             default:
    154                 FAILIF(1, "Error parsing (%d): %s\n", __LINE__, buffer);
    155             }
    156             break;
    157         default:
    158             FAILIF(1, "Error parsing (%d): %s\n", __LINE__, buffer);
    159         }
    160     }
    161 
    162     dump_record(file_out, opcode, dp - data, data);
    163 }
    164 
    165 
    166 int main(int argc, char **argv) {
    167 
    168     if (argc != 3)
    169         usage();
    170 
    171     FILE *file_in = fopen(argv[1], "r");
    172     FAILIF(!file_in, "Could not open %s: %s\n", argv[1], strerror(errno));
    173 
    174     FILE *file_out = fopen(argv[2], "w+");
    175     FAILIF(!file_out, "Could not open %s: %s\n", argv[2], strerror(errno));
    176 
    177     char buffer[1024];
    178     char *buf;
    179 
    180     while (fgets(buffer, 1024, file_in) != NULL) {
    181         buf = buffer;
    182         while (*buf && isspace(*buf))
    183             buf++;
    184         switch (*buf) {
    185         case 'S':
    186             process_line(file_out, buf, buffer);
    187             break;
    188         case 'W':  // Wait_HCI_Command... meta-data, not needed
    189         case '#':
    190         case 0:
    191             continue;
    192         default:
    193             FAILIF(1, "Don't know what to do with: %s\n", buffer);
    194         }
    195     }
    196 
    197     fclose(file_in);
    198     fclose(file_out);
    199 
    200     return 0;
    201 }
    202