S&B Volcano vaporizer remote control with Pi Pico W
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

wifi.c 5.0KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. /*
  2. * wifi.c
  3. *
  4. * Copyright (c) 2023 Thomas Buck (thomas@xythobuz.de)
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * See <http://www.gnu.org/licenses/>.
  17. */
  18. #include "pico/cyw43_arch.h"
  19. #include "lwip/netif.h"
  20. #include "lwip/ip4_addr.h"
  21. #include "config.h"
  22. #include "log.h"
  23. #include "mem.h"
  24. #include "wifi.h"
  25. #define CONNECT_TIMEOUT (5 * 1000)
  26. enum wifi_state {
  27. WS_IDLE = 0,
  28. WS_SCAN,
  29. WS_CONNECT,
  30. WS_WAIT_FOR_IP,
  31. WS_READY,
  32. };
  33. static enum wifi_state state = WS_IDLE;
  34. static uint32_t start_time = 0;
  35. static void wifi_connect(const char *ssid, const char *pw, uint32_t auth) {
  36. debug("connecting to '%s'", ssid);
  37. start_time = to_ms_since_boot(get_absolute_time());
  38. state = WS_CONNECT;
  39. // https://github.com/raspberrypi/pico-sdk/issues/1413
  40. uint32_t a = 0;
  41. if (auth & 4) {
  42. a = CYW43_AUTH_WPA2_AES_PSK;
  43. } else if (auth & 2) {
  44. a = CYW43_AUTH_WPA_TKIP_PSK;
  45. }
  46. int r = cyw43_arch_wifi_connect_async(ssid, pw, a);
  47. if (r != 0) {
  48. debug("failed to connect %d", r);
  49. state = WS_SCAN;
  50. }
  51. }
  52. static int scan_result(void *env, const cyw43_ev_scan_result_t *result) {
  53. (void)env;
  54. cyw43_thread_enter();
  55. if (result && (state == WS_SCAN)) {
  56. for (int i = 0; i < mem_data()->net_count; i++) {
  57. if ((strlen(mem_data()->net[i].name) == result->ssid_len)
  58. && (memcmp(mem_data()->net[i].name, result->ssid, result->ssid_len) == 0)) {
  59. wifi_connect(mem_data()->net[i].name,
  60. mem_data()->net[i].pass,
  61. result->auth_mode);
  62. break;
  63. }
  64. }
  65. }
  66. cyw43_thread_exit();
  67. return 0;
  68. }
  69. static void wifi_scan(void) {
  70. debug("starting scan");
  71. state = WS_SCAN;
  72. cyw43_wifi_scan_options_t scan_options = {0};
  73. int err = cyw43_wifi_scan(&cyw43_state, &scan_options, NULL, scan_result);
  74. if (err != 0) {
  75. debug("error %d", err);
  76. }
  77. }
  78. void wifi_init(void) {
  79. if (state != WS_IDLE) {
  80. debug("invalid state %d", state);
  81. return;
  82. }
  83. cyw43_thread_enter();
  84. cyw43_arch_enable_sta_mode();
  85. wifi_scan();
  86. cyw43_thread_exit();
  87. }
  88. void wifi_deinit(void) {
  89. cyw43_thread_enter();
  90. cyw43_arch_disable_sta_mode();
  91. state = WS_IDLE;
  92. cyw43_thread_exit();
  93. }
  94. bool wifi_initialized(void) {
  95. return (state != WS_IDLE);
  96. }
  97. bool wifi_ready(void) {
  98. return (state == WS_READY);
  99. }
  100. const char *wifi_state(void) {
  101. switch (state) {
  102. case WS_IDLE:
  103. return "Disabled";
  104. case WS_SCAN:
  105. return "Scanning";
  106. case WS_CONNECT:
  107. return "Connecting";
  108. case WS_WAIT_FOR_IP:
  109. return "Waiting for IP";
  110. case WS_READY: {
  111. cyw43_arch_lwip_begin();
  112. const ip4_addr_t *ip = netif_ip4_addr(netif_default);
  113. cyw43_arch_lwip_end();
  114. return ip4addr_ntoa(ip);
  115. }
  116. }
  117. return NULL;
  118. }
  119. void wifi_run(void) {
  120. cyw43_thread_enter();
  121. if (state == WS_SCAN) {
  122. if (!cyw43_wifi_scan_active(&cyw43_state)) {
  123. debug("restarting scan");
  124. wifi_scan();
  125. }
  126. } else if (state == WS_CONNECT) {
  127. int link = cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA);
  128. static int prev_link = 0xFF;
  129. if (prev_link != link) {
  130. prev_link = link;
  131. debug("net link status: %d", link);
  132. }
  133. if (link == CYW43_LINK_JOIN) {
  134. debug("joined network");
  135. start_time = to_ms_since_boot(get_absolute_time());
  136. state = WS_WAIT_FOR_IP;
  137. } else if (link < CYW43_LINK_DOWN) {
  138. debug("net connection failed. retry.");
  139. wifi_scan();
  140. }
  141. uint32_t now = to_ms_since_boot(get_absolute_time());
  142. if ((now - start_time) >= CONNECT_TIMEOUT) {
  143. debug("net connection timeout. retry.");
  144. wifi_scan();
  145. }
  146. } else if (state == WS_WAIT_FOR_IP) {
  147. cyw43_arch_lwip_begin();
  148. const ip4_addr_t *ip = netif_ip4_addr(netif_default);
  149. cyw43_arch_lwip_end();
  150. if (ip4_addr_get_u32(ip) != 0) {
  151. state = WS_READY;
  152. debug("got IP '%s'", ip4addr_ntoa(ip));
  153. }
  154. uint32_t now = to_ms_since_boot(get_absolute_time());
  155. if ((now - start_time) >= CONNECT_TIMEOUT) {
  156. debug("net dhcp timeout. retry.");
  157. start_time = now;
  158. //cyw43_arch_lwip_begin();
  159. //dhcp_renew(netif_default);
  160. //cyw43_arch_lwip_end();
  161. // DHCP renew does not seem to help, only a full reconnect
  162. wifi_scan();
  163. }
  164. }
  165. cyw43_thread_exit();
  166. }