implement TS console over ATWINC1500 WiFi

This commit is contained in:
Matthew Kennedy 2024-03-01 15:37:55 -05:00 committed by rusefillc
parent 3b671b8c55
commit 24c1b78ecd
12 changed files with 625 additions and 11 deletions

View File

@ -218,6 +218,11 @@ ifeq ($(USE_FATFS),yes)
include $(PROJECT_DIR)/ext/FatFS/fatfs.mk
endif
ifeq ($(USE_WIFI),yes)
include $(PROJECT_DIR)/ext/atwinc1500/atwinc1500.mk
DDEFS += -DEFI_WIFI=1
endif
include $(PROJECT_DIR)/hw_layer/mass_storage/mass_storage.mk
include $(PROJECT_DIR)/common.mk

View File

@ -1,3 +1,6 @@
# Atlas is STM32H743
PROJECT_CPU = ARCH_STM32H7
# List of all the board related files.
BOARDCPPSRC = $(BOARD_DIR)/board_configuration.cpp
@ -11,11 +14,7 @@ DDEFS += -DFIRMWARE_ID=\"atlas\"
# We are running on Atlas hardware!
DDEFS += -DHW_ATLAS=1
# Atlas needs networking library
LWIP = yes
ALLOW_SHADOW = yes
DDEFS += -DEFI_TCU=TRUE
DDEFS += -DCH_CFG_USE_DYNAMIC=TRUE
DDEFS += -DEFI_ETHERNET=TRUE
DDEFS += -DSTATIC_BOARD_ID=STATIC_BOARD_ID_ATLAS
# Atlas has WiFi
USE_WIFI = yes
SHORT_BOARD_NAME = atlas

View File

@ -13,4 +13,26 @@ Gpio getWarningLedPin() {
Gpio getRunningLedPin() {
// this board has no running led
return Gpio::Unassigned;
}
}
spi_device_e getWifiSpiDevice() {
return SPI_DEVICE_4;
}
Gpio getWifiCsPin() {
return Gpio::E4;
}
Gpio getWifiResetPin() {
return Gpio::E1;
}
Gpio getWifiIsrPin() {
return Gpio::E3;
}
void setBoardConfigOverrides() {
engineConfiguration->is_enabled_spi_4 = true;
engineConfiguration->spi4sckPin = Gpio::E2;
engineConfiguration->spi4misoPin = Gpio::E5;
engineConfiguration->spi4mosiPin = Gpio::E6;
}

View File

@ -10,6 +10,7 @@ CONSOLE_SRC_CPP = $(CONSOLE_COMMON_SRC_CPP) \
$(PROJECT_DIR)/console/binary_log/binary_logging.cpp \
$(PROJECT_DIR)/console/binary_log/usb_console.cpp \
$(PROJECT_DIR)/console/binary_log/ethernet_console.cpp \
$(PROJECT_DIR)/console/wifi_console.cpp \
CONSOLE_INC=\

View File

@ -14,3 +14,4 @@ void startUsbConsole();
void printUsbConnectorStats();
void startEthernetConsole();
void startWifiConsole();

View File

@ -0,0 +1,218 @@
#include "pch.h"
#if EFI_WIFI
#include "driver/include/m2m_wifi.h"
#include "socket/include/socket.h"
#include "thread_controller.h"
#include "tunerstudio.h"
static int listenerSocket = -1;
static int connectionSocket = -1;
chibios_rt::BinarySemaphore isrSemaphore(/* taken =*/ true);
void os_hook_isr() {
isrSemaphore.signalI();
}
// TX Helper data
static const uint8_t* sendBuffer;
static size_t sendSize;
bool sendRequest = false;
chibios_rt::BinarySemaphore sendDoneSemaphore(/* taken =*/ true);
// RX Helper data
static uint8_t recvBuffer[512];
static input_queue_t wifiIqueue;
static bool socketReady = false;
class WifiChannel : public TsChannelBase {
public:
WifiChannel()
: TsChannelBase("WiFi")
{
}
bool isReady() const override {
return true;
}
void write(const uint8_t* buffer, size_t size, bool /*isEndOfPacket*/) override {
sendBuffer = buffer;
sendSize = size;
sendRequest = true;
isrSemaphore.signal();
sendDoneSemaphore.wait();
}
size_t readTimeout(uint8_t* buffer, size_t size, int timeout) override {
return iqReadTimeout(&wifiIqueue, buffer, size, timeout);
}
};
static WifiChannel wifiChannel;
class WifiHelperThread : public ThreadController<4096> {
public:
WifiHelperThread() : ThreadController("WiFi", WIFI_THREAD_PRIORITY) {}
void ThreadTask() override {
while (true)
{
m2m_wifi_handle_events(nullptr);
if (socketReady && sendRequest) {
send(connectionSocket, (void*)sendBuffer, sendSize, 0);
sendRequest = false;
} else {
isrSemaphore.wait(TIME_MS2I(1));
}
}
}
};
static WifiHelperThread wifiHelper;
static tstrWifiInitParam param;
static tstrM2MAPConfig apConfig;
void wifiCallback(uint8 u8MsgType, void* pvMsg) {
switch (u8MsgType) {
case M2M_WIFI_REQ_DHCP_CONF: {
auto& dhcpInfo = *reinterpret_cast<tstrM2MIPConfig*>(pvMsg);
uint8_t* addr = reinterpret_cast<uint8_t*>(&dhcpInfo.u32StaticIP);
efiPrintf("WiFi client connected DHCP IP is %d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
} break;
default:
efiPrintf("WifiCallback: %d", (int)u8MsgType);
break;
}
}
uint8_t rxBuf[512];
static void socketCallback(SOCKET sock, uint8_t u8Msg, void* pvMsg) {
switch (u8Msg) {
case SOCKET_MSG_BIND: {
auto bindMsg = reinterpret_cast<tstrSocketBindMsg*>(pvMsg);
if (bindMsg && bindMsg->status == 0) {
// Socket bind complete, now listen!
listen(sock, 1);
}
} break;
case SOCKET_MSG_LISTEN: {
auto listenMsg = reinterpret_cast<tstrSocketListenMsg*>(pvMsg);
if (listenMsg && listenMsg->status == 0) {
// Listening, now accept a connection
accept(sock, nullptr, nullptr);
}
} break;
case SOCKET_MSG_ACCEPT: {
auto acceptMsg = reinterpret_cast<tstrSocketAcceptMsg*>(pvMsg);
if (acceptMsg && (acceptMsg->sock >= 0)) {
connectionSocket = acceptMsg->sock;
recv(connectionSocket, &rxBuf, 1, 0);
socketReady = true;
}
} break;
case SOCKET_MSG_RECV: {
auto recvMsg = reinterpret_cast<tstrSocketRecvMsg*>(pvMsg);
if (recvMsg && (recvMsg->s16BufferSize > 0)) {
{
chibios_rt::CriticalSectionLocker csl;
for (size_t i = 0; i < recvMsg->s16BufferSize; i++) {
iqPutI(&wifiIqueue, rxBuf[i]);
}
}
size_t nextRecv;
if (recvMsg->u16RemainingSize < 1) {
// Always try to read at least 1 byte
nextRecv = 1;
} else if (recvMsg->u16RemainingSize > sizeof(rxBuf)) {
// Remaining is too big for the buffer, so just read one buffer worth
nextRecv = sizeof(rxBuf);
} else {
// The full thing will fit, try to read it
nextRecv = recvMsg->u16RemainingSize;
}
// start the next recv
recv(sock, &rxBuf, nextRecv, 0);
} else {
close(sock);
socketReady = false;
}
} break;
case SOCKET_MSG_SEND: {
// Send completed, notify caller!
chibios_rt::CriticalSectionLocker csl;
sendDoneSemaphore.signalI();
} break;
}
}
struct WifiConsoleThread : public TunerstudioThread {
WifiConsoleThread() : TunerstudioThread("WiFi Console") { }
TsChannelBase* setupChannel() override {
// Initialize the WiFi module
param.pfAppWifiCb = wifiCallback;
if (M2M_SUCCESS != m2m_wifi_init(&param)) {
return nullptr;
}
strcpy(apConfig.au8SSID, "FOME EFI");
apConfig.u8ListenChannel = 1;
apConfig.u8SecType = M2M_WIFI_SEC_OPEN;
apConfig.u8SsidHide = 0;
// IP Address
apConfig.au8DHCPServerIP[0] = 192;
apConfig.au8DHCPServerIP[1] = 168;
apConfig.au8DHCPServerIP[2] = 1;
apConfig.au8DHCPServerIP[3] = 1;
// Trigger AP
if (M2M_SUCCESS != m2m_wifi_enable_ap(&apConfig)) {
return nullptr;
}
// Start the helper thread
wifiHelper.start();
// Set up the socket APIs
socketInit();
registerSocketCallback(socketCallback, nullptr);
// Start listening on the socket
sockaddr_in address;
address.sin_family = AF_INET;
address.sin_port = _htons(17999);
address.sin_addr.s_addr = 0;
listenerSocket = socket(AF_INET, SOCK_STREAM, SOCKET_CONFIG_SSL_OFF);
bind(listenerSocket, (sockaddr*)&address, sizeof(address));
return &wifiChannel;
}
};
static WifiConsoleThread wifiThread;
void startWifiConsole() {
iqObjectInit(&wifiIqueue, recvBuffer, sizeof(recvBuffer), nullptr, nullptr);
wifiThread.start();
}
#endif // EFI_WIFI

View File

@ -0,0 +1,191 @@
#include "spi_flash/include/spi_flash.h"
#include "usbcfg.h"
static bool isBigEndian() {
uint32_t test = 0x11223344;
uint8_t *pTest = reinterpret_cast<uint8_t *>(&test);
return pTest[0] == 0x11;
}
static uint32_t fromNetwork32(uint32_t from) {
static const bool be = isBigEndian();
if (be) {
return from;
} else {
uint8_t *pFrom = reinterpret_cast<uint8_t *>(&from);
uint32_t to;
to = pFrom[0]; to <<= 8;
to |= pFrom[1]; to <<= 8;
to |= pFrom[2]; to <<= 8;
to |= pFrom[3];
return to;
}
}
static uint16_t fromNetwork16(uint16_t from) {
static bool be = isBigEndian();
if (be) {
return from;
} else {
uint8_t *pFrom = reinterpret_cast<uint8_t *>(&from);
uint16_t to;
to = pFrom[0]; to <<= 8;
to |= pFrom[1];
return to;
}
}
static uint32_t toNetwork32(uint32_t to) {
return fromNetwork32(to);
}
static uint16_t toNetwork16(uint16_t to) {
return fromNetwork16(to);
}
typedef struct __attribute__((__packed__)) {
uint8_t command;
uint32_t address;
uint32_t arg1;
uint16_t payloadLength;
// payloadLenght bytes of data follows...
} UartPacket;
static const int MAX_PAYLOAD_SIZE = 256;
#define CMD_READ_FLASH 0x01
#define CMD_WRITE_FLASH 0x02
#define CMD_ERASE_FLASH 0x03
#define CMD_MAX_PAYLOAD_SIZE 0x50
#define CMD_HELLO 0x99
static int readch() {
uint8_t buf;
int ret = chnReadTimeout(&SDU1, &buf, 1, TIME_MS2I(1));
if (ret == 0) {
return -1;
} else {
return (int)buf;
}
}
static void receivePacket(UartPacket *pkt, uint8_t *payload) {
// Read command
uint8_t *p = reinterpret_cast<uint8_t *>(pkt);
uint16_t l = sizeof(UartPacket);
while (l > 0) {
int c = readch();
if (c == -1)
continue;
*p++ = c;
l--;
}
// Convert parameters from network byte order to cpu byte order
pkt->address = fromNetwork32(pkt->address);
pkt->arg1 = fromNetwork32(pkt->arg1);
pkt->payloadLength = fromNetwork16(pkt->payloadLength);
// Read payload
l = pkt->payloadLength;
while (l > 0) {
int c = readch();
if (c == -1)
continue;
*payload++ = c;
l--;
}
}
// Allocated statically so the compiler can tell us
// about the amount of used RAM
static UartPacket pkt;
static uint8_t payload[MAX_PAYLOAD_SIZE];
static void serialPrint(const uint8_t* data, size_t length) {
chnWriteTimeout(&SDU1, data, length, TIME_MS2I(100));
}
static void serialPrintStr(const char* str) {
size_t len = strlen(str);
serialPrint(reinterpret_cast<const uint8_t*>(str), len);
}
struct WifiUpdaterThread : public ThreadController<4096> {
WifiUpdaterThread() : ThreadController("WifiPump", NORMALPRIO - 10) {}
void ThreadTask() override {
if (M2M_SUCCESS != m2m_wifi_download_mode()) {
return;
}
auto flashSize = spi_flash_get_size();
(void)flashSize;
//int ret = spi_flash_erase(0, FLASH_SECTOR_SZ);
//(void)ret;
usb_serial_start();
while (true) {
while (!is_usb_serial_ready()) {
chThdSleepMilliseconds(1);
}
receivePacket(&pkt, payload);
if (pkt.command == CMD_HELLO) {
if (pkt.address == 0x11223344 && pkt.arg1 == 0x55667788) {
serialPrintStr("v10000");
}
}
if (pkt.command == CMD_MAX_PAYLOAD_SIZE) {
uint16_t res = toNetwork16(MAX_PAYLOAD_SIZE);
serialPrint(reinterpret_cast<uint8_t *>(&res), sizeof(res));
}
if (pkt.command == CMD_READ_FLASH) {
uint32_t address = pkt.address;
uint32_t len = pkt.arg1;
if (spi_flash_read(payload, address, len) != M2M_SUCCESS) {
serialPrintStr("ER");
} else {
serialPrint(payload, len);
serialPrintStr("OK");
}
}
if (pkt.command == CMD_WRITE_FLASH) {
uint32_t address = pkt.address;
uint32_t len = pkt.payloadLength;
if (spi_flash_write(payload, address, len) != M2M_SUCCESS) {
serialPrintStr("ER");
} else {
serialPrintStr("OK");
}
}
if (pkt.command == CMD_ERASE_FLASH) {
uint32_t address = pkt.address;
uint32_t len = pkt.arg1;
if (spi_flash_erase(address, len) != M2M_SUCCESS) {
serialPrintStr("ER");
// serialPrintStr("OK");
} else {
serialPrintStr("OK");
}
}
}
}
};
static WifiUpdaterThread wifiUpdater;
void startWifiUpdater() {
wifiUpdater.start();
}

View File

@ -32,6 +32,8 @@
// Console thread
#define PRIO_CONSOLE (NORMALPRIO + 1)
#define WIFI_THREAD_PRIORITY (NORMALPRIO)
// Less important things
#define PRIO_MMC (NORMALPRIO - 1)

View File

@ -0,0 +1,11 @@
#pragma once
#include <stddef.h>
#include <stdbool.h>
void* malloc(size_t);
void free(void*);
#define min(a, b) ((a)<(b)?(a):(b))
// TODO: what is this for?

View File

@ -0,0 +1,156 @@
#include "pch.h"
#if EFI_WIFI
#include "ch.h"
#include "hal.h"
#include "digital_input_exti.h"
#include "bus_wrapper/include/nm_bus_wrapper.h"
// Implement these functions for your board for WiFi to work!
spi_device_e getWifiSpiDevice();
Gpio getWifiCsPin();
Gpio getWifiResetPin();
Gpio getWifiIsrPin();
void nm_bsp_sleep(uint32 u32TimeMsec) {
chThdSleepMilliseconds(u32TimeMsec);
}
static tpfNmBspIsr gpfIsr = nullptr;
static void isrAdapter(void*, efitick_t) {
if (gpfIsr) {
gpfIsr();
}
}
static bool isrEnabled = false;
void nm_bsp_interrupt_ctrl(uint8 u8Enable) {
if (u8Enable && !isrEnabled) {
efiExtiEnablePin("WiFi ISR", getWifiIsrPin(), PAL_EVENT_MODE_FALLING_EDGE, isrAdapter, nullptr);
isrEnabled = true;
} else if (!u8Enable && isrEnabled) {
efiExtiDisablePin(getWifiIsrPin());
isrEnabled = false;
}
}
void nm_bsp_register_isr(tpfNmBspIsr pfIsr) {
gpfIsr = pfIsr;
nm_bsp_interrupt_ctrl(1);
}
static SPIDriver* wifiSpi = nullptr;
tstrNmBusCapabilities egstrNmBusCapabilities = { .u16MaxTrxSz = 4096 };
#ifdef STM32H7XX
// H7 SPI clock is set to 80MHz
// fast mode is 80mhz/2 = 40MHz
SPIConfig wifi_spicfg = {
.circular = false,
.end_cb = NULL,
.ssport = NULL,
.sspad = 0,
.cfg1 = 7 // 8 bits per byte
| 0 /* MBR = 0, divider = 2 */,
.cfg2 = 0
};
#else // Not H7, ie F4/F7
// 168mhz F4: 42 or 21 MHz depending on which SPI device
// 216mhz F7: 54 or 27 MHz depending on whcih SPI device
static SPIConfig wifi_spicfg = {
.circular = false,
.end_cb = NULL,
.ssport = NULL,
.sspad = 0,
.cr1 = SPI_BaudRatePrescaler_2,
.cr2 = 0
};
#endif
static OutputPin wifiCs;
static OutputPin wifiReset;
sint8 nm_bus_init(void*) {
auto spi = getWifiSpiDevice();
if (spi == SPI_NONE) {
return M2M_ERR_BUS_FAIL;
}
// Set up chip select, reset
wifiCs.initPin("WiFi CS", getWifiCsPin());
wifiCs.setValue(1);
wifiReset.initPin("WiFi RST", getWifiResetPin());
// Reset the chip
wifiReset.setValue(0);
chThdSleepMilliseconds(10);
wifiReset.setValue(1);
chThdSleepMilliseconds(10);
// Set up SPI
wifiSpi = getSpiDevice(getWifiSpiDevice());
wifi_spicfg.ssport = wifiCs.m_port;
wifi_spicfg.sspad = wifiCs.m_pin;
spiStart(wifiSpi, &wifi_spicfg);
// Take exclusive access of the bus for WiFi use, don't release it until the bus is de-init.
spiAcquireBus(wifiSpi);
return M2M_SUCCESS;
}
sint8 nm_bus_deinit(void) {
spiReleaseBus(wifiSpi);
spiStop(wifiSpi);
return M2M_SUCCESS;
}
sint8 nm_bus_speed(uint8 /*level*/) {
// Do we even need to do anything here?
return M2M_SUCCESS;
}
sint8 nm_spi_rw(uint8* pu8Mosi, uint8* pu8Miso, uint16 u16Sz) {
spiSelectI(wifiSpi);
if (u16Sz < 16) {
for (size_t i = 0; i < u16Sz; i++) {
uint8 tx = pu8Mosi ? pu8Mosi[i] : 0;
uint8 rx = spiPolledExchange(wifiSpi, tx);
if (pu8Miso) {
pu8Miso[i] = rx;
}
}
} else {
if (pu8Mosi && pu8Miso) {
spiExchange(wifiSpi, u16Sz, pu8Mosi, pu8Miso);
} else if (pu8Mosi) {
spiSend(wifiSpi, u16Sz, pu8Mosi);
} else if (pu8Miso) {
spiReceive(wifiSpi, u16Sz, pu8Miso);
} else {
// Neither MISO nor MOSI???
osalSysHalt("wifi neither mosi nor miso");
}
}
spiUnselectI(wifiSpi);
return M2M_SUCCESS;
}
#endif // EFI_WIFI

View File

@ -3,9 +3,11 @@ HW_LAYER_INC= $(PROJECT_DIR)/hw_layer $(PROJECT_DIR)/hw_layer/adc \
$(PROJECT_DIR)/hw_layer/digital_input \
$(PROJECT_DIR)/hw_layer/digital_input/trigger \
$(PROJECT_DIR)/hw_layer/microsecond_timer \
$(PROJECT_DIR)/hw_layer/atwinc1500 \
HW_INC = hw_layer/$(CPU_HWLAYER) \
$(PROJECT_DIR)/hw_layer/ports
$(PROJECT_DIR)/hw_layer/ports \
HW_LAYER_CPP = \
$(PROJECT_DIR)/hw_layer/pin_repository.cpp \
@ -30,7 +32,10 @@ HW_LAYER_CPP = \
$(PROJECT_DIR)/hw_layer/rtc_helper.cpp \
$(PROJECT_DIR)/hw_layer/cdm_ion_sense.cpp \
$(PROJECT_DIR)/hw_layer/debounce.cpp \
$(PROJECT_DIR)/hw_layer/adc/mcp3208.cpp
$(PROJECT_DIR)/hw_layer/adc/mcp3208.cpp \
$(PROJECT_DIR)/hw_layer/atwinc1500/wifi_bsp.cpp \
ifeq ($(USE_OPENBLT),yes)
HW_LAYER += \
@ -39,6 +44,6 @@ endif
#
# '-include' is a magic kind of 'include' which would survive if file to be included is not found
#
#
-include $(PROJECT_DIR)/hw_layer/$(CPU_HWLAYER)/hw_ports.mk

View File

@ -258,6 +258,9 @@ void runRusEfiWithConfig() {
commonEarlyInit();
#if EFI_WIFI
startWifiConsole();
#endif
// Config could be completely bogus - don't start anything else!
if (validateConfig()) {