ZuluSCSI_platform_network.cpp 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343
  1. /*
  2. * Copyright (c) 2023 joshua stein <jcs@jcs.org>
  3. *
  4. * Permission to use, copy, modify, and distribute this software for any
  5. * purpose with or without fee is hereby granted, provided that the above
  6. * copyright notice and this permission notice appear in all copies.
  7. *
  8. * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  9. * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  10. * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  11. * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  12. * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  13. * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  14. * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  15. */
  16. #include "ZuluSCSI_platform.h"
  17. #include "ZuluSCSI_log.h"
  18. #include "ZuluSCSI_config.h"
  19. #include <scsi.h>
  20. #ifdef ZULUSCSI_NETWORK
  21. #include <network.h>
  22. extern "C" {
  23. #include <cyw43.h>
  24. #include <pico/cyw43_arch.h>
  25. #ifndef CYW43_IOCTL_GET_RSSI
  26. #define CYW43_IOCTL_GET_RSSI (0xfe)
  27. #endif
  28. // A default DaynaPort-compatible MAC
  29. static const char defaultMAC[] = { 0x00, 0x80, 0x19, 0xc0, 0xff, 0xee };
  30. static bool network_in_use = false;
  31. bool platform_network_supported()
  32. {
  33. /* from cores/rp2040/RP2040Support.h */
  34. #if !defined(ARDUINO_RASPBERRY_PI_PICO_W)
  35. return false;
  36. #else
  37. extern bool __isPicoW;
  38. return __isPicoW;
  39. #endif
  40. }
  41. int platform_network_init(char *mac)
  42. {
  43. pico_unique_board_id_t board_id;
  44. uint8_t set_mac[6], read_mac[6];
  45. if (!platform_network_supported())
  46. return -1;
  47. logmsg(" ");
  48. logmsg("=== Network Initialization ===");
  49. memset(wifi_network_list, 0, sizeof(wifi_network_list));
  50. cyw43_deinit(&cyw43_state);
  51. if (mac == NULL || (mac[0] == 0 && mac[1] == 0 && mac[2] == 0 && mac[3] == 0 && mac[4] == 0 && mac[5] == 0))
  52. {
  53. mac = (char *)&set_mac;
  54. memcpy(mac, defaultMAC, sizeof(set_mac));
  55. // retain Dayna vendor but use a device id specific to this board
  56. pico_get_unique_board_id(&board_id);
  57. if (g_log_debug)
  58. logmsg_f("Unique board id: %02x %02x %02x %02x %02x %02x %02x %02x",
  59. board_id.id[0], board_id.id[1], board_id.id[2], board_id.id[3],
  60. board_id.id[4], board_id.id[5], board_id.id[6], board_id.id[7]);
  61. if (board_id.id[3] != 0 && board_id.id[4] != 0 && board_id.id[5] != 0)
  62. {
  63. mac[3] = board_id.id[3];
  64. mac[4] = board_id.id[4];
  65. mac[5] = board_id.id[5];
  66. }
  67. memcpy(scsiDev.boardCfg.wifiMACAddress, mac, sizeof(scsiDev.boardCfg.wifiMACAddress));
  68. }
  69. // setting the MAC requires libpico to be compiled with CYW43_USE_OTP_MAC=0
  70. memcpy(cyw43_state.mac, mac, sizeof(cyw43_state.mac));
  71. cyw43_arch_enable_sta_mode();
  72. cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, read_mac);
  73. logmsg_f("Wi-Fi MAC: %02X:%02X:%02X:%02X:%02X:%02X",
  74. read_mac[0], read_mac[1], read_mac[2], read_mac[3], read_mac[4], read_mac[5]);
  75. if (memcmp(mac, read_mac, sizeof(read_mac)) != 0)
  76. logmsg("WARNING: Wi-Fi MAC is not what was requested (%02x:%02x:%02x:%02x:%02x:%02x), is libpico not compiled with CYW43_USE_OTP_MAC=0?",
  77. mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
  78. network_in_use = true;
  79. return 0;
  80. }
  81. void platform_network_add_multicast_address(uint8_t *mac)
  82. {
  83. int ret;
  84. if ((ret = cyw43_wifi_update_multicast_filter(&cyw43_state, mac, true)) != 0)
  85. logmsg_f("%s: cyw43_wifi_update_multicast_filter: %d", __func__, ret);
  86. }
  87. bool platform_network_wifi_join(char *ssid, char *password)
  88. {
  89. int ret;
  90. if (!platform_network_supported())
  91. return false;
  92. if (password == NULL || password[0] == 0)
  93. {
  94. logmsg_f("Connecting to Wi-Fi SSID \"%s\" with no authentication", ssid);
  95. ret = cyw43_arch_wifi_connect_async(ssid, NULL, CYW43_AUTH_OPEN);
  96. }
  97. else
  98. {
  99. logmsg_f("Connecting to Wi-Fi SSID \"%s\" with WPA/WPA2 PSK", ssid);
  100. ret = cyw43_arch_wifi_connect_async(ssid, password, CYW43_AUTH_WPA2_MIXED_PSK);
  101. }
  102. if (ret != 0)
  103. {
  104. logmsg_f("Wi-Fi connection failed: %d", ret);
  105. }
  106. else
  107. {
  108. // Blink 2 times at start of connection sequence
  109. LED_OFF();
  110. for (uint8_t i = 0; i < 2; i++)
  111. {
  112. delay(75);
  113. LED_ON();
  114. delay(75);
  115. LED_OFF();
  116. }
  117. }
  118. return (ret == 0);
  119. }
  120. void platform_network_poll()
  121. {
  122. if (!network_in_use)
  123. return;
  124. scsiNetworkPurge();
  125. cyw43_arch_poll();
  126. }
  127. int platform_network_send(uint8_t *buf, size_t len)
  128. {
  129. int ret = cyw43_send_ethernet(&cyw43_state, 0, len, buf, 0);
  130. if (ret != 0)
  131. logmsg_f("cyw43_send_ethernet failed: %d", ret);
  132. return ret;
  133. }
  134. static int platform_network_wifi_scan_result(void *env, const cyw43_ev_scan_result_t *result)
  135. {
  136. struct wifi_network_entry *entry = NULL;
  137. if (!result || !result->ssid_len || !result->ssid[0])
  138. return 0;
  139. for (int i = 0; i < WIFI_NETWORK_LIST_ENTRY_COUNT; i++)
  140. {
  141. // take first available
  142. if (wifi_network_list[i].ssid[0] == '\0')
  143. {
  144. entry = &wifi_network_list[i];
  145. break;
  146. }
  147. // or if we've seen this network before, use this slot
  148. else if (strcmp((char *)result->ssid, wifi_network_list[i].ssid) == 0)
  149. {
  150. entry = &wifi_network_list[i];
  151. break;
  152. }
  153. }
  154. if (!entry)
  155. {
  156. // no available slots, insert according to our RSSI
  157. for (int i = 0; i < WIFI_NETWORK_LIST_ENTRY_COUNT; i++)
  158. {
  159. if (result->rssi > wifi_network_list[i].rssi)
  160. {
  161. // shift everything else down
  162. for (int j = WIFI_NETWORK_LIST_ENTRY_COUNT - 1; j > i; j--)
  163. wifi_network_list[j] = wifi_network_list[j - 1];
  164. entry = &wifi_network_list[i];
  165. memset(entry, 0, sizeof(struct wifi_network_entry));
  166. break;
  167. }
  168. }
  169. }
  170. if (entry == NULL)
  171. return 0;
  172. if (entry->rssi == 0 || result->rssi > entry->rssi)
  173. {
  174. entry->channel = result->channel;
  175. entry->rssi = result->rssi;
  176. }
  177. if (result->auth_mode & 7)
  178. entry->flags = WIFI_NETWORK_FLAGS_AUTH;
  179. strncpy(entry->ssid, (const char *)result->ssid, sizeof(entry->ssid));
  180. entry->ssid[sizeof(entry->ssid) - 1] = '\0';
  181. memcpy(entry->bssid, result->bssid, sizeof(entry->bssid));
  182. return 0;
  183. }
  184. int platform_network_wifi_start_scan()
  185. {
  186. if (cyw43_wifi_scan_active(&cyw43_state))
  187. return -1;
  188. cyw43_wifi_scan_options_t scan_options = { 0 };
  189. memset(wifi_network_list, 0, sizeof(wifi_network_list));
  190. return cyw43_wifi_scan(&cyw43_state, &scan_options, NULL, platform_network_wifi_scan_result);
  191. }
  192. int platform_network_wifi_scan_finished()
  193. {
  194. return !cyw43_wifi_scan_active(&cyw43_state);
  195. }
  196. void platform_network_wifi_dump_scan_list()
  197. {
  198. struct wifi_network_entry *entry = NULL;
  199. for (int i = 0; i < WIFI_NETWORK_LIST_ENTRY_COUNT; i++)
  200. {
  201. entry = &wifi_network_list[i];
  202. if (entry->ssid[0] == '\0')
  203. break;
  204. logmsg_f("wifi[%d] = %s, channel %d, rssi %d, bssid %02x:%02x:%02x:%02x:%02x:%02x, flags %d",
  205. i, entry->ssid, entry->channel, entry->rssi,
  206. entry->bssid[0], entry->bssid[1], entry->bssid[2],
  207. entry->bssid[3], entry->bssid[4], entry->bssid[5],
  208. entry->flags);
  209. }
  210. }
  211. int platform_network_wifi_rssi()
  212. {
  213. int32_t rssi = 0;
  214. cyw43_ioctl(&cyw43_state, CYW43_IOCTL_GET_RSSI, sizeof(rssi), (uint8_t *)&rssi, CYW43_ITF_STA);
  215. return rssi;
  216. }
  217. char * platform_network_wifi_ssid()
  218. {
  219. struct ssid_t {
  220. uint32_t ssid_len;
  221. uint8_t ssid[32 + 1];
  222. } ssid;
  223. static char cur_ssid[32 + 1];
  224. memset(cur_ssid, 0, sizeof(cur_ssid));
  225. int ret = cyw43_ioctl(&cyw43_state, CYW43_IOCTL_GET_SSID, sizeof(ssid), (uint8_t *)&ssid, CYW43_ITF_STA);
  226. if (ret)
  227. {
  228. logmsg_f("Failed getting Wi-Fi SSID: %d", ret);
  229. return NULL;
  230. }
  231. ssid.ssid[sizeof(ssid.ssid) - 1] = '\0';
  232. if (ssid.ssid_len < sizeof(ssid.ssid))
  233. ssid.ssid[ssid.ssid_len] = '\0';
  234. strlcpy(cur_ssid, (char *)ssid.ssid, sizeof(cur_ssid));
  235. return cur_ssid;
  236. }
  237. char * platform_network_wifi_bssid()
  238. {
  239. static char bssid[6];
  240. memset(bssid, 0, sizeof(bssid));
  241. /* TODO */
  242. return bssid;
  243. }
  244. int platform_network_wifi_channel()
  245. {
  246. int32_t channel = 0;
  247. cyw43_ioctl(&cyw43_state, CYW43_IOCTL_GET_CHANNEL, sizeof(channel), (uint8_t *)&channel, CYW43_ITF_STA);
  248. return channel;
  249. }
  250. // these override weakly-defined functions in pico-sdk
  251. void cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, const uint8_t *buf)
  252. {
  253. scsiNetworkEnqueue(buf, len);
  254. }
  255. void cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf)
  256. {
  257. logmsg_f("Disassociated from Wi-Fi SSID \"%s\"", self->ap_ssid);
  258. }
  259. void cyw43_cb_tcpip_set_link_up(cyw43_t *self, int itf)
  260. {
  261. char *ssid = platform_network_wifi_ssid();
  262. if (ssid)
  263. {
  264. logmsg_f("Successfully connected to Wi-Fi SSID \"%s\"", ssid);
  265. // blink LED 3 times when connected
  266. LED_OFF();
  267. for (uint8_t i = 0; i < 3; i++)
  268. {
  269. delay(75);
  270. LED_ON();
  271. delay(75);
  272. LED_OFF();
  273. }
  274. }
  275. }
  276. }
  277. #endif // ZULUSCSI_NETWORK