17342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project/*
27342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project** Copyright 2007, The Android Open Source Project
37342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project**
47342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project** Licensed under the Apache License, Version 2.0 (the "License");
57342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project** you may not use this file except in compliance with the License.
67342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project** You may obtain a copy of the License at
77342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project**
87342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project**     http://www.apache.org/licenses/LICENSE-2.0
97342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project**
107342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project** Unless required by applicable law or agreed to in writing, software
117342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project** distributed under the License is distributed on an "AS IS" BASIS,
127342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project** WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
137342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project** See the License for the specific language governing permissions and
147342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project** limitations under the License.
157342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project*/
167342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
177342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project#include <stdio.h>
187342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project#include <unistd.h>
197342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project#include <stdlib.h>
207342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project#include <string.h>
217342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project#include <errno.h>
227342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project#include <ctype.h>
237342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
247342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project#define FAILIF(x, args...) do {          \
257342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    if (x) {                             \
267342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project        fprintf(stderr, ##args);         \
277342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project        exit(1);                         \
287342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    }                                    \
297342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project} while(0)
307342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
317342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Projectstatic void usage() {
327342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    printf("Usage: brfpatch INPUT OUTPUT\n"
337342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project           "\n"
347342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project           "\tGenerates bluetooth firmware\n"
357342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project           "\n"
367342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project           "INPUT: Bluetooth script in ASCII format.\n"
377342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project           "       For TI BRF chips this can be generated from .bts files using the TI Bluetooth\n"
387342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project           "       script pad to save as .txt. This txt file can be used as input.\n"
397342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project           "       Alternately, run strings on the .bts and manually edit to change decimal\n"
407342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project           "       arguments into hex of the appropriate number of octets.\n"
417342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project           "       FORMAT: Send_HCI_xxxx OPCODE DATA1 DATA2 DATA3 ...\n"
427342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project           "       where OPCODE, DATA1 etc are one of:\n"
437342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project           "       0x12          (1 byte)\n"
447342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project           "       0x1234        (2 byte)\n"
457342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project           "       0x12345678    (4 byte)\n"
467342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project           "       \"0123456789ABCDEF0123\"            (multibyte)\n"
477342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project           "       \"01:23:45:67:89:AB:CD:EF:01:23\"   (multibyte)\n"
487342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project           "\n"
497342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project           "OUTPUT: Binary firmware\n"
507342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project           "        FORMAT: 0x01 OPCODE DATA_LEN DATA\n");
517342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    exit(1);
527342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project}
537342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
547342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Projectstatic void dump_record(FILE *fpo, unsigned short opcode, unsigned char len,
557342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                        unsigned char *data) {
567342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
577342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    unsigned char prefix = 0x01;  // H4 UART command packet
587342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    fwrite(&prefix, 1, 1, fpo);
597342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    fwrite(&opcode, 2, 1, fpo);  // opcode
607342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    fwrite(&len, 1, 1, fpo);     // data length
617342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    fwrite(data, len, 1, fpo);   // data
627342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project}
637342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
647342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project// advance beyond next whitespace. Return -1 if end of string reached
657342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Projectstatic int advance(char **buf) {
667342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    char *b = *buf;
677342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    while (*b && !isspace(*b))
687342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project        b++;
697342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    while (*b && isspace(*b))
707342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project        b++;
717342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    *buf = b;
727342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    if (!(*b))
737342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project        return -1;
747342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    return 0;
757342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project}
767342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
777342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Projectstatic void process_line(FILE *file_out, char *buf, char *buffer) {
787342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    FAILIF(strncmp(buf, "Send_", 5) != 0, "Not expecting: %s\n", buffer);
797342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
807342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
817342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    unsigned int opcode;
827342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
837342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    FAILIF(advance(&buf), "Could not find opcode in: %s\n", buffer);
847342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    FAILIF(sscanf(buf, "0x%04x\n", &opcode) != 1,
857342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project           "Could not find opcode in: %s\n", buffer);
867342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
877342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
887342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    unsigned char data[1024];
897342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    unsigned char *dp = data;
907342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
917342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    while (!advance(&buf)) {
927342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project        switch (*buf) {
937342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project        case '"':
947342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            buf++;
957342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            while (*buf != '"' && *buf != 0) {
967342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                FAILIF(dp > data + sizeof(data),
977342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                       "Too much data: %s\n", buffer);
987342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                FAILIF(sscanf(buf, "%02x", (unsigned int *)dp) != 1,
997342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                       "Error parsing (%d): %s\n", __LINE__, buffer);
1007342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                dp++;
1017342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                buf += 2;
1027342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                if (*buf == ':')
1037342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                    buf++;
1047342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            }
1057342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            break;
1067342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project        case '0':
1077342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            buf++;
1087342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            FAILIF(*buf != 'x', "Error parsing: %s\n", buffer);
1097342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            buf++;
1107342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
1117342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            // find length of this piece of data
1127342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            char *end = buf;
1137342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            while (isalnum(*end))
1147342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                end++;
1157342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
1167342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            // switch on length
1177342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            switch ((unsigned int)end - (unsigned int)buf) {
1187342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            case 2:
1197342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                FAILIF(sscanf(buf, "%02x", (unsigned int *)dp) != 1,
1207342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                       "Error parsing (%d): %s\n", __LINE__, buffer);
1217342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                buf += 2;
1227342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                dp += 1;
1237342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                break;
1247342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            case 4:
1257342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                FAILIF(sscanf(buf, "%04x", (unsigned int *)dp) != 1,
1267342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                       "Error parsing (%d): %s\n", __LINE__, buffer);
1277342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                buf += 4;
1287342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                dp += 2;
1297342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                break;
13030a738e653aa2d9f7670d0b19409ce30916cc397Nick Pelly            case 6:
13130a738e653aa2d9f7670d0b19409ce30916cc397Nick Pelly                FAILIF(sscanf(buf, "%06x", (unsigned int *)dp) != 1,
13230a738e653aa2d9f7670d0b19409ce30916cc397Nick Pelly                       "Error parsing (%d): %s\n", __LINE__, buffer);
13330a738e653aa2d9f7670d0b19409ce30916cc397Nick Pelly                buf += 6;
13430a738e653aa2d9f7670d0b19409ce30916cc397Nick Pelly                dp += 3;
13530a738e653aa2d9f7670d0b19409ce30916cc397Nick Pelly                break;
1367342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            case 8:
1377342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                FAILIF(sscanf(buf, "%08x", (unsigned int *)dp) != 1,
1387342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                       "Error parsing (%d): %s\n", __LINE__, buffer);
1397342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                buf += 8;
1407342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                dp += 4;
1417342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                break;
14230a738e653aa2d9f7670d0b19409ce30916cc397Nick Pelly            case 16:
14330a738e653aa2d9f7670d0b19409ce30916cc397Nick Pelly                dp += 4;
14430a738e653aa2d9f7670d0b19409ce30916cc397Nick Pelly                FAILIF(sscanf(buf, "%08x", (unsigned int *)dp) != 1,
14530a738e653aa2d9f7670d0b19409ce30916cc397Nick Pelly                       "Error parsing (%d): %s\n", __LINE__, buffer);
14630a738e653aa2d9f7670d0b19409ce30916cc397Nick Pelly                buf += 8;
14730a738e653aa2d9f7670d0b19409ce30916cc397Nick Pelly                dp -= 4;
14830a738e653aa2d9f7670d0b19409ce30916cc397Nick Pelly                FAILIF(sscanf(buf, "%08x", (unsigned int *)dp) != 1,
14930a738e653aa2d9f7670d0b19409ce30916cc397Nick Pelly                       "Error parsing (%d): %s\n", __LINE__, buffer);
15030a738e653aa2d9f7670d0b19409ce30916cc397Nick Pelly                buf += 8;
15130a738e653aa2d9f7670d0b19409ce30916cc397Nick Pelly                dp += 8;
15230a738e653aa2d9f7670d0b19409ce30916cc397Nick Pelly                break;
1537342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            default:
1547342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project                FAILIF(1, "Error parsing (%d): %s\n", __LINE__, buffer);
1557342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            }
1567342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            break;
1577342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project        default:
1587342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            FAILIF(1, "Error parsing (%d): %s\n", __LINE__, buffer);
1597342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project        }
1607342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    }
1617342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
1627342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    dump_record(file_out, opcode, dp - data, data);
1637342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project}
1647342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
1657342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
1667342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Projectint main(int argc, char **argv) {
1677342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
1687342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    if (argc != 3)
1697342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project        usage();
1707342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
1717342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    FILE *file_in = fopen(argv[1], "r");
1727342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    FAILIF(!file_in, "Could not open %s: %s\n", argv[1], strerror(errno));
1737342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
1747342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    FILE *file_out = fopen(argv[2], "w+");
1757342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    FAILIF(!file_out, "Could not open %s: %s\n", argv[2], strerror(errno));
1767342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
1777342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    char buffer[1024];
1787342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    char *buf;
1797342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
1807342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    while (fgets(buffer, 1024, file_in) != NULL) {
1817342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project        buf = buffer;
1827342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project        while (*buf && isspace(*buf))
1837342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            buf++;
1847342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project        switch (*buf) {
1857342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project        case 'S':
1867342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            process_line(file_out, buf, buffer);
1877342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            break;
1887342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project        case 'W':  // Wait_HCI_Command... meta-data, not needed
1897342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project        case '#':
1907342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project        case 0:
1917342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            continue;
1927342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project        default:
1937342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project            FAILIF(1, "Don't know what to do with: %s\n", buffer);
1947342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project        }
1957342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    }
1967342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
1977342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    fclose(file_in);
1987342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    fclose(file_out);
1997342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project
2007342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project    return 0;
2017342a3e6a751116a193ff27d69b87eda478a5016The Android Open Source Project}
202