mirror of
https://github.com/cesanta/mongoose.git
synced 2026-10-16 10:39:49 +00:00
526 lines
18 KiB
C
526 lines
18 KiB
C
#include "st67w6.h"
|
|
#include "net.h"
|
|
|
|
#if MG_ENABLE_TCPIP && defined(MG_ENABLE_DRIVER_ST67W6) && \
|
|
MG_ENABLE_DRIVER_ST67W6
|
|
|
|
static struct mg_tcpip_if *s_ifp;
|
|
static uint32_t s_ip, s_mask;
|
|
static bool s_link = false, s_connecting = false;
|
|
|
|
static void wifi_cb(struct mg_tcpip_if *ifp, int ev, void *ev_data) {
|
|
struct mg_wifi_data *wifi =
|
|
&((struct mg_tcpip_driver_st67w6_data *) ifp->driver_data)->wifi;
|
|
if (wifi->apmode && ev == MG_TCPIP_EV_STATE_CHANGE &&
|
|
*(uint8_t *) ev_data == MG_TCPIP_STATE_UP) {
|
|
MG_DEBUG(("Access Point started"));
|
|
s_ip = ifp->ip, ifp->ip = wifi->apip;
|
|
s_mask = ifp->mask, ifp->mask = wifi->apmask;
|
|
ifp->enable_dhcp_client = false;
|
|
ifp->enable_dhcp_server = true;
|
|
}
|
|
}
|
|
|
|
static bool st67w6_init(uint8_t *mac);
|
|
static void st67w6_poll(bool is_at);
|
|
|
|
static bool mg_tcpip_driver_st67w6_init(struct mg_tcpip_if *ifp) {
|
|
struct mg_tcpip_driver_st67w6_data *d =
|
|
(struct mg_tcpip_driver_st67w6_data *) ifp->driver_data;
|
|
struct mg_wifi_data *wifi = &d->wifi;
|
|
if (MG_BIG_ENDIAN) {
|
|
MG_ERROR(("Big-endian host"));
|
|
return false;
|
|
}
|
|
if (d->is_ready == NULL) return false;
|
|
s_ifp = ifp;
|
|
s_ip = ifp->ip;
|
|
s_mask = ifp->mask;
|
|
s_link = false;
|
|
ifp->pfn = wifi_cb;
|
|
if (!st67w6_init(ifp->mac)) return false;
|
|
|
|
if (d->send_queue.size == 0) d->send_queue.size = 8192;
|
|
d->send_queue.buf = (char *) mg_calloc(1, d->send_queue.size);
|
|
if (d->send_queue.buf == NULL) {
|
|
MG_ERROR(("OOM"));
|
|
return false;
|
|
}
|
|
|
|
if (wifi->apmode) {
|
|
return mg_wifi_ap_start(wifi);
|
|
} else if (wifi->ssid != NULL && wifi->pass != NULL) {
|
|
return mg_wifi_connect(wifi);
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Decouple; module access depends on it being RDY. See st67w6_poll()
|
|
size_t mg_tcpip_driver_st67w6_output(const void *buf, size_t len,
|
|
struct mg_tcpip_if *ifp) {
|
|
struct mg_tcpip_driver_st67w6_data *d =
|
|
(struct mg_tcpip_driver_st67w6_data *) ifp->driver_data;
|
|
char *p;
|
|
if (mg_queue_book(&d->send_queue, &p, len) < len) return 0;
|
|
memcpy(p, buf, len);
|
|
mg_queue_add(&d->send_queue, len);
|
|
return len;
|
|
}
|
|
|
|
static bool mg_tcpip_driver_st67w6_poll(struct mg_tcpip_if *ifp, bool s1) {
|
|
struct mg_tcpip_driver_st67w6_data *d =
|
|
(struct mg_tcpip_driver_st67w6_data *) ifp->driver_data;
|
|
if (d->is_ready == NULL) return false;
|
|
st67w6_poll(false);
|
|
if (!s1) return false;
|
|
return s_link;
|
|
}
|
|
|
|
struct mg_tcpip_driver mg_tcpip_driver_st67w6 = {
|
|
mg_tcpip_driver_st67w6_init, mg_tcpip_driver_st67w6_output, NULL,
|
|
mg_tcpip_driver_st67w6_poll};
|
|
|
|
// AT | STA | AP | HCI | OT
|
|
// --------------------------
|
|
// framing <-- includes rx stall indication
|
|
// --------------------------
|
|
// SPI <-- padded to 32-bit
|
|
//
|
|
// Transactions take place when the module signals RDY, 'tx' and 'write'
|
|
// functions actually just write to memory
|
|
// - AT: handles configuration and events (unsolicited +foo:). Responses may
|
|
// come as:
|
|
// - 1 frame: just OK or ERROR
|
|
// - 2 frames: 1 text line each, a response and OK
|
|
// - 3 frames: 2 text lines: 1 frame with text and no CR/LF, 1 frame with
|
|
// binary and CR/LF, 1 text line with OK
|
|
// - STA and AP contain plain Ethernet frames to/from the STA and AP networks,
|
|
// respectively
|
|
// - HCI: BLE stuff
|
|
// - OT: ?
|
|
|
|
#pragma pack(push, 1)
|
|
// little endian
|
|
|
|
struct spi_hdr {
|
|
uint16_t magic;
|
|
uint16_t len;
|
|
uint8_t vflags; // version :2, rx_stall :1, flags :5
|
|
uint8_t type;
|
|
uint16_t reserved;
|
|
};
|
|
|
|
#define ST67W6_SPI_TYPE_AT 0
|
|
#define ST67W6_SPI_TYPE_STA 1
|
|
#define ST67W6_SPI_TYPE_AP 2
|
|
#define ST67W6_SPI_TYPE_HCI 3
|
|
#define ST67W6_SPI_TYPE_OT 4
|
|
|
|
#pragma pack(pop)
|
|
|
|
static uint32_t txdata[2048 / 4], rxdata[2048 / 4];
|
|
static uint8_t at_resp[300];
|
|
|
|
static bool s_at_ok, s_at_err;
|
|
static size_t s_at_resp_len;
|
|
static void st67w6_handle_wifi_evnt(char *, size_t len);
|
|
static void st67w6_handle_scan_result(char *, size_t len);
|
|
|
|
static size_t st67w6_spi_poll(uint8_t *write, uint8_t *read);
|
|
static void st67w6_write(unsigned int f, void *data, uint16_t len);
|
|
static void st67w6_update_hash_table(void);
|
|
|
|
// High-level comm stuff
|
|
|
|
static void st67w6_poll(bool is_at) {
|
|
struct mg_tcpip_driver_st67w6_data *d =
|
|
(struct mg_tcpip_driver_st67w6_data *) s_ifp->driver_data;
|
|
struct spi_hdr *h = (struct spi_hdr *) rxdata;
|
|
unsigned int type;
|
|
uint8_t *txsource = (uint8_t *) txdata;
|
|
if (s_ifp->update_mac_hash_table) {
|
|
// first call to _poll() is after _init(), so this is safe
|
|
st67w6_update_hash_table();
|
|
s_ifp->update_mac_hash_table = false;
|
|
}
|
|
if (!is_at) { // send outstanding WLAN frames in the queue
|
|
char *buf;
|
|
size_t len;
|
|
// NOTE(): have traffic-dependent queues or queue traffic type with data
|
|
if ((len = mg_queue_next(&d->send_queue, &buf)) > 0) {
|
|
st67w6_write(d->wifi.apmode ? ST67W6_SPI_TYPE_AP : ST67W6_SPI_TYPE_STA,
|
|
buf, (uint16_t) len);
|
|
mg_queue_del(&d->send_queue, len);
|
|
} else { // nothing to send
|
|
txsource = NULL;
|
|
}
|
|
}
|
|
if (st67w6_spi_poll(txsource, (uint8_t *) rxdata) == 0) return;
|
|
if (h->len == 0) return;
|
|
type = h->type;
|
|
if (type == ST67W6_SPI_TYPE_AT) {
|
|
char *p = (char *) (h + 1);
|
|
size_t len = h->len;
|
|
if (len > 7 && strncmp(p, "+CWLAP:", 7) == 0) { // scan result
|
|
st67w6_handle_scan_result(p + 7, len - 7);
|
|
} else if (len > 4 && strncmp(p, "+CW:", 4) == 0) {
|
|
st67w6_handle_wifi_evnt(p + 4, len - 4);
|
|
} else {
|
|
MG_VERBOSE(("AT partial: %.*s", (int) len, p));
|
|
if (s_at_resp_len + len >= sizeof(at_resp))
|
|
s_at_resp_len = 0; // truncate response, error will be caught later
|
|
memcpy(at_resp + s_at_resp_len, p, len);
|
|
s_at_resp_len += len;
|
|
if (mg_match(mg_str_n((char *) at_resp, s_at_resp_len),
|
|
mg_str_n("*ERROR*", 7), NULL)) {
|
|
s_at_err = true;
|
|
} else if (mg_match(mg_str_n((char *) at_resp, s_at_resp_len),
|
|
mg_str_n("*OK*", 4), NULL)) {
|
|
s_at_ok = true;
|
|
}
|
|
}
|
|
} else if (type == ST67W6_SPI_TYPE_STA || type == ST67W6_SPI_TYPE_AP) {
|
|
// WLAN frame reception
|
|
mg_tcpip_qwrite(h + 1, h->len, s_ifp);
|
|
} // else silently discard
|
|
}
|
|
|
|
// WLAN event handling
|
|
|
|
// - Do not call any AT functions here, otherwise revise st67w6_at_wait()
|
|
// - The module likes to send ERROR along with other events
|
|
static void st67w6_handle_wifi_evnt(char *p, size_t len) {
|
|
struct mg_str data[2];
|
|
MG_VERBOSE(("event: %.*s", (int) len, p));
|
|
if (len > 9 && strncmp(p, "CONNECTED", 9) == 0) {
|
|
s_link = true;
|
|
s_connecting = false;
|
|
} else if (len > 12 && strncmp(p, "DISCONNECTED", 12) == 0) {
|
|
s_link = false;
|
|
s_connecting = false; // should not be needed
|
|
} else if (s_connecting && len > 6 &&
|
|
mg_match(mg_str_n(p, len), mg_str_n("ERROR,*\r\n*", 10), data)) {
|
|
size_t reason = 0;
|
|
bool ok = mg_to_size_t(data[0], &reason);
|
|
s_connecting = false;
|
|
MG_ERROR(("CONNECT FAILED"));
|
|
mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_CONNECT_ERR, ok ? &reason : NULL);
|
|
} else if (len > 9 && strncmp(p, "SCAN_DONE", 9) == 0) {
|
|
MG_VERBOSE(("scan complete"));
|
|
mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_SCAN_END, NULL);
|
|
} // else silently discard: CONNECTING; STA_CONNECTED,"MAC";
|
|
// STA_DISCONNECTED,"MAC"; DIST_STA_IP,"MAC","IP"
|
|
}
|
|
|
|
static bool st67w6_at_cmd(char *cmd, size_t len);
|
|
|
|
// Wi-Fi network stuff
|
|
|
|
static bool st67w6_wifi_connect(char *ssid, char *pass) {
|
|
char cmd[90]; // ssid + pass + AT
|
|
size_t cmd_len;
|
|
if (!st67w6_at_cmd("AT+CWMODE=1,0\r\n", 15)) return false;
|
|
cmd_len = mg_snprintf(cmd, sizeof(cmd), "AT+CWJAP=\"%s\",\"%s\",,0\r\n", ssid,
|
|
pass); // takes >700ms
|
|
if (!st67w6_at_cmd(cmd, cmd_len)) return false;
|
|
st67w6_at_cmd("AT+CWRECONNCFG=0,0\r\n", 20); // disregard error, connecting
|
|
s_connecting = true;
|
|
return true;
|
|
}
|
|
|
|
static bool st67w6_wifi_disconnect(void) {
|
|
s_connecting = false;
|
|
if (!st67w6_at_cmd("AT+CWQAP=0\r\n", 12)) return false; // takes >800ms
|
|
return st67w6_at_cmd("AT+CWMODE=0,0\r\n", 15); // takes >550ms
|
|
}
|
|
|
|
static bool st67w6_wifi_ap_start(char *ssid, char *pass, unsigned int channel) {
|
|
char cmd[90]; // ssid + pass + AT
|
|
size_t cmd_len;
|
|
if (!st67w6_at_cmd("AT+CWMODE=2,0\r\n", 15)) return false; // takes >800ms
|
|
cmd_len = mg_snprintf(
|
|
cmd, sizeof(cmd), "AT+CWSAP=\"%s\",\"%s\",%u,3,2,0\r\n", ssid, pass,
|
|
channel); // 3: WPA2_PSK; 2: max stations // takes >350ms
|
|
s_link = true;
|
|
return st67w6_at_cmd(cmd, cmd_len);
|
|
}
|
|
|
|
static bool st67w6_wifi_ap_stop(void) {
|
|
s_link = false;
|
|
return st67w6_at_cmd("AT+CWMODE=0,0\r\n", 15); // takes >550ms
|
|
}
|
|
|
|
// WLAN scan handling
|
|
|
|
// +CWLAP:(security,"SSID",RSSI,"BSSID",channel,cipher,proto,wps)\r\n
|
|
// security: OPEN, WEP, WPA, WPA2, WPA-WPA2, WPA-EAP, WPA3-SAE, WPA2-WPA3-SAE
|
|
// cipher: NONE, WEP, AES/CCMP, TKIP, TKIP and AES/CCMP
|
|
// proto: 4-bit bitmap AX,N,G,B; all set from right to left
|
|
|
|
static bool st67w6_wifi_scan(void) {
|
|
return st67w6_at_cmd("AT+CWLAPOPT=1,1695,-100,255,50\r\n", 32) &&
|
|
st67w6_at_cmd("AT+CWLAP=0,,,0\r\n", 16);
|
|
}
|
|
|
|
static void st67w6_handle_scan_result(char *data, size_t len) {
|
|
struct mg_wifi_scan_bss_data bss;
|
|
struct mg_str fields[2];
|
|
char mac[6];
|
|
uint8_t val;
|
|
unsigned int i;
|
|
MG_VERBOSE(("scan result event: %.*s", (int) len, data));
|
|
++data, --len; // skip '('
|
|
if (!mg_span(mg_str_n(data, len), &fields[0], &fields[1], ',') ||
|
|
!mg_str_to_num(fields[0], 10, &val, 1))
|
|
return;
|
|
bss.security =
|
|
(val == 0) ? MG_WIFI_SECURITY_OPEN : (uint8_t) MG_WIFI_SECURITY_WEP;
|
|
if (val == 2 || val == 4) bss.security |= MG_WIFI_SECURITY_WPA;
|
|
if (val == 3 || val == 4 || val == 7) bss.security |= MG_WIFI_SECURITY_WPA2;
|
|
if (val == 6 || val == 7) bss.security |= MG_WIFI_SECURITY_WPA3;
|
|
if (val == 5) bss.security |= MG_WIFI_SECURITY_WPA_ENTERPRISE;
|
|
if (!mg_span(fields[1], &fields[0], &fields[1], ',')) return;
|
|
bss.SSID.buf = fields[0].buf + 1, bss.SSID.len = fields[0].len - 2;
|
|
if (!mg_span(fields[1], &fields[0], &fields[1], ',')) return;
|
|
while (fields[0].buf[0] == ' ') ++fields[0].buf, --fields[0].len;
|
|
if (fields[0].buf[0] != '-') return; // positive RSSI would be great
|
|
++fields[0].buf, --fields[0].len;
|
|
if (!mg_str_to_num(fields[0], 10, &val, 1)) return;
|
|
bss.RSSI = (int8_t) - (int8_t) val;
|
|
if (!mg_span(fields[1], &fields[0], &fields[1], ',')) return;
|
|
if (fields[0].len < 19) return;
|
|
++fields[0].buf, --fields[0].len; // skip '"'
|
|
for (i = 0; i < 6; i++) {
|
|
struct mg_str str;
|
|
str.buf = fields[0].buf + 3 * i;
|
|
str.len = 2;
|
|
if (!mg_str_to_num(str, 16, &mac[i], 1)) return;
|
|
}
|
|
bss.BSSID = mac;
|
|
if (!mg_span(fields[1], &fields[0], &fields[1], ',') ||
|
|
!mg_str_to_num(fields[0], 10, &bss.channel, 1))
|
|
return;
|
|
if (!mg_span(fields[1], &fields[0], &fields[1], ',') ||
|
|
!mg_str_to_num(fields[0], 10, &val, 1))
|
|
return;
|
|
// ignore cypher
|
|
if (!mg_span(fields[1], &fields[0], &fields[1], ',') ||
|
|
!mg_str_to_num(fields[0], 10, &val, 1))
|
|
return;
|
|
bss.has_n = (val & 4) != 0;
|
|
bss.has_ax = (val & 8) != 0;
|
|
bss.band = MG_WIFI_BAND_2G; // NOT INFORMED with default options, no docs
|
|
MG_VERBOSE(("BSS: %.*s (%u) (%M) %d dBm %u", bss.SSID.len, bss.SSID.buf,
|
|
bss.channel, mg_print_mac, bss.BSSID, (int) bss.RSSI,
|
|
bss.security));
|
|
mg_tcpip_call(s_ifp, MG_TCPIP_EV_WIFI_SCAN_RESULT, &bss);
|
|
}
|
|
|
|
// AT stuff
|
|
|
|
static inline bool delayms(unsigned int ms) {
|
|
mg_delayms(ms);
|
|
return true;
|
|
}
|
|
|
|
// send AT command, wait for a response or timeout, meanwhile delivering
|
|
// received frames and events
|
|
|
|
static bool st67w6_at_cmd(char *cmd, size_t len) {
|
|
bool is_at = true;
|
|
unsigned int times = 1000;
|
|
s_at_resp_len = 0;
|
|
st67w6_write(ST67W6_SPI_TYPE_AT, cmd, (uint16_t) len);
|
|
s_at_ok = false, s_at_err = false;
|
|
do { // AT response processing does not call any other AT function
|
|
st67w6_poll(is_at); // otherwise we can't allow them to pile up here
|
|
is_at = false; // avoid repeating, allow queued WLAN frames to be sent
|
|
// network frames will be pushed to the queue so that is safe
|
|
} while (!s_at_ok && !s_at_err && times-- > 0 && delayms(1));
|
|
MG_VERBOSE(("AT response:\n%.*s", s_at_resp_len, at_resp));
|
|
MG_VERBOSE(("ok: %c, err: %c, times: %d", s_at_ok ? '1' : '0',
|
|
s_at_err ? '1' : '0', (int) times));
|
|
return s_at_ok;
|
|
}
|
|
|
|
static bool st67w6_spi_init(void);
|
|
bool mg_to_size_t(struct mg_str str, size_t *val);
|
|
|
|
static bool st67w6_init(uint8_t *mac) {
|
|
// struct mg_tcpip_driver_st67w6_data *d = (struct
|
|
// mg_tcpip_driver_st67w6_data *) s_ifp->driver_data;
|
|
struct mg_str data[3];
|
|
size_t val;
|
|
bool is_b = false;
|
|
if (!st67w6_spi_init()) return false;
|
|
if (!st67w6_at_cmd("AT\r\n", 4)) return false;
|
|
if (!st67w6_at_cmd("AT+CWNETMODE?\r\n", 15) ||
|
|
!mg_match(mg_str_n((char *) at_resp, s_at_resp_len),
|
|
mg_str_n("*:*\r\n*", 6), data) ||
|
|
!mg_to_size_t(data[1], &val))
|
|
return false;
|
|
if (val != 0) {
|
|
MG_ERROR(("Wrong firmware, T02 is needed"));
|
|
return false;
|
|
}
|
|
// set clock, who cares ???
|
|
if (!st67w6_at_cmd("AT+GET_CLOCK\r\n", 14)) return false;
|
|
MG_DEBUG(("%.*s", s_at_resp_len, at_resp)); // TODO(scaprile): --> VERBOSE
|
|
// BT-ENABLED DEPENDENCY
|
|
|
|
// MODULE DEPENDENCY
|
|
if (!st67w6_at_cmd("AT+EFUSE-R=24,\"0x100\"\r\n", 23) ||
|
|
!mg_match(mg_str_n((char *) at_resp, s_at_resp_len), mg_str_n("*,*", 3),
|
|
data))
|
|
return false;
|
|
if (data[1].buf[0] == 'C' && data[1].buf[1] == '6') is_b = true;
|
|
MG_DEBUG(("WLAN module is %sB type", is_b ? "" : "not")); // --> VERBOSE
|
|
if (is_b) {
|
|
// Disable the antenna diversity pin
|
|
if (!st67w6_at_cmd("AT+IORST=0\r\n", 12)) return false;
|
|
// Apparently they intend to disable some antenna ...
|
|
if (!st67w6_at_cmd("AT+CWANTENABLE?\r\n", 17)) return false;
|
|
MG_DEBUG(("%.*s", s_at_resp_len, at_resp)); // --> VERBOSE
|
|
}
|
|
|
|
// Do not set wake-up pin (AT+SLWKIO)
|
|
// Disable power save mode
|
|
// NOTE(scaprile): (no response if in hibernate mode, though I guess we
|
|
// wouldn't have reached this point in that case either)
|
|
if (!st67w6_at_cmd("AT+PWR=0\r\n", 12)) return false;
|
|
// set Wi-Fi
|
|
// set country code
|
|
if (!st67w6_at_cmd("AT+CWCOUNTRY=0,\"00\"\r\n", 21)) return false;
|
|
#if 0
|
|
// set DTIM
|
|
if (!st67w6_at_cmd("AT+SLWKDTIM=1\r\n", 15)) return false;
|
|
#endif
|
|
// Read only default MAC, ignore set bit count (data[6] & 0x3F). Custom MACs
|
|
// reside at @0x64 and 0x70
|
|
if (st67w6_at_cmd("AT+EFUSE-R=7,\"0x014\"\r\n", 22) &&
|
|
mg_match(mg_str_n((char *) at_resp, s_at_resp_len), mg_str_n("*,*", 3),
|
|
data)) {
|
|
int i;
|
|
for (i = 0; i < 6; i++) mac[i] = data[1].buf[5 - i];
|
|
MG_DEBUG(("MAC: %M", mg_print_mac, mac));
|
|
} else {
|
|
MG_ERROR(("read MAC failed"));
|
|
}
|
|
return true;
|
|
}
|
|
|
|
static void st67w6_update_hash_table(void) {
|
|
// TODO(): read database, rebuild hash table
|
|
// uint32_t val = 0;
|
|
// val = 1;
|
|
// st67w6_at_iovar_set2_(0, "mcast_list", (uint8_t *) &val, sizeof(val),
|
|
// (uint8_t *) mcast_addr, sizeof(mcast_addr)); mg_delayms(50);
|
|
}
|
|
|
|
// SPI specifics
|
|
|
|
#define ST67W6_SPI_MAGIC 0x55AA
|
|
// #define ST67W6_SPI_VERSION(x), IS_STALL, FLAGS(x), ...
|
|
|
|
static const uint8_t idlehdr[sizeof(struct spi_hdr)] = {0xaa, 0x55, 0, 0,
|
|
0, 0, 0, 0};
|
|
|
|
static void st67w6_write(unsigned int f, void *data, uint16_t len) {
|
|
struct spi_hdr *h = (struct spi_hdr *) txdata;
|
|
h->magic = ST67W6_SPI_MAGIC;
|
|
h->type = (uint8_t) f;
|
|
h->vflags = 0;
|
|
h->len = len;
|
|
h->reserved = 0;
|
|
memmove(h + 1, data, len);
|
|
}
|
|
|
|
static size_t st67w6_spi_poll(uint8_t *write, uint8_t *read) {
|
|
struct mg_tcpip_driver_st67w6_data *d =
|
|
(struct mg_tcpip_driver_st67w6_data *) s_ifp->driver_data;
|
|
struct spi_hdr *th, *rh = (struct spi_hdr *) read;
|
|
struct mg_tcpip_spi *s = (struct mg_tcpip_spi *) d->spi;
|
|
size_t padded;
|
|
unsigned int times;
|
|
|
|
th = (write != NULL) ? (struct spi_hdr *) write : (struct spi_hdr *) idlehdr;
|
|
s->begin(s->spi);
|
|
times = 50;
|
|
while (times--) {
|
|
if (d->is_ready()) break;
|
|
if (times == 0) {
|
|
MG_ERROR(("RDY TIMEOUT"));
|
|
s->end(s->spi);
|
|
return 0;
|
|
}
|
|
mg_delayms(1);
|
|
}
|
|
|
|
padded = (th->len + 3) & ~3;
|
|
s->txn(s->spi, (uint8_t *) th, (uint8_t *) rh, sizeof(*th) + padded);
|
|
if (rh->magic == ST67W6_SPI_MAGIC && rh->len > padded) {
|
|
size_t remaining_padded = (rh->len - padded + 3) & ~3;
|
|
if (remaining_padded > (2048 - sizeof(*rh) - padded))
|
|
remaining_padded = 2048 - sizeof(*rh) - padded;
|
|
s->txn(s->spi, NULL, read + sizeof(*rh) + padded, remaining_padded);
|
|
}
|
|
times = 50;
|
|
while (times--) {
|
|
if (!d->is_ready()) break;
|
|
if (times == 0) {
|
|
MG_ERROR(("!RDY TIMEOUT"));
|
|
break;
|
|
}
|
|
mg_delayms(1);
|
|
}
|
|
s->end(s->spi);
|
|
return (size_t) rh->len;
|
|
}
|
|
|
|
static bool st67w6_spi_init(void) {
|
|
struct mg_tcpip_driver_st67w6_data *d =
|
|
(struct mg_tcpip_driver_st67w6_data *) s_ifp->driver_data;
|
|
size_t len;
|
|
unsigned int times = 1000;
|
|
while (times--) {
|
|
if (d->is_ready()) break;
|
|
if (times == 0) return false;
|
|
mg_delayms(1);
|
|
}
|
|
if (((len = st67w6_spi_poll(NULL, (uint8_t *) rxdata)) == 0) ||
|
|
!mg_match(mg_str_n(((char *) rxdata) + sizeof(struct spi_hdr), len),
|
|
mg_str_n("*ready*", 7), NULL))
|
|
return false;
|
|
return true;
|
|
}
|
|
|
|
// Mongoose Wi-Fi API functions
|
|
|
|
bool mg_wifi_scan(void) {
|
|
return st67w6_wifi_scan();
|
|
}
|
|
|
|
bool mg_wifi_connect(struct mg_wifi_data *wifi) {
|
|
s_ifp->ip = s_ip;
|
|
s_ifp->mask = s_mask;
|
|
if (s_ifp->ip == 0) s_ifp->enable_dhcp_client = true;
|
|
s_ifp->enable_dhcp_server = false;
|
|
MG_DEBUG(("Connecting to '%s'", wifi->ssid));
|
|
return st67w6_wifi_connect(wifi->ssid, wifi->pass);
|
|
}
|
|
|
|
bool mg_wifi_disconnect(void) {
|
|
return st67w6_wifi_disconnect();
|
|
}
|
|
|
|
bool mg_wifi_ap_start(struct mg_wifi_data *wifi) {
|
|
MG_DEBUG(("Starting AP '%s' (%u)", wifi->apssid, wifi->apchannel));
|
|
return st67w6_wifi_ap_start(wifi->apssid, wifi->appass, wifi->apchannel);
|
|
}
|
|
|
|
bool mg_wifi_ap_stop(void) {
|
|
return st67w6_wifi_ap_stop();
|
|
}
|
|
|
|
#endif
|