btstack_chipset_bcm.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  1. /*
  2. * Copyright (C) 2009-2012 by Matthias Ringwald
  3. *
  4. * Redistribution and use in source and binary forms, with or without
  5. * modification, are permitted provided that the following conditions
  6. * are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright
  9. * notice, this list of conditions and the following disclaimer.
  10. * 2. Redistributions in binary form must reproduce the above copyright
  11. * notice, this list of conditions and the following disclaimer in the
  12. * documentation and/or other materials provided with the distribution.
  13. * 3. Neither the name of the copyright holders nor the names of
  14. * contributors may be used to endorse or promote products derived
  15. * from this software without specific prior written permission.
  16. * 4. Any redistribution, use, or modification is done solely for
  17. * personal benefit and not for any commercial purpose or for
  18. * monetary gain.
  19. *
  20. * THIS SOFTWARE IS PROVIDED BY MATTHIAS RINGWALD AND CONTRIBUTORS
  21. * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  22. * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
  23. * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL MATTHIAS
  24. * RINGWALD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
  25. * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
  26. * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
  27. * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
  28. * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  29. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  30. * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  31. * SUCH DAMAGE.
  32. *
  33. * Please inquire about commercial licensing options at contact@bluekitchen-gmbh.com
  34. *
  35. */
  36. #define BTSTACK_FILE__ "btstack_chipset_bcm.c"
  37. /*
  38. * bt_control_bcm.c
  39. *
  40. * Adapter to use Broadcom-based chipsets with BTstack
  41. */
  42. #include "btstack_config.h"
  43. #include <stddef.h> /* NULL */
  44. #include <stdio.h>
  45. #include <string.h> /* memcpy */
  46. #ifdef ART_PI_USING_OTA_LIB
  47. #include <rt_ota.h>
  48. #endif
  49. #include <fal.h>
  50. #include "btstack_control.h"
  51. #include "btstack_debug.h"
  52. #include "btstack_chipset_bcm.h"
  53. #include "hci.h"
  54. #ifdef HAVE_POSIX_FILE_IO
  55. #include <ctype.h>
  56. #if defined(RT_VERSION_CHECK) && (RTTHREAD_VERSION >= RT_VERSION_CHECK(5, 2, 0))
  57. #include <dfs_file.h>
  58. #else
  59. #include <dfs_posix.h>
  60. #endif
  61. #include <fcntl.h>
  62. #include <unistd.h>
  63. #endif
  64. #ifdef _WIN32
  65. #include <Windows.h>
  66. #endif
  67. // assert outgoing and incoming hci packet buffers can hold max hci command resp. event packet
  68. #if HCI_OUTGOING_PACKET_BUFFER_SIZE < (HCI_CMD_HEADER_SIZE + 255)
  69. #error "HCI_OUTGOING_PACKET_BUFFER_SIZE to small. Outgoing HCI packet buffer to small for largest HCI Command packet. Please set HCI_ACL_PAYLOAD_SIZE to 258 or higher."
  70. #endif
  71. #if HCI_INCOMING_PACKET_BUFFER_SIZE < (HCI_EVENT_HEADER_SIZE + 255)
  72. #error "HCI_INCOMING_PACKET_BUFFER_SIZE to small. Incoming HCI packet buffer to small for largest HCI Event packet. Please set HCI_ACL_PAYLOAD_SIZE to 257 or higher."
  73. #endif
  74. static int send_download_command;
  75. static uint32_t init_script_offset;
  76. // Embedded == non posix systems
  77. // actual init script provided by separate bt_firmware_image.c from WICED SDK
  78. extern const uint8_t brcm_patchram_buf[];
  79. extern const int brcm_patch_ram_length;
  80. extern const char brcm_patch_version[];
  81. //
  82. // @note: Broadcom chips require higher UART clock for baud rate > 3000000 -> limit baud rate in hci.c
  83. static void chipset_set_baudrate_command(uint32_t baudrate, uint8_t *hci_cmd_buffer){
  84. hci_cmd_buffer[0] = 0x18;
  85. hci_cmd_buffer[1] = 0xfc;
  86. hci_cmd_buffer[2] = 0x06;
  87. hci_cmd_buffer[3] = 0x00;
  88. hci_cmd_buffer[4] = 0x00;
  89. little_endian_store_32(hci_cmd_buffer, 5, baudrate);
  90. }
  91. // @note: bd addr has to be set after sending init script (it might just get re-set)
  92. static void chipset_set_bd_addr_command(bd_addr_t addr, uint8_t *hci_cmd_buffer){
  93. hci_cmd_buffer[0] = 0x01;
  94. hci_cmd_buffer[1] = 0xfc;
  95. hci_cmd_buffer[2] = 0x06;
  96. reverse_bd_addr(addr, &hci_cmd_buffer[3]);
  97. }
  98. #ifdef HAVE_POSIX_FILE_IO
  99. static const char * hcd_file_path;
  100. static const char * hcd_folder_path = "";
  101. static int hcd_fd;
  102. //static char matched_file[1000];
  103. static void chipset_init(const void * config){
  104. if (hcd_file_path){
  105. log_info("chipset-bcm: init file %s", hcd_file_path);
  106. } else {
  107. log_info("chipset-bcm: init folder %s", hcd_folder_path);
  108. }
  109. send_download_command = 1;
  110. init_script_offset = 0;
  111. hcd_fd = -1;
  112. }
  113. static const uint8_t download_command[] = {0x2e, 0xfc, 0x00};
  114. static btstack_chipset_result_t chipset_next_command(uint8_t * hci_cmd_buffer){
  115. static int hcd_file_length;
  116. if (hcd_fd < 0){
  117. log_info("chipset-bcm: hcd_file_path open file %s", hcd_file_path);
  118. hcd_fd = open(hcd_file_path, O_RDONLY);
  119. if (hcd_fd < 0){
  120. log_error("chipset-bcm: can't open file %s", hcd_file_path);
  121. return BTSTACK_CHIPSET_NO_INIT_SCRIPT;
  122. }
  123. #ifdef ART_PI_USING_OTA_LIB
  124. const struct fal_partition *hcd_part = fal_partition_find("bt_image");
  125. hcd_file_length = rt_ota_get_raw_fw_size(hcd_part);
  126. #else
  127. struct stat file_stat;
  128. if (fstat(hcd_fd, &file_stat) < 0) {
  129. log_error("chipset-bcm: can't get file size for %s", hcd_file_path);
  130. close(hcd_fd);
  131. return BTSTACK_CHIPSET_NO_INIT_SCRIPT;
  132. }
  133. hcd_file_length = file_stat.st_size;
  134. log_info("\r\n patch file len :%d", hcd_file_length);
  135. #endif
  136. if(hcd_file_path <= 0){
  137. return BTSTACK_CHIPSET_NO_INIT_SCRIPT;
  138. }
  139. }
  140. // send download firmware command
  141. if (send_download_command){
  142. send_download_command = 0;
  143. memcpy(hci_cmd_buffer, download_command, sizeof(download_command));
  144. return BTSTACK_CHIPSET_VALID_COMMAND;
  145. }
  146. // read next command, but skip download command
  147. do {
  148. // read command
  149. int res = read(hcd_fd, hci_cmd_buffer, 3);
  150. if (init_script_offset == hcd_file_length){
  151. log_info("chipset-bcm: end of file, size %u", init_script_offset);
  152. close(hcd_fd);
  153. return BTSTACK_CHIPSET_DONE;
  154. }
  155. if (res < 0){
  156. log_error("chipset-bcm: read error at %u", init_script_offset);
  157. return BTSTACK_CHIPSET_DONE;
  158. }
  159. init_script_offset += 3;
  160. // read parameters
  161. int param_len = hci_cmd_buffer[2];
  162. if (param_len){
  163. res = read(hcd_fd, &hci_cmd_buffer[3], param_len);
  164. }
  165. if (res < 0){
  166. log_error("chipset-bcm: read error at %u", init_script_offset);
  167. return BTSTACK_CHIPSET_DONE;
  168. }
  169. init_script_offset += param_len;
  170. } while (memcmp(hci_cmd_buffer, download_command, sizeof(download_command)) == 0);
  171. return BTSTACK_CHIPSET_VALID_COMMAND;
  172. }
  173. void btstack_chipset_bcm_set_hcd_file_path(const char * path){
  174. hcd_file_path = path;
  175. }
  176. void btstack_chipset_bcm_set_hcd_folder_path(const char * path){
  177. hcd_folder_path = path;
  178. }
  179. //static int equal_ignore_case(const char *str1, const char *str2){
  180. // if (!str1 || !str2) return (1);
  181. // int i = 0;
  182. // while (true){
  183. // if (!str1[i] && !str2[i]) return 1;
  184. // if (tolower(str1[i]) != tolower(str2[i])) return 0;
  185. // if (!str1[i] || !str2[i]) return 0;
  186. // i++;
  187. // }
  188. //}
  189. // assumption starts with BCM or bcm
  190. #define MAX_DEVICE_NAME_LEN 25
  191. void btstack_chipset_bcm_set_device_name(const char * device_name){
  192. // ignore if file path already set
  193. int fd = -1;
  194. if (hcd_file_path) {
  195. log_error("chipset-bcm: set device name called %s although path %s already set", device_name, hcd_file_path);
  196. return;
  197. }
  198. fd = open(device_name,O_RDONLY);
  199. if(fd < 0 )
  200. {
  201. log_error("cannot open bluetooth firmware %s", device_name);
  202. return;
  203. }
  204. close(fd);
  205. hcd_file_path = device_name;
  206. // construct filename for long variant
  207. // if (strlen(device_name) > MAX_DEVICE_NAME_LEN){
  208. // log_error("chipset-bcm: device name %s too long", device_name);
  209. // return;
  210. // }
  211. // char filename_complete[MAX_DEVICE_NAME_LEN+5];
  212. // strcpy(filename_complete, device_name);
  213. // //strcat(filename_complete, ".hcd");
  214. //
  215. // // construct short variant without revision info
  216. // char filename_short[MAX_DEVICE_NAME_LEN+5];
  217. // strcpy(filename_short, device_name);
  218. // int len = strlen(filename_short);
  219. // while (len > 3){
  220. // char c = filename_short[len-1];
  221. // if (isdigit(c) == 0) break;
  222. // len--;
  223. // }
  224. // if (len > 3){
  225. // filename_short[len-1] = 0;
  226. // }
  227. // // strcat(filename_short, ".hcd");
  228. // log_info("chipset-bcm: looking for %s and %s", filename_short, filename_complete);
  229. //
  230. // // find in folder
  231. // DIR *dirp = opendir(hcd_folder_path);
  232. // int match_short = 0;
  233. // int match_complete = 0;
  234. // if (!dirp){
  235. // log_error("chipset-bcm: could not get directory for %s", hcd_folder_path);
  236. // return;
  237. // }
  238. // while (true){
  239. // struct dirent *dp = readdir(dirp);
  240. // if (!dp) break;
  241. // if (equal_ignore_case(filename_complete, dp->d_name)){
  242. // match_complete = 1;
  243. // continue;
  244. // }
  245. // if (equal_ignore_case(filename_short, dp->d_name)){
  246. // match_short = 1;
  247. // }
  248. // }
  249. // closedir(dirp);
  250. // if (match_complete){
  251. // sprintf(matched_file, "%s/%s", hcd_folder_path, filename_complete);
  252. // hcd_file_path = matched_file;
  253. // return;
  254. // }
  255. // if (match_short){
  256. // sprintf(matched_file, "%s/%s", hcd_folder_path, filename_short);
  257. // hcd_file_path = matched_file;
  258. // return;
  259. // }
  260. // log_error("chipset-bcm: could not find %s or %s, please provide firmware in %s", filename_complete, filename_short, hcd_folder_path);
  261. }
  262. #else
  263. static void chipset_init(const void * config){
  264. log_info("chipset-bcm: init script %s, len %u", brcm_patch_version, brcm_patch_ram_length);
  265. init_script_offset = 0;
  266. send_download_command = 1;
  267. }
  268. static btstack_chipset_result_t chipset_next_command(uint8_t * hci_cmd_buffer){
  269. // no initscript
  270. if (brcm_patch_ram_length == 0) return BTSTACK_CHIPSET_NO_INIT_SCRIPT;
  271. // send download firmware command
  272. if (send_download_command){
  273. send_download_command = 0;
  274. hci_cmd_buffer[0] = 0x2e;
  275. hci_cmd_buffer[1] = 0xfc;
  276. hci_cmd_buffer[2] = 0x00;
  277. return BTSTACK_CHIPSET_VALID_COMMAND;
  278. }
  279. if (init_script_offset >= brcm_patch_ram_length) {
  280. return BTSTACK_CHIPSET_DONE;
  281. }
  282. int cmd_len = 3 + brcm_patchram_buf[init_script_offset+2];
  283. memcpy(&hci_cmd_buffer[0], &brcm_patchram_buf[init_script_offset], cmd_len);
  284. init_script_offset += cmd_len;
  285. return BTSTACK_CHIPSET_VALID_COMMAND;
  286. }
  287. #endif
  288. static btstack_chipset_t btstack_chipset_bcm = {
  289. "BCM",
  290. chipset_init,
  291. chipset_next_command,
  292. chipset_set_baudrate_command,
  293. chipset_set_bd_addr_command,
  294. };
  295. // MARK: public API
  296. const btstack_chipset_t * btstack_chipset_bcm_instance(void){
  297. return &btstack_chipset_bcm;
  298. }
  299. /**
  300. * @brief Enable init file - needed by btstack_chipset_bcm_download_firmware when using h5
  301. * @param enabled
  302. */
  303. void btstack_chipset_bcm_enable_init_script(int enabled){
  304. if (enabled){
  305. btstack_chipset_bcm.next_command = &chipset_next_command;
  306. } else {
  307. btstack_chipset_bcm.next_command = NULL;
  308. }
  309. }