diff --git a/inc/config.h b/inc/config.h
index 9aad9d35..9780dc29 100644
--- a/inc/config.h
+++ b/inc/config.h
@@ -160,7 +160,7 @@
* Set it to 1 if you want to enable the TTY text console module (written by Andreas Dietrich).
* It consume about 34 bytes of memory when enabled.
*/
-#define MODULE_CONSOLE 1
+#define MODULE_CONSOLE 0
#endif // _CONFIG_
diff --git a/inc/ext/mw/16c550.h b/inc/ext/mw/16c550.h
index 6e5754a1..dd066bc1 100644
--- a/inc/ext/mw/16c550.h
+++ b/inc/ext/mw/16c550.h
@@ -1,184 +1,193 @@
-/************************************************************************//**
- * \brief Simple 16C550 UART chip driver.
- *
- * \author Jesus Alonso (doragasu)
- * \date 2016
- * \defgroup 16C550 16c550
- * \{
- ****************************************************************************/
-
-#ifndef _16C550_H_
-#define _16C550_H_
-
-#include "types.h"
-
-#if (MODULE_MEGAWIFI != 0)
-
-/// 16C550 UART base address
-#define UART_BASE 0xA130C1
-
-/// Clock applied to 16C550 chip. Currently using 24 MHz crystal
-#define UART_CLK 24000000LU
-
-/// Desired baud rate. Maximum achievable baudrate with 24 MHz crystal
-/// is 24000000/16 = 1.5 Mbps
-#define UART_BR 1500000LU
-//#define UART_BR 500000LU
-//#define UART_BR 750000LU
-//#define UART_BR 115200
-
-/// Length of the TX FIFO in bytes
-#define UART_TX_FIFO_LEN 16
-
-/// Division with one bit rounding, useful for divisor calculations.
-#define DivWithRounding(dividend, divisor) ((((dividend)*2/(divisor))+1)/2)
-/// Value to load on the UART divisor, high byte
-#define UART_DLM_VAL (DivWithRounding(UART_CLK, 16 * UART_BR)>>8)
-//#define UART_DLM_VAL ((UART_CLK/16/UART_BR)>>8)
-/// Value to load on the UART divisor, low byte
-#define UART_DLL_VAL (DivWithRounding(UART_CLK, 16 * UART_BR) & 0xFF)
-//#define UART_DLL_VAL ((UART_CLK/16/UART_BR)&0xFF)
-
-/** \addtogroup UartRegs UartRegs
- * \brief 16C550 UART registers
- * \note Do NOT access IER, FCR, LCR and MCR directly, use Set/Get functions.
- * Remaining registers can be directly accessed, but meeting the
- * read only/write only restrictions.
- * \{
- */
-/// Receiver holding register. Read only.
-#define UART_RHR (*((volatile uint8_t*)(UART_BASE + 0)))
-/// Transmit holding register. Write only.
-#define UART_THR (*((volatile uint8_t*)(UART_BASE + 0)))
-/// Interrupt enable register. Write only.
-#define UART_IER (*((volatile uint8_t*)(UART_BASE + 2)))
-/// FIFO control register. Write only.
-#define UART_FCR (*((volatile uint8_t*)(UART_BASE + 4)))
-/// Interrupt status register. Read only.
-#define UART_ISR (*((volatile uint8_t*)(UART_BASE + 4)))
-/// Line control register. Write only.
-#define UART_LCR (*((volatile uint8_t*)(UART_BASE + 6)))
-/// Modem control register. Write only.
-#define UART_MCR (*((volatile uint8_t*)(UART_BASE + 8)))
-/// Line status register. Read only.
-#define UART_LSR (*((volatile uint8_t*)(UART_BASE + 10)))
-/// Modem status register. Read only.
-#define UART_MSR (*((volatile uint8_t*)(UART_BASE + 12)))
-/// Scratchpad register.
-#define UART_SPR (*((volatile uint8_t*)(UART_BASE + 14)))
-/// Divisor latch LSB. Acessed only when LCR[7] = 1.
-#define UART_DLL (*((volatile uint8_t*)(UART_BASE + 0)))
-/// Divisor latch MSB. Acessed only when LCR[7] = 1.
-#define UART_DLM (*((volatile uint8_t*)(UART_BASE + 2)))
-/** \} */
-
-/// Structure with the shadow registers.
-typedef struct {
- uint8_t IER; ///< Interrupt Enable Register
- uint8_t FCR; ///< FIFO Control Register
- uint8_t LCR; ///< Line Control Register
- uint8_t MCR; ///< Modem Control Register
-} UartShadow;
-
-/// Uart shadow registers. Do NOT access directly!
-extern UartShadow sh;
-
-/** \addtogroup UartOuts UartOuts
- * \brief Output pins controlled by the MCR UART
- * register.
- * \{ */
-#define UART_MCR__DTR 0x01 ///< Data Terminal Ready.
-#define UART_MCR__RTS 0x02 ///< Request To Send.
-#define UART_MCR__OUT1 0x04 ///< GPIO pin 1.
-#define UART_MCR__OUT2 0x08 ///< GPIO pin 2.
-/** \} */
-
-/** \addtogroup UartIns UartIns
- * \brief Input pins readed in the MSR UART register.
- * \{ */
-#define UART_MSR__DSR 0x20 ///< Data Set Ready
-/** \} */
-
-/************************************************************************//**
- * \brief Initializes the driver. The baud rate is set to UART_BR, and the
- * UART FIFOs are enabled. This function must be called before using
- * any other API call.
- ****************************************************************************/
-void uart_init(void);
-
-/************************************************************************//**
- * \brief Checks if UART transmit register/FIFO is ready. In FIFO mode, up to
- * 16 characters can be loaded each time transmitter is ready.
- *
- * \return TRUE if transmitter is ready, FALSE otherwise.
- ****************************************************************************/
-#define uart_tx_ready() (UART_LSR & 0x20)
-
-/************************************************************************//**
- * \brief Checks if UART receive register/FIFO has data available.
- *
- * \return TRUE if at least 1 byte is available, FALSE otherwise.
- ****************************************************************************/
-#define uart_rx_ready() (UART_LSR & 0x01)
-
-/************************************************************************//**
- * \brief Sends a character. Please make sure there is room in the transmit
- * register/FIFO by calling uart_rx_ready() before using this function.
- *
- * \return Received character.
- ****************************************************************************/
-#define uart_putc(c) do{UART_RHR = (c);}while(0);
-
-/************************************************************************//**
- * \brief Returns a received character. Please make sure data is available by
- * calling uart_rx_ready() before using this function.
- *
- * \return Received character.
- ****************************************************************************/
-#define uart_getc() (UART_RHR)
-
-/************************************************************************//**
- * \brief Sets a value in IER, FCR, LCR or MCR register.
- *
- * \param[in] reg Register to modify (IER, FCR, LCR or MCR).
- * \param[in] val Value to set in IER, FCR, LCR or MCR register.
- ****************************************************************************/
-#define uart_set(reg, val) do{sh.reg = (val);UART_##reg = (val);}while(0)
-
-/************************************************************************//**
- * \brief Gets value of IER, FCR, LCR or MCR register.
- *
- * \param[in] reg Register to read (IER, FCR, LCR or MCR).
- * \return The value of the requested register.
- ****************************************************************************/
-#define uart_get(reg) (sh.reg)
-
-/************************************************************************//**
- * \brief Sets bits in IER, FCR, LCR or MCR register.
- *
- * \param[in] reg Register to modify (IER, FCR, LCR or MCR).
- * \param[in] val Bits set in val, will be set in reg register.
- ****************************************************************************/
-#define uart_set_bits(reg, val) do{sh.reg |= (val); \
- UART_##reg = sh.reg;}while(0)
-
-/************************************************************************//**
- * \brief Clears bits in IER, FCR, LCR or MCR register.
- *
- * \param[in] reg Register to modify (IER, FCR, LCR or MCR).
- * \param[in] val Bits set in val, will be cleared in reg register.
- ****************************************************************************/
-#define uart_clr_bits(reg, val) do{sh.reg &= ~(val); \
- UART_##reg = sh.reg;}while(0)
-
-/************************************************************************//**
- * \brief Reset TX and RX FIFOs.
- ****************************************************************************/
-#define uart_reset_fifos() uart_set_bits(FCR, 0x07)
-
-#endif // MODULE_MEGAWIFI
-
-#endif /*_16C550_H_*/
-
-/** \} */
-
+/************************************************************************//**
+ * \brief Simple 16C550 UART chip driver.
+ *
+ * \author Jesus Alonso (doragasu)
+ * \date 2016
+ * \defgroup 16C550 16c550
+ * \{
+ ****************************************************************************/
+
+#ifndef _16C550_H_
+#define _16C550_H_
+
+#include "types.h"
+
+#if (MODULE_MEGAWIFI == 1 && MODULE_EVERDRIVE == 0)
+
+/// 16C550 UART base address
+#define UART_BASE 0xA130C1
+
+/// Clock applied to 16C550 chip. Currently using 24 MHz crystal
+#define UART_CLK 24000000LU
+
+/// Desired baud rate. Maximum achievable baudrate with 24 MHz crystal
+/// is 24000000/16 = 1.5 Mbps
+#define UART_BR 1500000LU
+//#define UART_BR 500000LU
+//#define UART_BR 750000LU
+//#define UART_BR 115200
+
+/// Length of the TX FIFO in bytes
+#define UART_TX_FIFO_LEN 16
+
+/// Division with one bit rounding, useful for divisor calculations.
+#define DivWithRounding(dividend, divisor) ((((dividend)*2/(divisor))+1)/2)
+/// Value to load on the UART divisor, high byte
+#define UART_DLM_VAL (DivWithRounding(UART_CLK, 16 * UART_BR)>>8)
+//#define UART_DLM_VAL ((UART_CLK/16/UART_BR)>>8)
+/// Value to load on the UART divisor, low byte
+#define UART_DLL_VAL (DivWithRounding(UART_CLK, 16 * UART_BR) & 0xFF)
+//#define UART_DLL_VAL ((UART_CLK/16/UART_BR)&0xFF)
+
+/** \addtogroup UartRegs UartRegs
+ * \brief 16C550 UART registers
+ * \note Do NOT access IER, FCR, LCR and MCR directly, use Set/Get functions.
+ * Remaining registers can be directly accessed, but meeting the
+ * read only/write only restrictions.
+ * \{
+ */
+/// Receiver holding register. Read only.
+#define UART_RHR (*((volatile uint8_t*)(UART_BASE + 0)))
+/// Transmit holding register. Write only.
+#define UART_THR (*((volatile uint8_t*)(UART_BASE + 0)))
+/// Interrupt enable register. Write only.
+#define UART_IER (*((volatile uint8_t*)(UART_BASE + 2)))
+/// FIFO control register. Write only.
+#define UART_FCR (*((volatile uint8_t*)(UART_BASE + 4)))
+/// Interrupt status register. Read only.
+#define UART_ISR (*((volatile uint8_t*)(UART_BASE + 4)))
+/// Line control register. Write only.
+#define UART_LCR (*((volatile uint8_t*)(UART_BASE + 6)))
+/// Modem control register. Write only.
+#define UART_MCR (*((volatile uint8_t*)(UART_BASE + 8)))
+/// Line status register. Read only.
+#define UART_LSR (*((volatile uint8_t*)(UART_BASE + 10)))
+/// Modem status register. Read only.
+#define UART_MSR (*((volatile uint8_t*)(UART_BASE + 12)))
+/// Scratchpad register.
+#define UART_SPR (*((volatile uint8_t*)(UART_BASE + 14)))
+/// Divisor latch LSB. Acessed only when LCR[7] = 1.
+#define UART_DLL (*((volatile uint8_t*)(UART_BASE + 0)))
+/// Divisor latch MSB. Acessed only when LCR[7] = 1.
+#define UART_DLM (*((volatile uint8_t*)(UART_BASE + 2)))
+/** \} */
+
+/// Structure with the shadow registers.
+typedef struct {
+ uint8_t IER; ///< Interrupt Enable Register
+ uint8_t FCR; ///< FIFO Control Register
+ uint8_t LCR; ///< Line Control Register
+ uint8_t MCR; ///< Modem Control Register
+} UartShadow;
+
+/// Uart shadow registers. Do NOT access directly!
+extern UartShadow sh;
+
+/** \addtogroup UartOuts UartOuts
+ * \brief Output pins controlled by the MCR UART
+ * register.
+ * \{ */
+#define UART_MCR__DTR 0x01 ///< Data Terminal Ready.
+#define UART_MCR__RTS 0x02 ///< Request To Send.
+#define UART_MCR__OUT1 0x04 ///< GPIO pin 1.
+#define UART_MCR__OUT2 0x08 ///< GPIO pin 2.
+/** \} */
+
+/** \addtogroup UartIns UartIns
+ * \brief Input pins readed in the MSR UART register.
+ * \{ */
+#define UART_MSR__DSR 0x20 ///< Data Set Ready
+/** \} */
+
+/************************************************************************//**
+ * \brief Initializes the driver. The baud rate is set to UART_BR, and the
+ * UART FIFOs are enabled. This function must be called before using
+ * any other API call.
+ ****************************************************************************/
+void uart_init(void);
+
+/************************************************************************//**
+ * \brief Checks if UART transmit register/FIFO is ready. In FIFO mode, up to
+ * 16 characters can be loaded each time transmitter is ready.
+ *
+ * \return TRUE if transmitter is ready, FALSE otherwise.
+ ****************************************************************************/
+#define uart_tx_ready() (UART_LSR & 0x20)
+
+/************************************************************************//**
+ * \brief Checks if UART receive register/FIFO has data available.
+ *
+ * \return TRUE if at least 1 byte is available, FALSE otherwise.
+ ****************************************************************************/
+#define uart_rx_ready() (UART_LSR & 0x01)
+
+/************************************************************************//**
+ * \brief Sends a character. Please make sure there is room in the transmit
+ * register/FIFO by calling uart_rx_ready() before using this function.
+ *
+ * \return Received character.
+ ****************************************************************************/
+#define uart_putc(c) do{UART_RHR = (c);}while(0);
+
+/************************************************************************//**
+ * \brief Returns a received character. Please make sure data is available by
+ * calling uart_rx_ready() before using this function.
+ *
+ * \return Received character.
+ ****************************************************************************/
+#define uart_getc() (UART_RHR)
+
+/************************************************************************//**
+ * \brief Sets a value in IER, FCR, LCR or MCR register.
+ *
+ * \param[in] reg Register to modify (IER, FCR, LCR or MCR).
+ * \param[in] val Value to set in IER, FCR, LCR or MCR register.
+ ****************************************************************************/
+#define uart_set(reg, val) do{sh.reg = (val);UART_##reg = (val);}while(0)
+
+/************************************************************************//**
+ * \brief Gets value of IER, FCR, LCR or MCR register.
+ *
+ * \param[in] reg Register to read (IER, FCR, LCR or MCR).
+ * \return The value of the requested register.
+ ****************************************************************************/
+#define uart_get(reg) (sh.reg)
+
+/************************************************************************//**
+ * \brief Sets bits in IER, FCR, LCR or MCR register.
+ *
+ * \param[in] reg Register to modify (IER, FCR, LCR or MCR).
+ * \param[in] val Bits set in val, will be set in reg register.
+ ****************************************************************************/
+#define uart_set_bits(reg, val) do{sh.reg |= (val); \
+ UART_##reg = sh.reg;}while(0)
+
+/************************************************************************//**
+ * \brief Clears bits in IER, FCR, LCR or MCR register.
+ *
+ * \param[in] reg Register to modify (IER, FCR, LCR or MCR).
+ * \param[in] val Bits set in val, will be cleared in reg register.
+ ****************************************************************************/
+#define uart_clr_bits(reg, val) do{sh.reg &= ~(val); \
+ UART_##reg = sh.reg;}while(0)
+
+/************************************************************************//**
+ * \brief Reset TX and RX FIFOs.
+ ****************************************************************************/
+#define uart_reset_fifos() uart_set_bits(FCR, 0x07)
+
+/************************************************************************//**
+ * \brief Test Connection with registers
+ *
+ * \param[in] reg Register to modify
+ * \param[in] val Bits set in val, will be readed from reg register.
+ ****************************************************************************/
+#define uart_test(reg, val) reg = val; \
+ if (reg != val) return MW_ERR
+
+#endif // MODULE_MEGAWIFI
+
+#endif /*_16C550_H_*/
+
+/** \} */
+
diff --git a/inc/ext/mw/lsd.h b/inc/ext/mw/lsd.h
index f876746f..fa635192 100644
--- a/inc/ext/mw/lsd.h
+++ b/inc/ext/mw/lsd.h
@@ -1,181 +1,186 @@
-/************************************************************************//**
- * \brief Local Symmetric Data-link. Implements an extremely simple
- * protocol to link two full-duplex devices, multiplexing the
- * data link.
- *
- * The multiplexing facility allows having up to LSD_MAX_CH simultaneous
- * channels on the serial link.
- *
- * The module has synchronous functions to send/receive data (easy to use, but
- * due to polling hang the console until transfer is complete) and their
- * asyncronous counterparts. The asynchronous functions return immediately,
- * but require calling frequently lsd_process() to actually send/receive data.
- * Once the asynchronous functions complete sending/receiving data, the
- * specified callback is run.
- *
- * \author Jesus Alonso (doragasu)
- * \date 2019
- * \note Unfortunately the Megadrive does have neither an interrupt pin nor
- * DMA threshold pins in the cartridge slot, so polling is the only
- * way. So you have
- * Megadrive does not have an interrupt pin on the cart, implementing
- * more efficient data transmission techniques will be tricky.
- * \warning The syncrhonous API is easier to use, but a lot less reliable:
- * * It polls, using all the CPU until the send/recv operation completes.
- * * A lsd_recv_sync() can freeze the machine if no frame is received. USE IT
- * WITH CARE!
- *
- * \defgroup lsd lsd
- * \{
- ****************************************************************************/
-
-/*
- * Frame format is:
- *
- * STX : CH-LENH : LENL : DATA : ETX
- *
- * - STX and ETX are the start/end of transmission characters (1 byte each).
- * - CH-LENH is the channel number (first 4 bits) and the 4 high bits of the
- * data length.
- * - LENL is the low 8 bits of the data length.
- * - DATA is the payload, of the previously specified length.
- */
-#ifndef _LSD_H_
-#define _LSD_H_
-
-#include "16c550.h"
-#include "mw-msg.h"
-
-#if (MODULE_MEGAWIFI != 0)
-
-/// LSD frame overhead in bytes
-#define LSD_OVERHEAD 4
-
-/// Maximum number of available simultaneous channels
-#define LSD_MAX_CH 4
-
-/// Maximum data payload length
-#define LSD_MAX_LEN 4095
-
-/// Number of buffer frames available
-#define LSD_BUF_FRAMES 2
-
-/// Return status codes for LSD functions
-enum lsd_status {
- LSD_STAT_ERR_FRAMING = -5, ///< Frame format error
- LSD_STAT_ERR_INVALID_CH = -4, ///< Invalid channel
- LSD_STAT_ERR_FRAME_TOO_LONG = -3, ///< Frame is too long
- LSD_STAT_ERR_IN_PROGRESS = -2, ///< Operation in progress
- LSD_STAT_ERROR = -1, ///< General error
- LSD_STAT_COMPLETE = 0, ///< No error
- LSD_STAT_BUSY = 1 ///< Doing requested operation
-};
-
-/// Callback for the asynchronous lsd_send() function.
-typedef void (*lsd_send_cb)(enum lsd_status stat, void *ctx);
-/// Callback for the asynchronous lsd_recv() function.
-typedef void (*lsd_recv_cb)(enum lsd_status stat, uint8_t ch,
- char *data, uint16_t len, void *ctx);
-
-/************************************************************************//**
- * \brief Module initialization.
- ****************************************************************************/
-void lsd_init(void);
-
-/************************************************************************//**
- * \brief Enables a channel to start reception and be able to send data.
- *
- * \param[in] ch Channel number.
- *
- * \return LSD_OK on success, LSD_ERROR otherwise.
- ****************************************************************************/
-int lsd_ch_enable(uint8_t ch);
-
-/************************************************************************//**
- * \brief Disables a channel to stop reception and prohibit sending data.
- *
- * \param[in] ch Channel number.
- *
- * \return LSD_OK on success, LSD_ERROR otherwise.
- ****************************************************************************/
-int lsd_ch_disable(uint8_t ch);
-
-
-/************************************************************************//**
- * \brief Asynchronously sends data through a previously enabled channel.
- *
- * \param[in] ch Channel number to use.
- * \param[in] data Buffer to send.
- * \param[in] len Length of the buffer to send.
- * \param[in] ctx Context for the send callback function.
- * \param[in] send_cb Callback to run when send completes or errors.
- *
- * \return Status of the send procedure. Usually LSD_STAT_BUSY is returned,
- * and the send procedure is then performed in background.
- * \note Calling this function while there is a send procedure in progress,
- * will cause the function call to fail with LSD_STAT_SEND_ERR_IN_PROGRESS.
- ****************************************************************************/
-enum lsd_status lsd_send(uint8_t ch, const char *data, int16_t len,
- void *ctx, lsd_send_cb send_cb);
-
-/************************************************************************//**
- * \brief Synchronously sends data through a previously enabled channel.
- *
- * \param[in] ch Channel number to use.
- * \param[in] data Buffer to send.
- * \param[in] len Length of the buffer to send.
- *
- * \return Status of the send procedure.
- * \warning This function polls until the procedure is complete (or errors).
- ****************************************************************************/
-enum lsd_status lsd_send_sync(uint8_t ch, const char *data, int16_t len);
-
-/************************************************************************//**
- * \brief Asyncrhonously Receives a frame using LSD protocol.
- *
- * \param[in] buf Buffer for reception.
- * \param[in] len Buffer length.
- * \param[in] ctx Context for the receive callback function.
- * \param[in] recv_cb Callback to run when receive completes or errors.
- *
- * \return Status of the receive procedure.
- ****************************************************************************/
-enum lsd_status lsd_recv(char *buf, int16_t len, void *ctx,
- lsd_recv_cb recv_cb);
-
-/************************************************************************//**
- * \brief Syncrhonously Receives a frame using LSD protocol.
- *
- * \param[out] buf Buffer for received data.
- * \param[inout] len On input: buffer length. On output: received frame length.
- * \param[out] ch Channel on which the data has been received.
- *
- * \warning This function polls until the reception is complete, or a reception
- * error occurs.
- * \warning If no frame is received when this function is called, the machine
- * will lock.
- ****************************************************************************/
-enum lsd_status lsd_recv_sync(char *buf, uint16_t *len, uint8_t *ch);
-
-/************************************************************************//**
- * \brief Processes sends/receives pending data.
- *
- * Call this function as much as possible when using the asynchronous
- * lsd_send() and lsd_receive() functions.
- ****************************************************************************/
-void lsd_process(void);
-
-/************************************************************************//**
- * \brief Sends syncrhonization frame.
- *
- * This function sends a chunk of 0x55 bytes to help physical layer to
- * synchronize. It is usually not necessary to use this function, but might
- * help some UART chips to compute an accurate clock.
- ****************************************************************************/
-void lsd_line_sync(void);
-
-#endif // MODULE_MEGAWIFI
-
-#endif //_LSD_H_
-
-/** \} */
+/************************************************************************//**
+ * \brief Local Symmetric Data-link. Implements an extremely simple
+ * protocol to link two full-duplex devices, multiplexing the
+ * data link.
+ *
+ * The multiplexing facility allows having up to LSD_MAX_CH simultaneous
+ * channels on the serial link.
+ *
+ * The module has synchronous functions to send/receive data (easy to use, but
+ * due to polling hang the console until transfer is complete) and their
+ * asyncronous counterparts. The asynchronous functions return immediately,
+ * but require calling frequently lsd_process() to actually send/receive data.
+ * Once the asynchronous functions complete sending/receiving data, the
+ * specified callback is run.
+ *
+ * \author Jesus Alonso (doragasu)
+ * \author Juan Antonio (PaCHoN)
+ * \date 2019~2025
+ * \note Unfortunately the Megadrive does have neither an interrupt pin nor
+ * DMA threshold pins in the cartridge slot, so polling is the only
+ * way. So you have
+ * Megadrive does not have an interrupt pin on the cart, implementing
+ * more efficient data transmission techniques will be tricky.
+ * \warning The syncrhonous API is easier to use, but a lot less reliable:
+ * * It polls, using all the CPU until the send/recv operation completes.
+ * * A lsd_recv_sync() can freeze the machine if no frame is received. USE IT
+ * WITH CARE!
+ *
+ * \defgroup lsd lsd
+ * \{
+ ****************************************************************************/
+
+/*
+ * Frame format is:
+ *
+ * STX : CH-LENH : LENL : DATA : ETX
+ *
+ * - STX and ETX are the start/end of transmission characters (1 byte each).
+ * - CH-LENH is the channel number (first 4 bits) and the 4 high bits of the
+ * data length.
+ * - LENL is the low 8 bits of the data length.
+ * - DATA is the payload, of the previously specified length.
+ */
+#ifndef _LSD_H_
+#define _LSD_H_
+
+#if (MODULE_MEGAWIFI == 1 && MODULE_EVERDRIVE == 0)
+ #include "16c550.h"
+#elif (MODULE_MEGAWIFI == 1 && MODULE_EVERDRIVE == 1)
+ #include "ssf.h"
+#endif
+#include "mw-msg.h"
+
+#if (MODULE_MEGAWIFI == 1)
+
+/// LSD frame overhead in bytes
+#define LSD_OVERHEAD 4
+
+/// Maximum number of available simultaneous channels
+#define LSD_MAX_CH 4
+
+/// Maximum data payload length
+#define LSD_MAX_LEN 4095
+
+/// Number of buffer frames available
+#define LSD_BUF_FRAMES 2
+
+/// Return status codes for LSD functions
+enum lsd_status {
+ LSD_STAT_ERR_FRAMING = -5, ///< Frame format error
+ LSD_STAT_ERR_INVALID_CH = -4, ///< Invalid channel
+ LSD_STAT_ERR_FRAME_TOO_LONG = -3, ///< Frame is too long
+ LSD_STAT_ERR_IN_PROGRESS = -2, ///< Operation in progress
+ LSD_STAT_ERROR = -1, ///< General error
+ LSD_STAT_COMPLETE = 0, ///< No error
+ LSD_STAT_BUSY = 1 ///< Doing requested operation
+};
+
+/// Callback for the asynchronous lsd_send() function.
+typedef void (*lsd_send_cb)(enum lsd_status stat, void *ctx);
+/// Callback for the asynchronous lsd_recv() function.
+typedef void (*lsd_recv_cb)(enum lsd_status stat, uint8_t ch,
+ char *data, uint16_t len, void *ctx);
+
+/************************************************************************//**
+ * \brief Module initialization.
+ ****************************************************************************/
+void lsd_init(void);
+
+/************************************************************************//**
+ * \brief Enables a channel to start reception and be able to send data.
+ *
+ * \param[in] ch Channel number.
+ *
+ * \return LSD_OK on success, LSD_ERROR otherwise.
+ ****************************************************************************/
+int lsd_ch_enable(uint8_t ch);
+
+/************************************************************************//**
+ * \brief Disables a channel to stop reception and prohibit sending data.
+ *
+ * \param[in] ch Channel number.
+ *
+ * \return LSD_OK on success, LSD_ERROR otherwise.
+ ****************************************************************************/
+int lsd_ch_disable(uint8_t ch);
+
+
+/************************************************************************//**
+ * \brief Asynchronously sends data through a previously enabled channel.
+ *
+ * \param[in] ch Channel number to use.
+ * \param[in] data Buffer to send.
+ * \param[in] len Length of the buffer to send.
+ * \param[in] ctx Context for the send callback function.
+ * \param[in] send_cb Callback to run when send completes or errors.
+ *
+ * \return Status of the send procedure. Usually LSD_STAT_BUSY is returned,
+ * and the send procedure is then performed in background.
+ * \note Calling this function while there is a send procedure in progress,
+ * will cause the function call to fail with LSD_STAT_SEND_ERR_IN_PROGRESS.
+ ****************************************************************************/
+enum lsd_status lsd_send(uint8_t ch, const char *data, int16_t len,
+ void *ctx, lsd_send_cb send_cb);
+
+/************************************************************************//**
+ * \brief Synchronously sends data through a previously enabled channel.
+ *
+ * \param[in] ch Channel number to use.
+ * \param[in] data Buffer to send.
+ * \param[in] len Length of the buffer to send.
+ *
+ * \return Status of the send procedure.
+ * \warning This function polls until the procedure is complete (or errors).
+ ****************************************************************************/
+enum lsd_status lsd_send_sync(uint8_t ch, const char *data, int16_t len);
+
+/************************************************************************//**
+ * \brief Asyncrhonously Receives a frame using LSD protocol.
+ *
+ * \param[in] buf Buffer for reception.
+ * \param[in] len Buffer length.
+ * \param[in] ctx Context for the receive callback function.
+ * \param[in] recv_cb Callback to run when receive completes or errors.
+ *
+ * \return Status of the receive procedure.
+ ****************************************************************************/
+enum lsd_status lsd_recv(char *buf, int16_t len, void *ctx,
+ lsd_recv_cb recv_cb);
+
+/************************************************************************//**
+ * \brief Syncrhonously Receives a frame using LSD protocol.
+ *
+ * \param[out] buf Buffer for received data.
+ * \param[inout] len On input: buffer length. On output: received frame length.
+ * \param[out] ch Channel on which the data has been received.
+ *
+ * \warning This function polls until the reception is complete, or a reception
+ * error occurs.
+ * \warning If no frame is received when this function is called, the machine
+ * will lock.
+ ****************************************************************************/
+enum lsd_status lsd_recv_sync(char *buf, uint16_t *len, uint8_t *ch);
+
+/************************************************************************//**
+ * \brief Processes sends/receives pending data.
+ *
+ * Call this function as much as possible when using the asynchronous
+ * lsd_send() and lsd_receive() functions.
+ ****************************************************************************/
+void lsd_process(void);
+
+/************************************************************************//**
+ * \brief Sends syncrhonization frame.
+ *
+ * This function sends a chunk of 0x55 bytes to help physical layer to
+ * synchronize. It is usually not necessary to use this function, but might
+ * help some UART chips to compute an accurate clock.
+ ****************************************************************************/
+void lsd_line_sync(void);
+
+#endif // MODULE_MEGAWIFI
+
+#endif //_LSD_H_
+
+/** \} */
diff --git a/inc/ext/mw/megawifi.h b/inc/ext/mw/megawifi.h
index 147e5732..e2286525 100644
--- a/inc/ext/mw/megawifi.h
+++ b/inc/ext/mw/megawifi.h
@@ -1,979 +1,1015 @@
-/************************************************************************//**
- * \file
- *
- * \brief MegaWiFi API implementation.
- *
- * \defgroup megawifi megawifi
- * \{
- *
- * \brief MegaWiFi API implementation.
- *
- * API to communicate with the wifi module and the Internet. API calls are
- * documented and most of them are self explanatory. Mostly the only weird
- * thing about the API is UDP reuse mode. If you enable reuse mode (setting
- * the dst_addr and/or dst_port to NULL in the mw_udp_set() call), received
- * data will prepend the IP and port of the peer (using mw_reuse_payload data
- * structure), and data to be sent also requires the IP and port to be
- * prepended to the payload.
- *
- * \author Jesus Alonso (doragasu)
- * \date 2015
- *
- * \note This module requires setting MODULE_MEGAWIFI to 1 in config.h and
- * rebuilding the library (if you had to change them).
- ****************************************************************************/
-
-#ifndef _MEGAWIFI_H_
-#define _MEGAWIFI_H_
-
-#include "16c550.h"
-#include "mw-msg.h"
-#include "lsd.h"
-
-#if (MODULE_MEGAWIFI != 0)
-
-
-/// API version implemented, major number
-#define MW_API_VERSION_MAJOR 1
-
-/// API version implemented, minor number
-#define MW_API_VERSION_MINOR 5
-
-/// Timeout for standard commands in milliseconds
-#define MW_COMMAND_TOUT_MS 1000
-/// Timeout for TCP connections
-#define MW_CONNECT_TOUT_MS 10000
-/// Timeout for HTTP open command in milliseconds
-#define MW_HTTP_OPEN_TOUT_MS 10000
-/// Timeout for the AP scan command in milliseconds
-#define MW_SCAN_TOUT_MS 10000
-/// Timeout for the AP associate command in milliseconds
-#define MW_ASSOC_TOUT_MS 20000
-/// Time to sleep before waiting for assoc in milliseconds
-#define MW_ASSOC_WAIT_SLEEP_MS 5000
-/// Timeout for upgrade command in milliseconds
-#define MW_UPGRADE_TOUT_MS 180000
-/// Milliseconds between status polls while in wm_ap_assoc_wait()
-#define MW_STAT_POLL_MS 250
-
-/// Error codes for MegaWiFi API functions
-enum mw_err {
- MW_ERR_NONE = 0, ///< No error (success)
- MW_ERR, ///< General error
- MW_ERR_NOT_READY, ///< Not ready to run command
- MW_ERR_BUFFER_TOO_SHORT, ///< Command buffer is too small
- MW_ERR_PARAM, ///< Input parameter out of range
- MW_ERR_SEND, ///< Error sending data
- MW_ERR_RECV ///< Error receiving data
-};
-
-/// Supported HTTP methods
-enum mw_http_method {
- MW_HTTP_METHOD_GET = 0, ///< HTTP GET Method
- MW_HTTP_METHOD_POST, ///< HTTP POST Method
- MW_HTTP_METHOD_PUT, ///< HTTP PUT Method
- MW_HTTP_METHOD_PATCH, ///< HTTP PATCH Method
- MW_HTTP_METHOD_DELETE, ///< HTTP DELETE Method
- MW_HTTP_METHOD_HEAD, ///< HTTP HEAD Method
- MW_HTTP_METHOD_NOTIFY, ///< HTTP NOTIFY Method
- MW_HTTP_METHOD_SUBSCRIBE, ///< HTTP SUBSCRIBE Method
- MW_HTTP_METHOD_UNSUBSCRIBE,///< HTTP UNSUBSCRIBE
- MW_HTTP_METHOD_OPTIONS, ///< HTTP OPTIONS
- MW_HTTP_METHOD_MAX,
-};
-
-/** \addtogroup mw_ctrl_pins mw_ctrl_pins
- * \brief Pins used to control WiFi module.
- * \{ */
-#define MW__RESET UART_MCR__OUT1 ///< Reset out.
-#define MW__PRG UART_MCR__OUT2 ///< Program out.
-#define MW__PD UART_MCR__DTR ///< Power Down out.
-#define MW__DAT UART_MSR__DSR ///< Data request in.
-/** \} */
-
-/// Maximum SSID length (including '\0').
-#define MW_SSID_MAXLEN 32
-/// Maximum password length (including '\0').
-#define MW_PASS_MAXLEN 64
-/// Maximum length of an NTP pool URI (including '\0').
-#define MW_NTP_POOL_MAXLEN 80
-/// Number of AP configurations stored to nvflash.
-#define MW_NUM_CFG_SLOTS 3
-/// Number of DSN servers supported per AP configuration.
-#define MW_NUM_DNS_SERVERS 2
-/// Length of the FSM queue
-#define MW_FSM_QUEUE_LEN 8
-/// Maximum number of simultaneous TCP connections
-#define MW_MAX_SOCK 3
-/// Control channel used for LSD protocol
-#define MW_CTRL_CH 0
-/// Channel used for HTTP requests and cert sets
-#define MW_HTTP_CH LSD_MAX_CH - 1
-
-/// Minimum command buffer length to be able to send all available commands
-/// with minimum data payload. This length might not guarantee that commands
-/// like mw_sntp_cfg_set() can be sent if payload length is big enough).
-#define MW_CMD_MIN_BUFLEN 168
-
-/// Access Point data.
-struct mw_ap_data {
- enum mw_security auth; ///< Security type
- uint8_t channel; ///< WiFi channel.
- int8_t rssi; ///< Signal strength.
- uint8_t ssid_len; ///< Length of ssid field.
- char *ssid; ///< SSID string (not NULL terminated).
-};
-
-/// Interface type for the mw_bssid_get() function.
-enum mw_if_type {
- MW_IF_STATION = 0, ///< Station interface
- MW_IF_SOFTAP, ///< Access Point interface
- MW_IF_MAX ///< Number of supported interface types
-};
-
-/************************************************************************//**
- * \brief Module initialization. Must be called once before using any
- * other function. It also initializes de UART.
- *
- * \param[in] cmd_buf Pointer to the buffer used to send and receive commands.
- * \param[in] buf_len Length of cmdBuf in bytes.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-int16_t mw_init(uint16_t *cmd_buf, uint16_t buf_len);
-
-/************************************************************************//**
- * \brief Processes sends/receives pending data.
- *
- * Call this function as much as possible to process incoming/outgoing data.
- *
- * \warning No data will be sent/received if this function is not frequently
- * invoked.
- ****************************************************************************/
-static inline void mw_process(void) {lsd_process();}
-
-/************************************************************************//**
- * \brief Sets the callback function to be run when network data is received
- * while waiting for a command reply.
- *
- * \param[in] cmd_recv_cb Callback to be run when data is received while
- * waiting for a command reply.
- *
- * \warning If this callback is not set, data received while waiting for a
- * command reply will be silently discarded.
- ****************************************************************************/
-void mw_cmd_data_cb_set(lsd_recv_cb cmd_recv_cb);
-
-/************************************************************************//**
- * \brief Performs the startup sequence for the WiFi module, and tries
- * detecting it by requesting the version data.
- *
- * \param[out] major Major version number.
- * \param[out] minor Minor version number.
- * \param[out] variant String with firmware variant ("std" for standard).
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-enum mw_err mw_detect(uint8_t *major, uint8_t *minor, char **variant);
-
-/************************************************************************//**
- * \brief Obtain module version numbers and string
- *
- * \param[out] version Version numbers (major, minor, micro) in order.
- * \param[out] variant String with firmware variant ("std" for standard).
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-enum mw_err mw_version_get(uint8_t version[3], char **variant);
-
-/************************************************************************//**
- * \brief Gets the module BSSID (the MAC address) for the specified interface.
- *
- * \param[in] interface_type Type of the interface to obtain BSSID from.
- *
- * \return The requested BSSID (6 byte binary data), or NULL on error.
- ****************************************************************************/
-uint8_t *mw_bssid_get(enum mw_if_type interface_type);
-
-/************************************************************************//**
- * \brief Set default module configuration (AKA factory settings).
- *
- * \return MW_ERR_NONE on success, other code on failure.
- *
- * \note For this command to take effect, it must be followed by a module
- * reset.
- ****************************************************************************/
-enum mw_err mw_default_cfg_set(void);
-
-/************************************************************************//**
- * \brief Set access point configuration (SSID and password).
- *
- * \param[in] slot Configuration slot to use.
- * \param[in] ssid String with the AP SSID to set.
- * \param[in] pass String with the AP SSID to set.
- * \param[in] phy_type Bitmask with the PHY type configuration.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- *
- * \note Strings must be NULL terminated. Maximum SSID length is 32 bytes,
- * maximum pass length is 64 bytes.
- * \note After a successful invocation, call mw_cfg_save() for changes to
- * be persistent
- ****************************************************************************/
-enum mw_err mw_ap_cfg_set(uint8_t slot, const char *ssid, const char *pass,
- enum mw_phy_type phy_type);
-
-/************************************************************************//**
- * \brief Gets access point configuration (SSID and password).
- *
- * \param[in] slot Configuration slot to use.
- * \param[out] ssid String with the AP SSID got.
- * \param[out] pass String with the AP SSID got.
- * \param[out] phy_type Bitmask with the PHY type configuration.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- *
- * \warning ssid is zero padded up to 32 bytes, and pass is zero padded up
- * to 64 bytes. If ssid is 32 bytes, it will NOT be NULL terminated.
- * Also if pass is 64 bytes, it will NOT be NULL terminated.
- ****************************************************************************/
-enum mw_err mw_ap_cfg_get(uint8_t slot, char **ssid, char **pass,
- enum mw_phy_type *phy_type);
-
-/************************************************************************//**
- * \brief Set IPv4 configuration.
- *
- * \param[in] slot Configuration slot to use.
- * \param[in] ip Pointer to the mw_ip_cfg structure, with IP configuration.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- *
- * \note After a successful invocation, call mw_cfg_save() for changes to
- * be persistent
- ****************************************************************************/
-enum mw_err mw_ip_cfg_set(uint8_t slot, const struct mw_ip_cfg *ip);
-
-/************************************************************************//**
- * \brief Get IPv4 configuration.
- *
- * \param[in] slot Configuration slot to use.
- * \param[out] ip Double pointer to mw_ip_cfg structure, with IP conf.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-enum mw_err mw_ip_cfg_get(uint8_t slot, struct mw_ip_cfg **ip);
-
-/************************************************************************//**
- * \brief Set advanced WiFi configuration.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- *
- * \warning This function is dangerous. Changing these parameters is rarely
- * needed, and setting incorrect values, may render the connection unstable
- * and/or crash the WiFi module. Invalid configurations can even cause the
- * module to crash in a bootloop, requiring a programmer to unbrick it.
- * Make sure you thoroughly test the values you allow users to set here.
- * \note If you want to change WiFi parameters, the recommendation is to get
- * the current configuration via mw_wifi_adv_cfg_get(), and from it change
- * only the required parameters.
- * \note These parameters will not take effect until saved to non-volatile
- * storage (with mw_cfg_save()) and issuing a module reboot.
- ****************************************************************************/
-enum mw_err mw_wifi_adv_cfg_set(const struct mw_wifi_adv_cfg *wifi);
-
-/************************************************************************//**
- * \brief Get advanced WiFi configuration.
- *
- * \return Pointer to the advanced WiFi configuration, or NULL on error.
- ****************************************************************************/
-struct mw_wifi_adv_cfg *mw_wifi_adv_cfg_get(void);
-
-/************************************************************************//**
- * \brief Saves changed configuration parameters to non-volatile memory.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-enum mw_err mw_cfg_save(void);
-
-/************************************************************************//**
- * \brief Get current IP configuration, of the joined AP.
- *
- * \param[out] ip Double pointer to mw_ip_cfg structure, with IP conf.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-enum mw_err mw_ip_current(struct mw_ip_cfg **ip);
-
-/************************************************************************//**
- * \brief Scan for access points.
- *
- * \param[in] phy_type Bitmask with the PHY type configuration.
- * \param[out] ap_data Data of the found access points. Each entry has the
- * format specified on the mw_ap_data structure.
- * \param[out] aps Number of found access points.
- *
- * \return Length in bytes of the output data if operation completes
- * successfully, or -1 if scan fails.
- ****************************************************************************/
-int16_t mw_ap_scan(enum mw_phy_type phy_type, char **ap_data, uint8_t *aps);
-
-/************************************************************************//**
- * \brief Parses received AP data and fills information of the AP at "pos".
- * Useful to extract AP information from the data obtained by
- * calling mw_ap_scan() function.
- *
- * \param[in] ap_data Access point data obtained from mw_ap_scan().
- * \param[in] pos Position at which to extract data.
- * \param[out] apd Pointer to the extracted data from an AP.
- * \param[in] data_len Lenght of apData.
- *
- * \return Position of the next AP entry in apData, 0 if no more APs
- * available or MW_ERROR if ap data/pos combination is not valid.
- *
- * \note This functions executes locally, does not communicate with the
- * WiFi module.
- ****************************************************************************/
-int16_t mw_ap_fill_next(const char *ap_data, uint16_t pos,
- struct mw_ap_data *apd, uint16_t data_len);
-
-/************************************************************************//**
- * \brief Tries associating to an AP. If successful, also configures IPv4.
- *
- * \param[in] slot Configuration slot to use.
- *
- * \return MW_ERR_NONE if AP join operation has been successfully started,
- ****************************************************************************/
-enum mw_err mw_ap_assoc(uint8_t slot);
-
-/************************************************************************//**
- * \brief Polls the module status until it reports device is associated to
- * AP or timeout occurs.
- *
- * \param[in] tout_frames Maximun number of frames to wait for association.
- * Set to TSK_PEND_FOREVER for an infinite wait.
- *
- * \return MW_ERR_NONE if device is associated to AP. MW_ERR_NOT_READY if
- * the timeout has expired.
- ****************************************************************************/
-enum mw_err mw_ap_assoc_wait(int16_t tout_frames);
-
-/************************************************************************//**
- * \brief Sets default AP/IP configuration.
- *
- * \param[in] slot Configuration slot to use.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- *
- * \note After a successful invocation, call mw_cfg_save() for changes to
- * be persistent
- ****************************************************************************/
-enum mw_err mw_def_ap_cfg(uint8_t slot);
-
-/************************************************************************//**
- * \brief Dissasociates from a previously associated AP.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-enum mw_err mw_ap_disassoc(void);
-
-/************************************************************************//**
- * \brief Gets default AP/IP configuration slot.
- *
- * \return The default configuration slot, of -1 on error.
- ****************************************************************************/
-int16_t mw_def_ap_cfg_get(void);
-
-/************************************************************************//**
- * \brief Tries establishing a TCP connection with specified server.
- *
- * \param[in] ch Channel used for the connection.
- * \param[in] dst_addr Address (IP or DNS entry) of the server.
- * \param[in] dst_port Port in which server is listening.
- * \param[in] src_port Port from which try establishing connection. Set to
- * 0 or empty string for automatic port allocation.
- *
- * \return MW_ERR_NONE on success, other code if connection failed.
- ****************************************************************************/
-enum mw_err mw_tcp_connect(uint8_t ch, const char *dst_addr,
- const char *dst_port, const char *src_port);
-
-/************************************************************************//**
- * \brief Closes and disconnects a socket from specified channel.
- *
- * This function can be used to free the channel associated to both TCP and
- * UDP sockets.
- *
- * \param[in] ch Channel associated to the socket to disconnect.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-enum mw_err mw_close(uint8_t ch);
-
-/// Closes a TCP socket. This is an alias of mw_close().
-#define mw_tcp_disconnect(ch) mw_close(ch)
-
-/************************************************************************//**
- * \brief Configures a UDP socket to send/receive data.
- *
- * \param[in] ch Channel used for the connection.
- * \param[in] dst_addr Address (IP or DNS entry) to send data to.
- * \param[in] dst_port Port to send data to.
- * \param[in] src_port Local port to listen message on.
- *
- * \return MW_ERR_NONE on success, other code if connection failed.
- *
- * \note Setting to NULL dst_addr and/or dst_port, enables reuse mode.
- ****************************************************************************/
-enum mw_err mw_udp_set(uint8_t ch, const char *dst_addr, const char *dst_port,
- const char *src_port);
-
-/// Frees a UDP socket. This is an alias of mw_close().
-#define mw_udp_unset(ch) mw_close(ch)
-
-/************************************************************************//**
- * \brief Binds a socket to a port, and listens to connections on the port.
- * If a connection request is received, it will be automatically
- * accepted.
- *
- * \param[in] ch Channel associated to the socket bound t port.
- * \param[in] port Port number to which the socket will be bound.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-enum mw_err mw_tcp_bind(uint8_t ch, uint16_t port);
-
-/************************************************************************//**
- * \brief Polls a socket until it is ready to transfer data. Typical use of
- * this function is after a successful mw_tcp_bind().
- *
- * \param[in] ch Channel associated to the socket to monitor.
- * \param[in] tout_frames Maximum number of frames to wait for connection.
- * Set to 0 for an infinite wait.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-enum mw_err mw_sock_conn_wait(uint8_t ch, int16_t tout_frames);
-
-/************************************************************************//**
- * \brief Receive data, asyncrhonous interface.
- *
- * \param[in] buf Reception buffer.
- * \param[in] len Length of the receive buffer.
- * \param[in] ctx Context pointer to pass to the reception callbak.
- * \param[in] recv_cb Callback to run when reception is complete or errors.
- *
- * \return Status of the receive procedure.
- ****************************************************************************/
-static inline enum lsd_status mw_recv(char *buf, int16_t len, void *ctx,
- lsd_recv_cb recv_cb)
-{
- return lsd_recv(buf, len, ctx, recv_cb);
-}
-
-/************************************************************************//**
- * \brief Receive data using an UDP socket in reuse mode.
- *
- * \param[in] data Receive buffer including the remote address and the
- * data payload.
- * \param[in] len Length of the receive buffer.
- * \param[in] ctx Context pointer to pass to the reception callbak.
- * \param[in] recv_cb Callback to run when reception is complete or errors.
- *
- * \return Status of the receive procedure.
- ****************************************************************************/
-static inline enum lsd_status mw_udp_reuse_recv(struct mw_reuse_payload *data,
- int16_t len, void *ctx, lsd_recv_cb recv_cb)
-{
- return lsd_recv((char*)data, len, ctx, recv_cb);
-}
-
-/************************************************************************//**
- * \brief Send data using a UDP socket in reuse mode.
- *
- * \param[in] ch Channel to use for the send operation.
- * \param[in] data Send buffer including the remote address and the
- * data payload.
- * \param[in] len Length of the receive buffer.
- * \param[in] ctx Context pointer to pass to the reception callbak.
- * \param[in] send_cb Callback to run when sending completes or errors.
- *
- * \return Status of the receive procedure.
- ****************************************************************************/
-static inline enum lsd_status mw_udp_reuse_send(uint8_t ch,
- const struct mw_reuse_payload *data, int16_t len, void *ctx,
- lsd_send_cb send_cb)
-{
- return lsd_send(ch, (const char*)data, len, ctx, send_cb);
-}
-
-/************************************************************************//**
- * \brief Sends data through a socket, using a previously allocated channel.
- * Asynchronous interface.
- *
- * \param[in] ch Channel used to send the data.
- * \param[in] data Buffer to send.
- * \param[in] len Length of the data to send.
- * \param[in] ctx Context for the send callback function.
- * \param[in] send_cb Callback to run when send completes or errors.
- *
- * \return Status of the send procedure. Usually LSD_STAT_BUSY is returned,
- * and the send procedure is then performed in background.
- * \note Calling this function while there is a send procedure in progress,
- * will cause the function call to fail with LSD_STAT_SEND_ERR_IN_PROGRESS.
- * \warning For very short data frames, it is possible that the send callback
- * is run before this function returns. In this case, the function returns
- * LSD_STAT_COMPLETE.
- ****************************************************************************/
-static inline enum lsd_status mw_send(uint8_t ch, const char *data, int16_t len,
- void *ctx, lsd_send_cb send_cb)
-{
- return lsd_send(ch, data, len, ctx, send_cb);
-}
-
-/************************************************************************//**
- * \brief Receive data, syncrhonous interface.
- *
- * \param[out] ch Channel on which data was received.
- * \param[out] buf Reception buffer.
- * \param[inout] buf_len On input, length of the buffer.
- * On output, received data length in bytes.
- * \param[in] tout_frames Reception timeout in frames. Set to TSK_PEND_FOREVER
- * for infinite wait (dangerous!).
- *
- * \return Status of the receive procedure.
- * \warning Do not use more than one syncrhonous call at once. You must wait
- * until a syncrhonous call ends to issue another one.
- ****************************************************************************/
-enum mw_err mw_recv_sync(uint8_t *ch, char *buf, int16_t *buf_len,
- int16_t tout_frames);
-
-/************************************************************************//**
- * \brief Sends data through a socket, using a previously allocated channel.
- * Synchronous interface.
- *
- * \param[in] ch Channel used to send the data.
- * \param[in] data Buffer to send.
- * \param[in] len Length of the data to send.
- * \param[in] tout_frames Timeout for send operation in frames. Set to 0 for
- * infinite wait (dangerous!).
- *
- * \return Status of the send procedure. Usually LSD_STAT_BUSY is returned,
- * and the send procedure is then performed in background.
- * \warning Do not use more than one syncrhonous call at once. You must wait
- * until a syncrhonous call ends to issue another one.
- ****************************************************************************/
-enum mw_err mw_send_sync(uint8_t ch, const char *data, uint16_t len,
- int16_t tout_frames);
-
-/************************************************************************//**
- * \brief Get system status.
- *
- * \return Pointer to system status structure on success, or NULL on error.
- ****************************************************************************/
-union mw_msg_sys_stat *mw_sys_stat_get(void);
-
-/************************************************************************//**
- * \brief Get socket status.
- *
- * \param[in] ch Channel associated to the socket asked for status.
- *
- * \return Socket status data on success, or -1 on error.
- ****************************************************************************/
-enum mw_sock_stat mw_sock_stat_get(uint8_t ch);
-
-/************************************************************************//**
- * \brief Configure SNTP parameters and timezone.
- *
- * \param[in] tz_str Timezone string (e.g. "CET"). See tzset(3) for details.
- * \param[in] server Array of up to three NTP servers. If less than three
- * servers are desired, unused entries must be empty.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- *
- * \note After a successful invocation, call mw_cfg_save() for changes to
- * be persistent
- ****************************************************************************/
-enum mw_err mw_sntp_cfg_set(const char *tz_str, const char *server[3]);
-
-/************************************************************************//**
- * \brief Get SNTP parameters and timezone configuration.
- *
- * \param[out] tz_str Timezone string (e.g. "CET"). See tzset(3) for details.
- * \param[out] server Array of three NTP server pointers. If less than 3
- * servers are configured, unused ones will be NULL.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-enum mw_err mw_sntp_cfg_get(char **tz_str, char *server[3]);
-
-/************************************************************************//**
- * \brief Get date and time.
- *
- * \param[out] dt_bin Date and time in seconds since Epoch. If set to NULL,
- * this info is not filled (but return value will still
- * be properly set).
- *
- * \return A string with the date and time in textual format, e.g.: "Thu Mar
- * 3 12:26:51 2016", or NULL if error.
- ****************************************************************************/
-char *mw_date_time_get(uint32_t dt_bin[2]);
-
-/************************************************************************//**
- * \brief Get the identifiers of the flash chip in the WiFi module.
- *
- * \param[out] man_id ID of the flash chip manufacturer.
- * \param[out] dev_id Device IDs of the flash chip.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-enum mw_err mw_flash_id_get(uint8_t *man_id, uint16_t *dev_id);
-
-/************************************************************************//**
- * \brief Erase a 4 KiB Flash sector. Every byte of an erased sector will be
- * read as 0xFF.
- *
- * \param[in] sect Sector number to erase.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-enum mw_err mw_flash_sector_erase(uint16_t sect);
-
-/************************************************************************//**
- * \brief Write data to specified flash address.
- *
- * \param[in] addr Address to which data will be written.
- * \param[in] data Data to be written to flash chip.
- * \param[in] data_len Length in bytes of data field.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-enum mw_err mw_flash_write(uint32_t addr, uint8_t *data, uint16_t data_len);
-
-/************************************************************************//**
- * \brief Read data from specified flash address.
- *
- * \param[in] addr Address from which data will be read.
- * \param[in] data_len Number of bytes to read from addr.
- *
- * \return Pointer to read data on success, or NULL if command failed.
- ****************************************************************************/
-uint8_t *mw_flash_read(uint32_t addr, uint16_t data_len);
-
-/************************************************************************//**
- * \brief Puts the WiFi module in reset state.
- ****************************************************************************/
-#define mw_module_reset() do{uart_set_bits(MCR, MW__RESET);}while(0)
-
-/************************************************************************//**
- * \brief Releases the module from reset state.
- ****************************************************************************/
-#define mw_module_start() do{uart_clr_bits(MCR, MW__RESET);}while(0)
-
-/************************************************************************//**
- * \brief Set gamertag information for one slot.
- *
- * \param[in] slot Slot to use (from 0 to 2).
- * \param[in] gamertag Gamertag information to set on specified slot.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- *
- * \note After a successful invocation, call mw_cfg_save() for changes to
- * be persistent
- ****************************************************************************/
-enum mw_err mw_gamertag_set(uint8_t slot, const struct mw_gamertag *gamertag);
-
-/************************************************************************//**
- * \brief Get gamertag information for one slot.
- *
- * \param[in] slot Slot to get gamertag from.
- *
- * \return Gamertag information on success, NULL on error.
- ****************************************************************************/
-struct mw_gamertag *mw_gamertag_get(uint8_t slot);
-
-/************************************************************************//**
- * \brief Write a message to the WiFi module log trace.
- *
- * \param[in] msg Message to write to the log trace.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-enum mw_err mw_log(const char *msg);
-
-/************************************************************************//**
- * \brief Set factory default configuration.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- * \note It is recommended to reboot the module after this command.
- ****************************************************************************/
-enum mw_err mw_factory_settings(void);
-
-/************************************************************************//**
- * \brief Powers off the WiFi module.
- *
- * The module will be put in deep sleep mode. To wake it up, the RESET pin
- * must be toggled.
- ****************************************************************************/
-void mw_power_off(void);
-
-/************************************************************************//**
- * \brief Sleep the specified amount of frames
- *
- * \param[in] frames Number of frames to sleep.
- ****************************************************************************/
-void mw_sleep(int16_t frames);
-
-/************************************************************************//**
- * \brief Set URL for HTTP requests.
- *
- * \param[in] url URL to set.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-enum mw_err mw_http_url_set(const char *url);
-
-/************************************************************************//**
- * \brief Set method for HTTP requests.
- *
- * \param[in] method Method to set.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-enum mw_err mw_http_method_set(enum mw_http_method method);
-
-/************************************************************************//**
- * \brief Add an HTTP header.
- *
- * \param[in] key Header key.
- * \param[in] value Value to set for the key.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-enum mw_err mw_http_header_add(const char *key, const char *value);
-
-/************************************************************************//**
- * \brief Delete a previously added HTTP header.
- *
- * \param[in] key Key of the header to delete.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-enum mw_err mw_http_header_del(const char *key);
-
-/************************************************************************//**
- * \brief Open HTTP connection.
- *
- * This functions opens the HTTP connection, sends the HTTP headers, and
- * prepares the module to send the specified content_len if (if any) with
- * a successive mw_send() or mw_send_sync(), using MW_HTTP_CH channel.
- *
- * \param[in] content_len Length of the content to write in HTTP request,
- * after a successfull call to this function.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-enum mw_err mw_http_open(uint32_t content_len);
-
-/************************************************************************//**
- * \brief Finish an opened HTTP request.
- *
- * After a successful call to mw_http_open(), and sending the content (if
- * any), call this function to receive the HTTP response headers, and obtain
- * the length of the body to receive with a further call to mw_recv() or
- * mw_recv_sync(), using MW_HTTP_CH.
- *
- * \param[out] content_len Length of the response content to receive after a
- * successfull call to this function.
- * \param[in] tout_frames Maximun number of frames to wait for reply.
- *
- * \return The HTTP status code if the request was completed, or an error
- * code (lower than 100) if the HTTP request did not complete.
- * \note Even if the HTTP request is completed, that does not mean there are
- * no errors, if the returned status code is 4xx or 5xx, there is a client
- * side or server side error.
- ****************************************************************************/
-int16_t mw_http_finish(uint32_t *content_len, int16_t tout_frames);
-
-/************************************************************************//**
- * \brief Query the X.509 hash of the installed PEM certificate.
- *
- * \return 0xFFFFFFFF if certificate is not installed or error occurs, or
- * the installed X.509 certificate hash on success.
- ****************************************************************************/
-uint32_t mw_http_cert_query(void);
-
-/************************************************************************//**
- * \brief Set the PEM certificate to use on HTTPS requests.
- *
- * The certificate is stored on the non volatile memory of the module, and
- * when present will be used in HTTPS requestes. This function can also be
- * used to delete a previously saved certificate using a NULL input value.
- *
- * \param[in] cert_hash X.509 hash of the certificate to set, ignored if
- * cert_len set to 0.
- * \param[in] cert PEM certificate in plain text. Ignored if cert_len
- * set to 0.
- * previously stored certificate.
- * \param[in] cert_len Certificate length in bytes. Set to 0 to delete a
- * previously stored certificate.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-enum mw_err mw_http_cert_set(uint32_t cert_hash, const char *cert,
- uint16_t cert_len);
-
-/************************************************************************//**
- * \brief Clean-up an HTTP request, freeing associated resources.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- ****************************************************************************/
-int16_t mw_http_cleanup(void);
-
-/************************************************************************//**
- * \brief Get the default server used for MegaWiFi connections.
- *
- * \return The server URL string, or NULL on error.
- ****************************************************************************/
-char *mw_def_server_get(void);
-
-/************************************************************************//**
- * \brief Set the default server used for MegaWiFi connections.
- *
- * \param[in] server_url The server URL to set.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- *
- * \note After a successful invocation, call mw_cfg_save() for changes to
- * be persistent
- ****************************************************************************/
-enum mw_err mw_def_server_set(const char *server_url);
-
-/************************************************************************//**
- * \brief Get random numbers.
- *
- * \param[in] rnd_len Number of bytes of resulting random array.
- *
- * \return The buffer with the requested random numbers on success, or NULL
- * when error.
- ****************************************************************************/
-uint8_t *mw_hrng_get(uint16_t rnd_len);
-
-/************************************************************************//**
- * \brief Set endpoint for Game API.
- *
- * Example endpoint for GameJolt: "https://api.gamejolt.com/api/game/v1_2/".
- *
- * \param[in] endpoint Endpoint for the Game API to set.
- * \param[in] priv_key Private key used for request signatures.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- *
- * \note The endpoint set persists between successive mw_ga_request() calls.
- ****************************************************************************/
-enum mw_err mw_ga_endpoint_set(const char *endpoint, const char *priv_key);
-
-/************************************************************************//**
- * \brief Add parameters to the Game API request in key/value format.
- *
- * Example key:value pair for GameJolt: "game_id":"123456".
- *
- * \param[in] key Array with the keys to add.
- * \param[in] value Array with the values to add
- * \param[in] num_pairs Number of key/value pairs to add.
- *
- * \return MW_ERR_NONE on success, other code on failure.
- *
- * \note The key/value pairs set persist between successive mw_ga_request()
- * calls.
- * \note Call mw_ga_key_value_add(NULL, NULL, 0) to clear previously set
- * key/value pairs.
- * \note Key/value pairs must NOT be URL encoded. Encoding is handled
- * internally.
- ****************************************************************************/
-enum mw_err mw_ga_key_value_add(const char **key, const char **value,
- uint16_t num_pairs);
-
-/************************************************************************//**
- * \brief Perform a GameAPI request, with the previously set endpoint and
- * key/value pairs.
- *
- * The request can also have URL encoded parameters. that are added to the
- * previously set key/value pairs.
- *
- * Example request for GameJolt:
- * - method: MW_HTTP_METHOD_GET
- * - path: "trophies"
- * - key:value: "achieved":"true"
- *
- * \param[in] method HTTP method to use. Most likely MW_HTTP_METHOD_GET.
- * \param[in] path Additional paths to add to the request.
- * \param[in] num_paths Number of additional paths to add.
- * \param[in] key Additional paths to add to the request.
- * \param[in] value Additional paths to add to the request.
- * \param[in] num_kv_pairs Number of key/value pairs.
- * \param[out] content_len Content length of the API response.
- * \param[in] tout_frames Number of frames to wait before canceling the
- * request due to a timeout error.
- *
- * \return HTTP status code on success (e.g. 200), or an error (lower than
- * 100) if the HTTP request could not be completed.
- * \note Even if the HTTP request is completed, that does not mean there are
- * no errors, if the returned status code is 4xx or 5xx, there is a client
- * side or server side error.
- * \note path, key and value parameters must not be URL encoded. Encoding is
- * handled internally.
- ****************************************************************************/
-int16_t mw_ga_request(enum mw_http_method method, const char **path,
- uint8_t num_paths, const char **key, const char **value,
- uint8_t num_kv_pairs, uint32_t *content_len,
- int16_t tout_frames);
-
-/************************************************************************//**
- * \brief Over-The-Air upgrade WiFi module firmware.
- *
- * \param[in] name Name of the firmware blob to upgrade.
- * E.g. "mw_rtos_std_v1.4.1"
- *
- * \return Status of the send procedure.
- ****************************************************************************/
-enum mw_err mw_fw_upgrade(const char *name);
-
-/****** THE FOLLOWING COMMANDS ARE LOWER LEVEL AND USUALLY NOT NEEDED ******/
-
-/************************************************************************//**
- * \brief Send a command to the WiFi module.
- *
- * \param[in] cmd Pointer to the filled mw_cmd command structure.
- * \param[in] ctx Context for callback function.
- * \param[in] send_cb Callback for the send operation completion.
- *
- * \return Status of the send procedure.
- ****************************************************************************/
-static inline enum lsd_status mw_cmd_send(mw_cmd *cmd, void *ctx,
- lsd_send_cb send_cb)
-{
- // Send data on control channel (0).
- return lsd_send(MW_CTRL_CH, cmd->packet, cmd->data_len + 4,
- ctx, send_cb);
-}
-
-/************************************************************************//**
- * \brief Try obtaining a reply to a command.
- *
- * \param[in] rep Buffer to hold the command reply.
- * \param[in] ctx Context for the reception callback.
- * \param[in] recv_cb Callback for data reception completion.
- *
- * \return Status of the reception procedure.
- ****************************************************************************/
-static inline enum lsd_status mw_cmd_recv(mw_cmd *rep, void *ctx,
- lsd_recv_cb recv_cb) {
- return lsd_recv(rep->packet, sizeof(mw_cmd), ctx, recv_cb);
-}
-
-#endif // MODULE_MEGAWIFI
-
-#endif /*_MEGAWIFI_H_*/
-
-/** \} */
-
+/************************************************************************//**
+ * \file
+ *
+ * \brief MegaWiFi API implementation.
+ *
+ * \defgroup megawifi megawifi
+ * \{
+ *
+ * \brief MegaWiFi API implementation.
+ *
+ * API to communicate with the wifi module and the Internet. API calls are
+ * documented and most of them are self explanatory. Mostly the only weird
+ * thing about the API is UDP reuse mode. If you enable reuse mode (setting
+ * the dst_addr and/or dst_port to NULL in the mw_udp_set() call), received
+ * data will prepend the IP and port of the peer (using mw_reuse_payload data
+ * structure), and data to be sent also requires the IP and port to be
+ * prepended to the payload.
+ *
+ * \author Jesus Alonso (doragasu)
+ * \author Juan Antonio (PaCHoN)
+ * \date 2025
+ *
+ * \note This module requires setting MODULE_MEGAWIFI to 1 in config.h and
+ * rebuilding the library (if you had to change them).
+ ****************************************************************************/
+
+#ifndef _MEGAWIFI_H_
+#define _MEGAWIFI_H_
+
+#if (MODULE_EVERDRIVE == 1)
+ #include "ssf.h"
+#else
+ #include "16c550.h"
+#endif
+#include "mw-msg.h"
+#include "lsd.h"
+
+/// API version implemented, major number
+#define MW_API_VERSION_MAJOR 1
+
+/// API version implemented, minor number
+#define MW_API_VERSION_MINOR 5
+
+/// Timeout for standard commands in milliseconds
+#define MW_COMMAND_TOUT_MS 1000
+/// Timeout for TCP connections
+#define MW_CONNECT_TOUT_MS 10000
+/// Timeout for HTTP open command in milliseconds
+#define MW_HTTP_OPEN_TOUT_MS 10000
+/// Timeout for the AP scan command in milliseconds
+#define MW_SCAN_TOUT_MS 10000
+/// Timeout for the AP associate command in milliseconds
+#define MW_ASSOC_TOUT_MS 20000
+/// Time to sleep before waiting for assoc in milliseconds
+#define MW_ASSOC_WAIT_SLEEP_MS 5000
+/// Timeout for upgrade command in milliseconds
+#define MW_UPGRADE_TOUT_MS 180000
+/// Timeout for ping command in milliseconds
+#define MW_PING_TOUT_MS 30000
+/// Milliseconds between status polls while in wm_ap_assoc_wait()
+#define MW_STAT_POLL_MS 250
+
+#if (MODULE_EVERDRIVE == 0)
+ /// Length of the wflash buffer
+ #define MW_BUFLEN 1460
+#elif (MODULE_EVERDRIVE == 1)
+ /// Length of the wflash buffer
+ #define MW_BUFLEN 1436
+#endif
+
+/// Error codes for MegaWiFi API functions
+enum mw_err {
+ MW_ERR_NONE = 0, ///< No error (success)
+ MW_ERR, ///< General error
+ MW_ERR_NOT_READY, ///< Not ready to run command
+ MW_ERR_BUFFER_TOO_SHORT, ///< Command buffer is too small
+ MW_ERR_PARAM, ///< Input parameter out of range
+ MW_ERR_SEND, ///< Error sending data
+ MW_ERR_RECV ///< Error receiving data
+};
+
+/// Supported HTTP methods
+enum mw_http_method {
+ MW_HTTP_METHOD_GET = 0, ///< HTTP GET Method
+ MW_HTTP_METHOD_POST, ///< HTTP POST Method
+ MW_HTTP_METHOD_PUT, ///< HTTP PUT Method
+ MW_HTTP_METHOD_PATCH, ///< HTTP PATCH Method
+ MW_HTTP_METHOD_DELETE, ///< HTTP DELETE Method
+ MW_HTTP_METHOD_HEAD, ///< HTTP HEAD Method
+ MW_HTTP_METHOD_NOTIFY, ///< HTTP NOTIFY Method
+ MW_HTTP_METHOD_SUBSCRIBE, ///< HTTP SUBSCRIBE Method
+ MW_HTTP_METHOD_UNSUBSCRIBE,///< HTTP UNSUBSCRIBE
+ MW_HTTP_METHOD_OPTIONS, ///< HTTP OPTIONS
+ MW_HTTP_METHOD_MAX,
+};
+
+/** \addtogroup mw_ctrl_pins mw_ctrl_pins
+ * \brief Pins used to control WiFi module.
+ * \{ */
+#define MW__RESET UART_MCR__OUT1 ///< Reset out.
+#define MW__PRG UART_MCR__OUT2 ///< Program out.
+#define MW__PD UART_MCR__DTR ///< Power Down out.
+#define MW__DAT UART_MSR__DSR ///< Data request in.
+/** \} */
+
+/// Maximum SSID length (including '\0').
+#define MW_SSID_MAXLEN 32
+/// Maximum password length (including '\0').
+#define MW_PASS_MAXLEN 64
+/// Maximum length of an NTP pool URI (including '\0').
+#define MW_NTP_POOL_MAXLEN 80
+/// Number of AP configurations stored to nvflash.
+#define MW_NUM_CFG_SLOTS 3
+/// Number of DSN servers supported per AP configuration.
+#define MW_NUM_DNS_SERVERS 2
+/// Length of the FSM queue
+#define MW_FSM_QUEUE_LEN 8
+/// Maximum number of simultaneous TCP connections
+#define MW_MAX_SOCK 3
+/// Control channel used for LSD protocol
+#define MW_CTRL_CH 0
+/// Channel used for HTTP requests and cert sets
+#define MW_HTTP_CH LSD_MAX_CH - 1
+
+/// Minimum command buffer length to be able to send all available commands
+/// with minimum data payload. This length might not guarantee that commands
+/// like mw_sntp_cfg_set() can be sent if payload length is big enough).
+#define MW_CMD_MIN_BUFLEN 168
+
+/// Access Point data.
+struct mw_ap_data {
+ enum mw_security auth; ///< Security type
+ uint8_t channel; ///< WiFi channel.
+ int8_t rssi; ///< Signal strength.
+ uint8_t ssid_len; ///< Length of ssid field.
+ char *ssid; ///< SSID string (not NULL terminated).
+};
+
+/// Interface type for the mw_bssid_get() function.
+enum mw_if_type {
+ MW_IF_STATION = 0, ///< Station interface
+ MW_IF_SOFTAP, ///< Access Point interface
+ MW_IF_MAX ///< Number of supported interface types
+};
+
+/************************************************************************//**
+ * \brief Module initialization. Must be called once before using any
+ * other function. It also initializes de UART.
+ *
+ * \param[in] cmd_buf Pointer to the buffer used to send and receive commands.
+ * \param[in] buf_len Length of cmdBuf in bytes.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+int16_t mw_init(uint16_t *cmd_buf, uint16_t buf_len);
+
+/************************************************************************//**
+ * \brief Processes sends/receives pending data.
+ *
+ * Call this function as much as possible to process incoming/outgoing data.
+ *
+ * \warning No data will be sent/received if this function is not frequently
+ * invoked.
+ ****************************************************************************/
+static inline void mw_process(void) {lsd_process();}
+
+/************************************************************************//**
+ * \brief Sets the callback function to be run when network data is received
+ * while waiting for a command reply.
+ *
+ * \param[in] cmd_recv_cb Callback to be run when data is received while
+ * waiting for a command reply.
+ *
+ * \warning If this callback is not set, data received while waiting for a
+ * command reply will be silently discarded.
+ ****************************************************************************/
+void mw_cmd_data_cb_set(lsd_recv_cb cmd_recv_cb);
+
+/************************************************************************//**
+ * \brief Performs the startup sequence for the WiFi module, and tries
+ * detecting it by requesting the version data.
+ *
+ * \param[out] major Major version number.
+ * \param[out] minor Minor version number.
+ * \param[out] variant String with firmware variant ("std" for standard).
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+enum mw_err mw_detect(uint8_t *major, uint8_t *minor, char **variant);
+
+/************************************************************************//**
+ * \brief Obtain module version numbers and string
+ *
+ * \param[out] version Version numbers (major, minor, micro) in order.
+ * \param[out] variant String with firmware variant ("std" for standard).
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+enum mw_err mw_version_get(uint8_t version[3], char **variant);
+
+/************************************************************************//**
+ * \brief Gets the module BSSID (the MAC address) for the specified interface.
+ *
+ * \param[in] interface_type Type of the interface to obtain BSSID from.
+ *
+ * \return The requested BSSID (6 byte binary data), or NULL on error.
+ ****************************************************************************/
+uint8_t *mw_bssid_get(enum mw_if_type interface_type);
+
+/************************************************************************//**
+ * \brief Set default module configuration (AKA factory settings).
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ *
+ * \note For this command to take effect, it must be followed by a module
+ * reset.
+ ****************************************************************************/
+enum mw_err mw_default_cfg_set(void);
+
+/************************************************************************//**
+ * \brief Set access point configuration (SSID and password).
+ *
+ * \param[in] slot Configuration slot to use.
+ * \param[in] ssid String with the AP SSID to set.
+ * \param[in] pass String with the AP SSID to set.
+ * \param[in] phy_type Bitmask with the PHY type configuration.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ *
+ * \note Strings must be NULL terminated. Maximum SSID length is 32 bytes,
+ * maximum pass length is 64 bytes.
+ * \note After a successful invocation, call mw_cfg_save() for changes to
+ * be persistent
+ ****************************************************************************/
+enum mw_err mw_ap_cfg_set(uint8_t slot, const char *ssid, const char *pass,
+ enum mw_phy_type phy_type);
+
+/************************************************************************//**
+ * \brief Gets access point configuration (SSID and password).
+ *
+ * \param[in] slot Configuration slot to use.
+ * \param[out] ssid String with the AP SSID got.
+ * \param[out] pass String with the AP SSID got.
+ * \param[out] phy_type Bitmask with the PHY type configuration.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ *
+ * \warning ssid is zero padded up to 32 bytes, and pass is zero padded up
+ * to 64 bytes. If ssid is 32 bytes, it will NOT be NULL terminated.
+ * Also if pass is 64 bytes, it will NOT be NULL terminated.
+ ****************************************************************************/
+enum mw_err mw_ap_cfg_get(uint8_t slot, char **ssid, char **pass,
+ enum mw_phy_type *phy_type);
+
+/************************************************************************//**
+ * \brief Set IPv4 configuration.
+ *
+ * \param[in] slot Configuration slot to use.
+ * \param[in] ip Pointer to the mw_ip_cfg structure, with IP configuration.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ *
+ * \note After a successful invocation, call mw_cfg_save() for changes to
+ * be persistent
+ ****************************************************************************/
+enum mw_err mw_ip_cfg_set(uint8_t slot, const struct mw_ip_cfg *ip);
+
+/************************************************************************//**
+ * \brief Get IPv4 configuration.
+ *
+ * \param[in] slot Configuration slot to use.
+ * \param[out] ip Double pointer to mw_ip_cfg structure, with IP conf.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+enum mw_err mw_ip_cfg_get(uint8_t slot, struct mw_ip_cfg **ip);
+
+/************************************************************************//**
+ * \brief Set advanced WiFi configuration.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ *
+ * \warning This function is dangerous. Changing these parameters is rarely
+ * needed, and setting incorrect values, may render the connection unstable
+ * and/or crash the WiFi module. Invalid configurations can even cause the
+ * module to crash in a bootloop, requiring a programmer to unbrick it.
+ * Make sure you thoroughly test the values you allow users to set here.
+ * \note If you want to change WiFi parameters, the recommendation is to get
+ * the current configuration via mw_wifi_adv_cfg_get(), and from it change
+ * only the required parameters.
+ * \note These parameters will not take effect until saved to non-volatile
+ * storage (with mw_cfg_save()) and issuing a module reboot.
+ ****************************************************************************/
+enum mw_err mw_wifi_adv_cfg_set(const struct mw_wifi_adv_cfg *wifi);
+
+/************************************************************************//**
+ * \brief Get advanced WiFi configuration.
+ *
+ * \return Pointer to the advanced WiFi configuration, or NULL on error.
+ ****************************************************************************/
+struct mw_wifi_adv_cfg *mw_wifi_adv_cfg_get(void);
+
+/************************************************************************//**
+ * \brief Saves changed configuration parameters to non-volatile memory.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+enum mw_err mw_cfg_save(void);
+
+/************************************************************************//**
+ * \brief Get current IP configuration, of the joined AP.
+ *
+ * \param[out] ip Double pointer to mw_ip_cfg structure, with IP conf.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+enum mw_err mw_ip_current(struct mw_ip_cfg **ip);
+
+/************************************************************************//**
+ * \brief Scan for access points.
+ *
+ * \param[in] phy_type Bitmask with the PHY type configuration.
+ * \param[out] ap_data Data of the found access points. Each entry has the
+ * format specified on the mw_ap_data structure.
+ * \param[out] aps Number of found access points.
+ *
+ * \return Length in bytes of the output data if operation completes
+ * successfully, or -1 if scan fails.
+ ****************************************************************************/
+int16_t mw_ap_scan(enum mw_phy_type phy_type, char **ap_data, uint8_t *aps);
+
+/************************************************************************//**
+ * \brief Parses received AP data and fills information of the AP at "pos".
+ * Useful to extract AP information from the data obtained by
+ * calling mw_ap_scan() function.
+ *
+ * \param[in] ap_data Access point data obtained from mw_ap_scan().
+ * \param[in] pos Position at which to extract data.
+ * \param[out] apd Pointer to the extracted data from an AP.
+ * \param[in] data_len Lenght of apData.
+ *
+ * \return Position of the next AP entry in apData, 0 if no more APs
+ * available or MW_ERROR if ap data/pos combination is not valid.
+ *
+ * \note This functions executes locally, does not communicate with the
+ * WiFi module.
+ ****************************************************************************/
+int16_t mw_ap_fill_next(const char *ap_data, uint16_t pos,
+ struct mw_ap_data *apd, uint16_t data_len);
+
+/************************************************************************//**
+ * \brief Tries associating to an AP. If successful, also configures IPv4.
+ *
+ * \param[in] slot Configuration slot to use.
+ *
+ * \return MW_ERR_NONE if AP join operation has been successfully started,
+ ****************************************************************************/
+enum mw_err mw_ap_assoc(uint8_t slot);
+
+/************************************************************************//**
+ * \brief Polls the module status until it reports device is associated to
+ * AP or timeout occurs.
+ *
+ * \param[in] tout_frames Maximun number of frames to wait for association.
+ * Set to TSK_PEND_FOREVER for an infinite wait.
+ *
+ * \return MW_ERR_NONE if device is associated to AP. MW_ERR_NOT_READY if
+ * the timeout has expired.
+ ****************************************************************************/
+enum mw_err mw_ap_assoc_wait(int16_t tout_frames);
+
+/************************************************************************//**
+ * \brief Sets default AP/IP configuration.
+ *
+ * \param[in] slot Configuration slot to use.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ *
+ * \note After a successful invocation, call mw_cfg_save() for changes to
+ * be persistent
+ ****************************************************************************/
+enum mw_err mw_def_ap_cfg(uint8_t slot);
+
+/************************************************************************//**
+ * \brief Dissasociates from a previously associated AP.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+enum mw_err mw_ap_disassoc(void);
+
+/************************************************************************//**
+ * \brief Gets default AP/IP configuration slot.
+ *
+ * \return The default configuration slot, of -1 on error.
+ ****************************************************************************/
+int16_t mw_def_ap_cfg_get(void);
+
+/************************************************************************//**
+ * \brief Tries establishing a TCP connection with specified server.
+ *
+ * \param[in] ch Channel used for the connection.
+ * \param[in] dst_addr Address (IP or DNS entry) of the server.
+ * \param[in] dst_port Port in which server is listening.
+ * \param[in] src_port Port from which try establishing connection. Set to
+ * 0 or empty string for automatic port allocation.
+ *
+ * \return MW_ERR_NONE on success, other code if connection failed.
+ ****************************************************************************/
+enum mw_err mw_tcp_connect(uint8_t ch, const char *dst_addr,
+ const char *dst_port, const char *src_port);
+
+/************************************************************************//**
+ * \brief Closes and disconnects a socket from specified channel.
+ *
+ * This function can be used to free the channel associated to both TCP and
+ * UDP sockets.
+ *
+ * \param[in] ch Channel associated to the socket to disconnect.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+enum mw_err mw_close(uint8_t ch);
+
+/// Closes a TCP socket. This is an alias of mw_close().
+#define mw_tcp_disconnect(ch) mw_close(ch)
+
+/************************************************************************//**
+ * \brief Configures a UDP socket to send/receive data.
+ *
+ * \param[in] ch Channel used for the connection.
+ * \param[in] dst_addr Address (IP or DNS entry) to send data to.
+ * \param[in] dst_port Port to send data to.
+ * \param[in] src_port Local port to listen message on.
+ *
+ * \return MW_ERR_NONE on success, other code if connection failed.
+ *
+ * \note Setting to NULL dst_addr and/or dst_port, enables reuse mode.
+ ****************************************************************************/
+enum mw_err mw_udp_set(uint8_t ch, const char *dst_addr, const char *dst_port,
+ const char *src_port);
+
+/// Frees a UDP socket. This is an alias of mw_close().
+#define mw_udp_unset(ch) mw_close(ch)
+
+/************************************************************************//**
+ * \brief Binds a socket to a port, and listens to connections on the port.
+ * If a connection request is received, it will be automatically
+ * accepted.
+ *
+ * \param[in] ch Channel associated to the socket bound t port.
+ * \param[in] port Port number to which the socket will be bound.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+enum mw_err mw_tcp_bind(uint8_t ch, uint16_t port);
+
+/************************************************************************//**
+ * \brief Polls a socket until it is ready to transfer data. Typical use of
+ * this function is after a successful mw_tcp_bind().
+ *
+ * \param[in] ch Channel associated to the socket to monitor.
+ * \param[in] tout_frames Maximum number of frames to wait for connection.
+ * Set to 0 for an infinite wait.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+enum mw_err mw_sock_conn_wait(uint8_t ch, int16_t tout_frames);
+
+/************************************************************************//**
+ * \brief Receive data, asyncrhonous interface.
+ *
+ * \param[in] buf Reception buffer.
+ * \param[in] len Length of the receive buffer.
+ * \param[in] ctx Context pointer to pass to the reception callbak.
+ * \param[in] recv_cb Callback to run when reception is complete or errors.
+ *
+ * \return Status of the receive procedure.
+ ****************************************************************************/
+static inline enum lsd_status mw_recv(char *buf, int16_t len, void *ctx,
+ lsd_recv_cb recv_cb)
+{
+ return lsd_recv(buf, len, ctx, recv_cb);
+}
+
+/************************************************************************//**
+ * \brief Receive data using an UDP socket in reuse mode.
+ *
+ * \param[in] data Receive buffer including the remote address and the
+ * data payload.
+ * \param[in] len Length of the receive buffer.
+ * \param[in] ctx Context pointer to pass to the reception callbak.
+ * \param[in] recv_cb Callback to run when reception is complete or errors.
+ *
+ * \return Status of the receive procedure.
+ ****************************************************************************/
+static inline enum lsd_status mw_udp_reuse_recv(struct mw_reuse_payload *data,
+ int16_t len, void *ctx, lsd_recv_cb recv_cb)
+{
+ return lsd_recv((char*)data, len, ctx, recv_cb);
+}
+
+/************************************************************************//**
+ * \brief Send data using a UDP socket in reuse mode.
+ *
+ * \param[in] ch Channel to use for the send operation.
+ * \param[in] data Send buffer including the remote address and the
+ * data payload.
+ * \param[in] len Length of the receive buffer.
+ * \param[in] ctx Context pointer to pass to the reception callbak.
+ * \param[in] send_cb Callback to run when sending completes or errors.
+ *
+ * \return Status of the receive procedure.
+ ****************************************************************************/
+static inline enum lsd_status mw_udp_reuse_send(uint8_t ch,
+ const struct mw_reuse_payload *data, int16_t len, void *ctx,
+ lsd_send_cb send_cb)
+{
+ return lsd_send(ch, (const char*)data, len, ctx, send_cb);
+}
+
+/************************************************************************//**
+ * \brief Sends data through a socket, using a previously allocated channel.
+ * Asynchronous interface.
+ *
+ * \param[in] ch Channel used to send the data.
+ * \param[in] data Buffer to send.
+ * \param[in] len Length of the data to send.
+ * \param[in] ctx Context for the send callback function.
+ * \param[in] send_cb Callback to run when send completes or errors.
+ *
+ * \return Status of the send procedure. Usually LSD_STAT_BUSY is returned,
+ * and the send procedure is then performed in background.
+ * \note Calling this function while there is a send procedure in progress,
+ * will cause the function call to fail with LSD_STAT_SEND_ERR_IN_PROGRESS.
+ * \warning For very short data frames, it is possible that the send callback
+ * is run before this function returns. In this case, the function returns
+ * LSD_STAT_COMPLETE.
+ ****************************************************************************/
+static inline enum lsd_status mw_send(uint8_t ch, const char *data, int16_t len,
+ void *ctx, lsd_send_cb send_cb)
+{
+ return lsd_send(ch, data, len, ctx, send_cb);
+}
+
+/************************************************************************//**
+ * \brief Receive data, syncrhonous interface.
+ *
+ * \param[out] ch Channel on which data was received.
+ * \param[out] buf Reception buffer.
+ * \param[inout] buf_len On input, length of the buffer.
+ * On output, received data length in bytes.
+ * \param[in] tout_frames Reception timeout in frames. Set to TSK_PEND_FOREVER
+ * for infinite wait (dangerous!).
+ *
+ * \return Status of the receive procedure.
+ * \warning Do not use more than one syncrhonous call at once. You must wait
+ * until a syncrhonous call ends to issue another one.
+ ****************************************************************************/
+enum mw_err mw_recv_sync(uint8_t *ch, char *buf, int16_t *buf_len,
+ int16_t tout_frames);
+
+/************************************************************************//**
+ * \brief Sends data through a socket, using a previously allocated channel.
+ * Synchronous interface.
+ *
+ * \param[in] ch Channel used to send the data.
+ * \param[in] data Buffer to send.
+ * \param[in] len Length of the data to send.
+ * \param[in] tout_frames Timeout for send operation in frames. Set to 0 for
+ * infinite wait (dangerous!).
+ *
+ * \return Status of the send procedure. Usually LSD_STAT_BUSY is returned,
+ * and the send procedure is then performed in background.
+ * \warning Do not use more than one syncrhonous call at once. You must wait
+ * until a syncrhonous call ends to issue another one.
+ ****************************************************************************/
+enum mw_err mw_send_sync(uint8_t ch, const char *data, uint16_t len,
+ int16_t tout_frames);
+
+/************************************************************************//**
+ * \brief Get system status.
+ *
+ * \return Pointer to system status structure on success, or NULL on error.
+ ****************************************************************************/
+union mw_msg_sys_stat *mw_sys_stat_get(void);
+
+/************************************************************************//**
+ * \brief Get socket status.
+ *
+ * \param[in] ch Channel associated to the socket asked for status.
+ *
+ * \return Socket status data on success, or -1 on error.
+ ****************************************************************************/
+enum mw_sock_stat mw_sock_stat_get(uint8_t ch);
+
+/************************************************************************//**
+ * \brief Configure SNTP parameters and timezone.
+ *
+ * \param[in] tz_str Timezone string (e.g. "CET"). See tzset(3) for details.
+ * \param[in] server Array of up to three NTP servers. If less than three
+ * servers are desired, unused entries must be empty.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ *
+ * \note After a successful invocation, call mw_cfg_save() for changes to
+ * be persistent
+ ****************************************************************************/
+enum mw_err mw_sntp_cfg_set(const char *tz_str, const char *server[3]);
+
+/************************************************************************//**
+ * \brief Get SNTP parameters and timezone configuration.
+ *
+ * \param[out] tz_str Timezone string (e.g. "CET"). See tzset(3) for details.
+ * \param[out] server Array of three NTP server pointers. If less than 3
+ * servers are configured, unused ones will be NULL.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+enum mw_err mw_sntp_cfg_get(char **tz_str, char *server[3]);
+
+/************************************************************************//**
+ * \brief Get date and time.
+ *
+ * \param[out] dt_bin Date and time in seconds since Epoch. If set to NULL,
+ * this info is not filled (but return value will still
+ * be properly set).
+ *
+ * \return A string with the date and time in textual format, e.g.: "Thu Mar
+ * 3 12:26:51 2016", or NULL if error.
+ ****************************************************************************/
+char *mw_date_time_get(uint32_t dt_bin[2]);
+
+/************************************************************************//**
+ * \brief Get the identifiers of the flash chip in the WiFi module.
+ *
+ * \param[out] man_id ID of the flash chip manufacturer.
+ * \param[out] dev_id Device IDs of the flash chip.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+enum mw_err mw_flash_id_get(uint8_t *man_id, uint16_t *dev_id);
+
+/************************************************************************//**
+ * \brief Erase a 4 KiB Flash sector. Every byte of an erased sector will be
+ * read as 0xFF.
+ *
+ * \param[in] sect Sector number to erase.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+enum mw_err mw_flash_sector_erase(uint16_t sect);
+
+/************************************************************************//**
+ * \brief Write data to specified flash address.
+ *
+ * \param[in] addr Address to which data will be written.
+ * \param[in] data Data to be written to flash chip.
+ * \param[in] data_len Length in bytes of data field.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+enum mw_err mw_flash_write(uint32_t addr, uint8_t *data, uint16_t data_len);
+
+/************************************************************************//**
+ * \brief Read data from specified flash address.
+ *
+ * \param[in] addr Address from which data will be read.
+ * \param[in] data_len Number of bytes to read from addr.
+ *
+ * \return Pointer to read data on success, or NULL if command failed.
+ ****************************************************************************/
+uint8_t *mw_flash_read(uint32_t addr, uint16_t data_len);
+
+/************************************************************************//**
+ * \brief Puts the WiFi module in reset state.
+ ****************************************************************************/
+#define mw_module_reset() do{uart_set_bits(MCR, MW__RESET);}while(0)
+
+/************************************************************************//**
+ * \brief Releases the module from reset state.
+ ****************************************************************************/
+#define mw_module_start() do{uart_clr_bits(MCR, MW__RESET);}while(0)
+
+/************************************************************************//**
+ * \brief Set gamertag information for one slot.
+ *
+ * \param[in] slot Slot to use (from 0 to 2).
+ * \param[in] gamertag Gamertag information to set on specified slot.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ *
+ * \note After a successful invocation, call mw_cfg_save() for changes to
+ * be persistent
+ ****************************************************************************/
+enum mw_err mw_gamertag_set(uint8_t slot, const struct mw_gamertag *gamertag);
+
+/************************************************************************//**
+ * \brief Get gamertag information for one slot.
+ *
+ * \param[in] slot Slot to get gamertag from.
+ *
+ * \return Gamertag information on success, NULL on error.
+ ****************************************************************************/
+struct mw_gamertag *mw_gamertag_get(uint8_t slot);
+
+/************************************************************************//**
+ * \brief Write a message to the WiFi module log trace.
+ *
+ * \param[in] msg Message to write to the log trace.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+enum mw_err mw_log(const char *msg);
+
+/************************************************************************//**
+ * \brief Set factory default configuration.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ * \note It is recommended to reboot the module after this command.
+ ****************************************************************************/
+enum mw_err mw_factory_settings(void);
+
+/************************************************************************//**
+ * \brief Powers off the WiFi module.
+ *
+ * The module will be put in deep sleep mode. To wake it up, the RESET pin
+ * must be toggled.
+ ****************************************************************************/
+void mw_power_off(void);
+
+/************************************************************************//**
+ * \brief Sleep the specified amount of frames
+ *
+ * \param[in] frames Number of frames to sleep.
+ ****************************************************************************/
+void mw_sleep(int16_t frames);
+
+/************************************************************************//**
+ * \brief Set URL for HTTP requests.
+ *
+ * \param[in] url URL to set.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+enum mw_err mw_http_url_set(const char *url);
+
+/************************************************************************//**
+ * \brief Set method for HTTP requests.
+ *
+ * \param[in] method Method to set.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+enum mw_err mw_http_method_set(enum mw_http_method method);
+
+/************************************************************************//**
+ * \brief Add an HTTP header.
+ *
+ * \param[in] key Header key.
+ * \param[in] value Value to set for the key.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+enum mw_err mw_http_header_add(const char *key, const char *value);
+
+/************************************************************************//**
+ * \brief Delete a previously added HTTP header.
+ *
+ * \param[in] key Key of the header to delete.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+enum mw_err mw_http_header_del(const char *key);
+
+/************************************************************************//**
+ * \brief Open HTTP connection.
+ *
+ * This functions opens the HTTP connection, sends the HTTP headers, and
+ * prepares the module to send the specified content_len if (if any) with
+ * a successive mw_send() or mw_send_sync(), using MW_HTTP_CH channel.
+ *
+ * \param[in] content_len Length of the content to write in HTTP request,
+ * after a successfull call to this function.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+enum mw_err mw_http_open(uint32_t content_len);
+
+/************************************************************************//**
+ * \brief Finish an opened HTTP request.
+ *
+ * After a successful call to mw_http_open(), and sending the content (if
+ * any), call this function to receive the HTTP response headers, and obtain
+ * the length of the body to receive with a further call to mw_recv() or
+ * mw_recv_sync(), using MW_HTTP_CH.
+ *
+ * \param[out] content_len Length of the response content to receive after a
+ * successfull call to this function.
+ * \param[in] tout_frames Maximun number of frames to wait for reply.
+ *
+ * \return The HTTP status code if the request was completed, or an error
+ * code (lower than 100) if the HTTP request did not complete.
+ * \note Even if the HTTP request is completed, that does not mean there are
+ * no errors, if the returned status code is 4xx or 5xx, there is a client
+ * side or server side error.
+ ****************************************************************************/
+int16_t mw_http_finish(uint32_t *content_len, int16_t tout_frames);
+
+/************************************************************************//**
+ * \brief Query the X.509 hash of the installed PEM certificate.
+ *
+ * \return 0xFFFFFFFF if certificate is not installed or error occurs, or
+ * the installed X.509 certificate hash on success.
+ ****************************************************************************/
+uint32_t mw_http_cert_query(void);
+
+/************************************************************************//**
+ * \brief Set the PEM certificate to use on HTTPS requests.
+ *
+ * The certificate is stored on the non volatile memory of the module, and
+ * when present will be used in HTTPS requestes. This function can also be
+ * used to delete a previously saved certificate using a NULL input value.
+ *
+ * \param[in] cert_hash X.509 hash of the certificate to set, ignored if
+ * cert_len set to 0.
+ * \param[in] cert PEM certificate in plain text. Ignored if cert_len
+ * set to 0.
+ * previously stored certificate.
+ * \param[in] cert_len Certificate length in bytes. Set to 0 to delete a
+ * previously stored certificate.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+enum mw_err mw_http_cert_set(uint32_t cert_hash, const char *cert,
+ uint16_t cert_len);
+
+/************************************************************************//**
+ * \brief Clean-up an HTTP request, freeing associated resources.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ ****************************************************************************/
+int16_t mw_http_cleanup(void);
+
+/************************************************************************//**
+ * \brief Get the default server used for MegaWiFi connections.
+ *
+ * \return The server URL string, or NULL on error.
+ ****************************************************************************/
+char *mw_def_server_get(void);
+
+/************************************************************************//**
+ * \brief Set the default server used for MegaWiFi connections.
+ *
+ * \param[in] server_url The server URL to set.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ *
+ * \note After a successful invocation, call mw_cfg_save() for changes to
+ * be persistent
+ ****************************************************************************/
+enum mw_err mw_def_server_set(const char *server_url);
+
+/************************************************************************//**
+ * \brief Get random numbers.
+ *
+ * \param[in] rnd_len Number of bytes of resulting random array.
+ *
+ * \return The buffer with the requested random numbers on success, or NULL
+ * when error.
+ ****************************************************************************/
+uint8_t *mw_hrng_get(uint16_t rnd_len);
+
+/************************************************************************//**
+ * \brief Set endpoint for Game API.
+ *
+ * Example endpoint for GameJolt: "https://api.gamejolt.com/api/game/v1_2/".
+ *
+ * \param[in] endpoint Endpoint for the Game API to set.
+ * \param[in] priv_key Private key used for request signatures.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ *
+ * \note The endpoint set persists between successive mw_ga_request() calls.
+ ****************************************************************************/
+enum mw_err mw_ga_endpoint_set(const char *endpoint, const char *priv_key);
+
+/************************************************************************//**
+ * \brief Add parameters to the Game API request in key/value format.
+ *
+ * Example key:value pair for GameJolt: "game_id":"123456".
+ *
+ * \param[in] key Array with the keys to add.
+ * \param[in] value Array with the values to add
+ * \param[in] num_pairs Number of key/value pairs to add.
+ *
+ * \return MW_ERR_NONE on success, other code on failure.
+ *
+ * \note The key/value pairs set persist between successive mw_ga_request()
+ * calls.
+ * \note Call mw_ga_key_value_add(NULL, NULL, 0) to clear previously set
+ * key/value pairs.
+ * \note Key/value pairs must NOT be URL encoded. Encoding is handled
+ * internally.
+ ****************************************************************************/
+enum mw_err mw_ga_key_value_add(const char **key, const char **value,
+ uint16_t num_pairs);
+
+/************************************************************************//**
+ * \brief Perform a GameAPI request, with the previously set endpoint and
+ * key/value pairs.
+ *
+ * The request can also have URL encoded parameters. that are added to the
+ * previously set key/value pairs.
+ *
+ * Example request for GameJolt:
+ * - method: MW_HTTP_METHOD_GET
+ * - path: "trophies"
+ * - key:value: "achieved":"true"
+ *
+ * \param[in] method HTTP method to use. Most likely MW_HTTP_METHOD_GET.
+ * \param[in] path Additional paths to add to the request.
+ * \param[in] num_paths Number of additional paths to add.
+ * \param[in] key Additional paths to add to the request.
+ * \param[in] value Additional paths to add to the request.
+ * \param[in] num_kv_pairs Number of key/value pairs.
+ * \param[out] content_len Content length of the API response.
+ * \param[in] tout_frames Number of frames to wait before canceling the
+ * request due to a timeout error.
+ *
+ * \return HTTP status code on success (e.g. 200), or an error (lower than
+ * 100) if the HTTP request could not be completed.
+ * \note Even if the HTTP request is completed, that does not mean there are
+ * no errors, if the returned status code is 4xx or 5xx, there is a client
+ * side or server side error.
+ * \note path, key and value parameters must not be URL encoded. Encoding is
+ * handled internally.
+ ****************************************************************************/
+int16_t mw_ga_request(enum mw_http_method method, const char **path,
+ uint8_t num_paths, const char **key, const char **value,
+ uint8_t num_kv_pairs, uint32_t *content_len,
+ int16_t tout_frames);
+
+/************************************************************************//**
+ * \brief List available upgrades WiFi module firmware.
+ *
+ * \param[in] page Page of list
+ * \param[in] page_size Page size of list
+ * \param[in] offset Offset number
+ * \param[out] listUpgrades Pointer to list of char*
+ * \param[out] len Result length
+ * \param[out] total Total elements
+ *
+ * \return Status of the send procedure.
+ ****************************************************************************/
+enum mw_err mw_fw_list_upgrades(uint8_t page, uint8_t size, uint8_t offset, char **listUpgrades, uint8_t *len, uint8_t *total);
+
+/************************************************************************//**
+ * \brief Over-The-Air upgrade WiFi module firmware.
+ *
+ * \param[in] name Name of the firmware blob to upgrade.
+ * E.g. "mw_rtos_std_v1.4.1"
+ *
+ * \return Status of the send procedure.
+ ****************************************************************************/
+enum mw_err mw_fw_upgrade(const char *name);
+
+/************************************************************************//**
+ * \brief Run ICMP requesto to domain.
+ *
+ * \param[in] domain Domain to ICMP request.
+ * E.g. "www.example.com"
+ * \param[in] retries retries to ICMP request
+ * E.g. 5
+ *
+ * \return Status of the send procedure.
+ ****************************************************************************/
+struct mw_ping_response *mw_ping(const char* domain, u8 retries);
+
+/****** THE FOLLOWING COMMANDS ARE LOWER LEVEL AND USUALLY NOT NEEDED ******/
+
+/************************************************************************//**
+ * \brief Send a command to the WiFi module.
+ *
+ * \param[in] cmd Pointer to the filled mw_cmd command structure.
+ * \param[in] ctx Context for callback function.
+ * \param[in] send_cb Callback for the send operation completion.
+ *
+ * \return Status of the send procedure.
+ ****************************************************************************/
+static inline enum lsd_status mw_cmd_send(mw_cmd *cmd, void *ctx,
+ lsd_send_cb send_cb)
+{
+ // Send data on control channel (0).
+ return lsd_send(MW_CTRL_CH, cmd->packet, cmd->data_len + 4,
+ ctx, send_cb);
+}
+
+/************************************************************************//**
+ * \brief Try obtaining a reply to a command.
+ *
+ * \param[in] rep Buffer to hold the command reply.
+ * \param[in] ctx Context for the reception callback.
+ * \param[in] recv_cb Callback for data reception completion.
+ *
+ * \return Status of the reception procedure.
+ ****************************************************************************/
+static inline enum lsd_status mw_cmd_recv(mw_cmd *rep, void *ctx,
+ lsd_recv_cb recv_cb) {
+ return lsd_recv(rep->packet, sizeof(mw_cmd), ctx, recv_cb);
+}
+
+#endif /*_MEGAWIFI_H_*/
+
+/** \} */
+
diff --git a/inc/ext/mw/mw-msg.h b/inc/ext/mw/mw-msg.h
index 668fed54..5707ff9b 100644
--- a/inc/ext/mw/mw-msg.h
+++ b/inc/ext/mw/mw-msg.h
@@ -12,7 +12,8 @@
* is not directly used by the application, but by megawifi internally.
*
* \author Jesus Alonso (doragasu)
- * \date 2015~2019
+ * \author Juan Antonio (PaCHoN)
+ * \date 2015~2025
****************************************************************************/
#ifndef _MW_MSG_H_
#define _MW_MSG_H_
@@ -310,6 +311,23 @@ struct mw_ga_request {
char req[]; ///< Request data
};
+struct mw_ping_request{
+ uint8_t retries;
+ char domain[64];
+};
+
+struct mw_ping_response{
+ uint32_t transmitted;
+ uint32_t received;
+ uint32_t total_time_ms;
+};
+
+struct mw_upgrade_list_response{
+ uint16_t total;
+ uint16_t len;
+ char *payload;
+};
+
/// Command sent to system FSM
typedef union mw_cmd {
char packet[MW_CMD_MAX_BUFLEN + 2 * sizeof(uint16_t)]; ///< Packet raw data
@@ -334,6 +352,9 @@ typedef union mw_cmd {
struct mw_msg_flash_data fl_data; ///< Flash memory data
struct mw_msg_flash_range fl_range; ///< Flash memory range
struct mw_msg_bind bind; ///< Bind message
+ struct mw_ping_request ping; ///< Ping message
+ struct mw_ping_response ping_response; ///< Ping message
+ struct mw_upgrade_list_response ug_list_response; ///< Ping message
union mw_msg_sys_stat sys_stat; ///< System status
struct mw_gamertag_set_msg gamertag_set;///< Gamertag set
struct mw_gamertag gamertag_get; ///< Gamertag get
diff --git a/inc/ext/mw/ssf.h b/inc/ext/mw/ssf.h
new file mode 100644
index 00000000..d5337ae2
--- /dev/null
+++ b/inc/ext/mw/ssf.h
@@ -0,0 +1,148 @@
+/************************************************************************
+ * \brief Simple SSF driver.
+ *
+ * \author Juan Antonio Ruiz (PaCHoN)
+ * \date 2024
+ * \defgroup SSF SSF
+ * \brief
+ * USB IO
+ * 0xA130E2 [........ DDDDDDDD] read/write
+ * D data bits
+ *
+ * IO status
+ * 0xA130E4 [.C...... .....RWS] read only
+ * S SPI controller ready. Not used on WIFI.
+ * W USB fifo ready to write
+ * R USB fifo ready to read
+ * C SD card type. 0=SD, 1=SDHC. Not used on WIFI.
+*************************************** */
+#ifndef _SSF_H_
+#define _SSF_H
+
+#include "config.h"
+#include "types.h"
+
+#if (MODULE_MEGAWIFI == 1 && MODULE_EVERDRIVE == 1)
+//#define SSF_CTRL_P 0x8000 //register accesss protection bit. should be set, otherwise register will ignore any attempts to write
+//#define SSF_CTRL_X 0x4000 //32x mode
+//#define SSF_CTRL_W 0x2000 //ROM memory write protection
+//#define SSF_CTRL_L 0x1000 //led
+
+//#define USB_RD_BUSY while ((REG_STE & STE_USB_RD_RDY) == 0)
+//#define USB_WR_BUSY while ((REG_STE & STE_USB_WR_RDY) == 0)
+/**************************************** */
+
+
+/// SSF UART base address
+#define UART_BASE 0xA13000
+
+/// Length of the TX FIFO in bytes
+#define UART_TX_FIFO_LEN 1
+
+/// Receiver holding register. Read only.
+#define UART_DATA (*((volatile u16*)(UART_BASE + 226)))
+#define UART_STE (*((volatile u16*)(UART_BASE + 228)))
+#define UART_REG_CFG (*((volatile u16*)(UART_BASE + 230)))
+#define UART_REG_SSF_CTRL (*((volatile u16*)(UART_BASE + 240)))
+
+#define SSF_CTRL_P 0x8000 //register accesss protection bit. should be set, otherwise register will ignore any attempts to write
+#define SSF_CTRL_X 0x4000 //32x mode
+#define SSF_CTRL_W 0x2000 //ROM memory write protection
+#define SSF_CTRL_L 0x1000 //led
+
+#define UART_SPR UART_DATA
+
+#define UART_STE_WR_RDY 2//usb write ready bit
+#define UART_STE_RD_RDY 4//usb read ready bit
+
+//spi chip select signal
+#define CFG_SPI_SS 1
+#define CFG_SPI_QRD 6
+#define CFG_SPI_QWR 2
+
+/************************************************************************//**
+ * \brief Initializes the driver. The baud rate is set to UART_BR, and the
+ * UART FIFOs are enabled. This function must be called before using
+ * any other API call.
+ ****************************************************************************/
+void uart_init(void);
+
+/************************************************************************//**
+ * \brief Checks if UART transmit register/FIFO is ready. In FIFO mode, up to
+ * 16 characters can be loaded each time transmitter is ready.
+ *
+ * \return TRUE if transmitter is ready, FALSE otherwise.
+ ****************************************************************************/
+#define uart_tx_ready() (UART_STE & UART_STE_WR_RDY)
+
+/************************************************************************//**
+ * \brief Checks if UART receive register/FIFO has data available.
+ *
+ * \return TRUE if at least 1 byte is available, FALSE otherwise.
+ ****************************************************************************/
+#define uart_rx_ready() (UART_STE & UART_STE_RD_RDY)
+
+/************************************************************************//**
+ * \brief Sends a character. Please make sure there is room in the transmit
+ * register/FIFO by calling uart_rx_ready() before using this function.
+ *
+ * \return Received character.
+ ****************************************************************************/
+#define uart_putc(c) do{UART_DATA = (c);}while(0);
+
+/************************************************************************//**
+ * \brief Returns a received character. Please make sure data is available by
+ * calling uart_rx_ready() before using this function.
+ *
+ * \return Received character.
+ ****************************************************************************/
+#define uart_getc() (UART_DATA)
+
+/************************************************************************//**
+ * \brief Sets a value in IER, FCR, LCR or MCR register.
+ *
+ * \param[in] reg Register to modify (IER, FCR, LCR or MCR).
+ * \param[in] val Value to set in IER, FCR, LCR or MCR register.
+ ****************************************************************************/
+#define uart_set(reg, val) while(0);
+
+/************************************************************************//**
+ * \brief Gets value of IER, FCR, LCR or MCR register.
+ *
+ * \param[in] reg Register to read (IER, FCR, LCR or MCR).
+ * \return The value of the requested register.
+ ****************************************************************************/
+#define uart_get(reg) while(0);
+
+/************************************************************************//**
+ * \brief Sets bits in IER, FCR, LCR or MCR register.
+ *
+ * \param[in] reg Register to modify (IER, FCR, LCR or MCR).
+ * \param[in] val Bits set in val, will be set in reg register.
+ ****************************************************************************/
+#define uart_set_bits(reg, val) while(0)
+
+/************************************************************************//**
+ * \brief Clears bits in IER, FCR, LCR or MCR register.
+ *
+ * \param[in] reg Register to modify (IER, FCR, LCR or MCR).
+ * \param[in] val Bits set in val, will be cleared in reg register.
+ ****************************************************************************/
+#define uart_clr_bits(reg, val) while(0)
+
+/************************************************************************//**
+ * \brief Test Connection with registers
+ *
+ * \param[in] reg Register to modify
+ * \param[in] val Bits set in val, will be readed from reg register.
+ ****************************************************************************/
+#define uart_test(reg, val) while(0)
+
+/************************************************************************//**
+ * \brief Reset TX and RX FIFOs.
+ ****************************************************************************/
+#define uart_reset_fifos() while(0)
+void ssf_set_rom_bank(u8 bank, u8 val);
+#endif
+#endif /*_SSF_H_*/
+
diff --git a/sample/megawifi/megawifi.cbp b/sample/megawifi/basic/megawifi.cbp
similarity index 100%
rename from sample/megawifi/megawifi.cbp
rename to sample/megawifi/basic/megawifi.cbp
diff --git a/sample/megawifi/out/rom.bin b/sample/megawifi/basic/out/rom.bin
similarity index 100%
rename from sample/megawifi/out/rom.bin
rename to sample/megawifi/basic/out/rom.bin
diff --git a/sample/megawifi/src/boot/rom_head.c b/sample/megawifi/basic/src/boot/rom_head.c
similarity index 100%
rename from sample/megawifi/src/boot/rom_head.c
rename to sample/megawifi/basic/src/boot/rom_head.c
diff --git a/sample/megawifi/src/boot/sega.s b/sample/megawifi/basic/src/boot/sega.s
similarity index 100%
rename from sample/megawifi/src/boot/sega.s
rename to sample/megawifi/basic/src/boot/sega.s
diff --git a/sample/megawifi/src/main.c b/sample/megawifi/basic/src/main.c
similarity index 100%
rename from sample/megawifi/src/main.c
rename to sample/megawifi/basic/src/main.c
diff --git a/sample/megawifi/menu/.gitignore b/sample/megawifi/menu/.gitignore
new file mode 100644
index 00000000..cfd08c85
--- /dev/null
+++ b/sample/megawifi/menu/.gitignore
@@ -0,0 +1,3 @@
+out/
+src/boot/
+.vscode
\ No newline at end of file
diff --git a/sample/megawifi/menu/README.MD b/sample/megawifi/menu/README.MD
new file mode 100644
index 00000000..2911297a
--- /dev/null
+++ b/sample/megawifi/menu/README.MD
@@ -0,0 +1,3 @@
+# My Awesome Game
+
+This is My Awesome 16 Bit Cartridge game for mega Drive
\ No newline at end of file
diff --git a/sample/megawifi/menu/inc/.gitkeep b/sample/megawifi/menu/inc/.gitkeep
new file mode 100644
index 00000000..43bae573
--- /dev/null
+++ b/sample/megawifi/menu/inc/.gitkeep
@@ -0,0 +1 @@
+# delete this file after add content to the directory
\ No newline at end of file
diff --git a/sample/megawifi/menu/inc/mw-api/configuration.h b/sample/megawifi/menu/inc/mw-api/configuration.h
new file mode 100644
index 00000000..fac99865
--- /dev/null
+++ b/sample/megawifi/menu/inc/mw-api/configuration.h
@@ -0,0 +1,24 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#ifndef _CONFIGURATION_H_
+#define _CONFIGURATION_H_
+
+#include "genesis.h"
+#include "utils.h"
+#include "mw-api/configuration_slot.h"
+#include "mw-api/configuration_cert.h"
+
+void CONFIG_start();
+
+void CONFIG_paint(bool repaint);
+
+bool CONFIG_doAction(u16 button, u8 max_option);
+
+#endif // _CONFIGURATION_H_
diff --git a/sample/megawifi/menu/inc/mw-api/configuration_ap.h b/sample/megawifi/menu/inc/mw-api/configuration_ap.h
new file mode 100644
index 00000000..a3941f28
--- /dev/null
+++ b/sample/megawifi/menu/inc/mw-api/configuration_ap.h
@@ -0,0 +1,29 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#ifndef _CONFIGURATION_AP_H_
+#define _CONFIGURATION_AP_H_
+
+#include "genesis.h"
+#include "utils.h"
+
+#define AP_MAX_ITEMS_PER_PAGE 20
+
+static struct mw_ap_data apData __attribute__((unused));
+
+void CONFIG_AP_start(u8 slot);
+
+u8 CONFIG_AP_paint(bool repaint, char* ap_data, u16 apLength, u8 page, u8 total_pages, s16 *selected_ap);
+
+bool CONFIG_AP_doAction(u16 button, u8 max_option, u8 *page, u8 total_pages, s16 selected_ap, char* ap_data, u16 apLength, u8 slot);
+
+void CONFIG_AP_paintApData(struct mw_ap_data apData, u8 line);
+void CONFIG_AP_save(const char *ap_data, u16 data_len, u16 pos, char *pass, u8 slot, enum mw_phy_type phy_type);
+
+#endif // _CONFIGURATION_AP_H_
diff --git a/sample/megawifi/menu/inc/mw-api/configuration_cert.h b/sample/megawifi/menu/inc/mw-api/configuration_cert.h
new file mode 100644
index 00000000..3ac89827
--- /dev/null
+++ b/sample/megawifi/menu/inc/mw-api/configuration_cert.h
@@ -0,0 +1,25 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#ifndef _CONFIGURATION_CERT_H_
+#define _CONFIGURATION_CERT_H_
+
+#include "genesis.h"
+#include "utils.h"
+#include "random.h"
+
+void CONFIG_CERT_start();
+
+void CONFIG_CERT_paint(bool repaint);
+
+bool CONFIG_CERT_doAction(u16 button, u8 max_option);
+
+void CONFIG_CERT_clear();
+
+#endif // _CONFIGURATION_CERT_H_
diff --git a/sample/megawifi/menu/inc/mw-api/configuration_slot.h b/sample/megawifi/menu/inc/mw-api/configuration_slot.h
new file mode 100644
index 00000000..141d7255
--- /dev/null
+++ b/sample/megawifi/menu/inc/mw-api/configuration_slot.h
@@ -0,0 +1,25 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#ifndef _CONFIGURATION_SLOT_H_
+#define _CONFIGURATION_SLOT_H_
+
+#include "genesis.h"
+#include "utils.h"
+#include "mw-api/configuration_ap.h"
+
+void CONFIG_SLOT_start();
+
+void CONFIG_SLOT_paint(bool repaint);
+
+bool CONFIG_SLOT_doAction(u16 button, u8 max_option);
+
+void CONFIG_SLOT_toogleConnection();
+
+#endif // _CONFIGURATION_SLOT_H_
diff --git a/sample/megawifi/menu/inc/mw-api/datetime.h b/sample/megawifi/menu/inc/mw-api/datetime.h
new file mode 100644
index 00000000..37f65ae9
--- /dev/null
+++ b/sample/megawifi/menu/inc/mw-api/datetime.h
@@ -0,0 +1,24 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#ifndef _DT_H_
+#define _DT_H_
+
+#include "genesis.h"
+#include "utils.h"
+
+void DT_start();
+
+void DT_paint(bool repaint);
+
+bool DT_doAction(u16 button, u8 max_option);
+
+void DT_test();
+
+#endif // _DT_H_
diff --git a/sample/megawifi/menu/inc/mw-api/flash.h b/sample/megawifi/menu/inc/mw-api/flash.h
new file mode 100644
index 00000000..faeecaba
--- /dev/null
+++ b/sample/megawifi/menu/inc/mw-api/flash.h
@@ -0,0 +1,25 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#ifndef _FLASH_H_
+#define _FLASH_H_
+
+#include "genesis.h"
+#include "utils.h"
+
+static u8 manufacturer __attribute__((unused));
+static u16 device __attribute__((unused));
+
+void FLASH_start();
+
+void FLASH_paint(bool repaint);
+
+bool FLASH_doAction(u16 button, u8 max_option);
+
+#endif // _FLASH_H_
diff --git a/sample/megawifi/menu/inc/mw-api/http.h b/sample/megawifi/menu/inc/mw-api/http.h
new file mode 100644
index 00000000..9550b8dd
--- /dev/null
+++ b/sample/megawifi/menu/inc/mw-api/http.h
@@ -0,0 +1,25 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#ifndef _HTTP_H_
+#define _HTTP_H_
+
+#include "genesis.h"
+#include "utils.h"
+#include "mw-api/configuration_cert.h"
+
+void HTTP_start();
+
+void HTTP_paint(bool repaint);
+
+bool HTTP_doAction(u16 button, u8 max_option);
+
+void HTTP_test(const char* url, bool ssl);
+
+#endif // _HTTP_H_
diff --git a/sample/megawifi/menu/inc/mw-api/ping.h b/sample/megawifi/menu/inc/mw-api/ping.h
new file mode 100644
index 00000000..260fe0aa
--- /dev/null
+++ b/sample/megawifi/menu/inc/mw-api/ping.h
@@ -0,0 +1,24 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#ifndef _PING_H_
+#define _PING_H_
+
+#include "genesis.h"
+#include "utils.h"
+
+void PING_start();
+
+void PING_paint(bool repaint);
+
+bool PING_doAction(u16 button, u8 max_option);
+
+void PING_test();
+
+#endif // _PING_H_
diff --git a/sample/megawifi/menu/inc/mw-api/random.h b/sample/megawifi/menu/inc/mw-api/random.h
new file mode 100644
index 00000000..2a65a36b
--- /dev/null
+++ b/sample/megawifi/menu/inc/mw-api/random.h
@@ -0,0 +1,24 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#ifndef _RANDOM_H_
+#define _RANDOM_H_
+
+#include "genesis.h"
+#include "utils.h"
+
+void RND_start();
+
+void RND_paint(bool repaint);
+
+bool RND_doAction(u16 button, u8 max_option);
+
+void RND_test();
+
+#endif // _RANDOM_H_
diff --git a/sample/megawifi/menu/inc/mw-api/tcp.h b/sample/megawifi/menu/inc/mw-api/tcp.h
new file mode 100644
index 00000000..0129dcfb
--- /dev/null
+++ b/sample/megawifi/menu/inc/mw-api/tcp.h
@@ -0,0 +1,26 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#ifndef _TCP_H_
+#define _TCP_H_
+
+#include "genesis.h"
+#include "utils.h"
+
+void TCP_start();
+
+void TCP_paint(bool repaint);
+
+bool TCP_doAction(u16 button, u8 max_option);
+
+void TCP_test();
+
+void TCP_test_server();
+
+#endif // _TCP_H_
diff --git a/sample/megawifi/menu/inc/mw-api/udp.h b/sample/megawifi/menu/inc/mw-api/udp.h
new file mode 100644
index 00000000..9c12a036
--- /dev/null
+++ b/sample/megawifi/menu/inc/mw-api/udp.h
@@ -0,0 +1,30 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#ifndef _UDP_H_
+#define _UDP_H_
+
+#include "genesis.h"
+#include "utils.h"
+
+void UDP_start();
+
+void UDP_paint(bool repaint);
+
+bool UDP_doAction(u16 button, u8 max_option);
+
+void UDP_normal_test();
+
+void UDP_reuse_test();
+
+/// UDP receive functions callback
+void udp_recv_cb(enum lsd_status stat, uint8_t ch, char *data, uint16_t len, void *ctx);
+void udp_send_complete_cb(enum lsd_status stat, void *ctx);
+
+#endif // _UDP_H_
diff --git a/sample/megawifi/menu/inc/mw-api/upgrade.h b/sample/megawifi/menu/inc/mw-api/upgrade.h
new file mode 100644
index 00000000..d9351796
--- /dev/null
+++ b/sample/megawifi/menu/inc/mw-api/upgrade.h
@@ -0,0 +1,26 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#ifndef _UPGRADE_H_
+#define _UPGRADE_H_
+
+#include "genesis.h"
+#include "utils.h"
+
+static char *listUpgrades __attribute__((unused)) = NULL;
+static uint8_t len __attribute__((unused)) = 0;
+static uint8_t total __attribute__((unused)) = 0;
+
+void UPGRADE_start();
+
+void UPGRADE_paint(bool repaint);
+
+bool UPGRADE_doAction(u16 button, u8 max_option);
+
+#endif // _UPGRADE_H_
diff --git a/sample/megawifi/menu/inc/utils.h b/sample/megawifi/menu/inc/utils.h
new file mode 100644
index 00000000..d5ca4670
--- /dev/null
+++ b/sample/megawifi/menu/inc/utils.h
@@ -0,0 +1,72 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#ifndef _UTILS_H_
+#define _UTILS_H_
+
+#include "genesis.h"
+
+#define DEFAULT_DELAY 500
+#define DEFAULT_MW_DELAY 1000
+
+/// Shut compiler warnings for unused parameters
+#define UNUSED_PARAM(par) (void)(par)
+
+/// Tuned for 60 Hz, change it for PAL consoles
+#define MS_TO_FRAMES(ms) ((((ms) * 60 / 500) + 1)/2)
+
+/// Certificate for www.example.org
+static const char cert[] = "-----BEGIN CERTIFICATE-----\n"
+"MIIDeTCCAv+gAwIBAgIQCwDpLU1tcx/KMFnHyx4YhjAKBggqhkjOPQQDAzBhMQsw"
+"CQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cu"
+"ZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBHMzAe"
+"Fw0yMTA0MTQwMDAwMDBaFw0zMTA0MTMyMzU5NTlaMFkxCzAJBgNVBAYTAlVTMRUw"
+"EwYDVQQKEwxEaWdpQ2VydCBJbmMxMzAxBgNVBAMTKkRpZ2lDZXJ0IEdsb2JhbCBH"
+"MyBUTFMgRUNDIFNIQTM4NCAyMDIwIENBMTB2MBAGByqGSM49AgEGBSuBBAAiA2IA"
+"BHipnHWuiF1jpK1dhtgQSdavklljQyOF9EhlMM1KNJWmDj7ZfAjXVwUoSJ4Lq+vC"
+"05ae7UXSi4rOAUsXQ+Fzz21zSDTcAEYJtVZUyV96xxMH0GwYF2zK28cLJlYujQf1"
+"Z6OCAYIwggF+MBIGA1UdEwEB/wQIMAYBAf8CAQAwHQYDVR0OBBYEFIoj655r1/k3"
+"XfltITl2mqFn3hCoMB8GA1UdIwQYMBaAFLPbSKT5ocXYrjZBzBFjaWIpvEvGMA4G"
+"A1UdDwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwdgYI"
+"KwYBBQUHAQEEajBoMCQGCCsGAQUFBzABhhhodHRwOi8vb2NzcC5kaWdpY2VydC5j"
+"b20wQAYIKwYBBQUHMAKGNGh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LmNvbS9EaWdp"
+"Q2VydEdsb2JhbFJvb3RHMy5jcnQwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2Ny"
+"bDMuZGlnaWNlcnQuY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdEczLmNybDA9BgNVHSAE"
+"NjA0MAsGCWCGSAGG/WwCATAHBgVngQwBATAIBgZngQwBAgEwCAYGZ4EMAQICMAgG"
+"BmeBDAECAzAKBggqhkjOPQQDAwNoADBlAjB+Jlhu7ojsDN0VQe56uJmZcNFiZU+g"
+"IJ5HsVvBsmcxHcxyeq8ickBCbmWE/odLDxkCMQDmv9auNIdbP2fHHahv1RJ4teaH"
+"MUSpXca4eMzP79QyWBH/OoUGPB2Eb9P1+dozHKQ="
+"-----END CERTIFICATE-----";
+
+static const uint16_t cert_len = sizeof(cert);
+/// Certificate hash, obtained with command:
+/// openssl x509 -hash in -noout
+static const uint32_t cert_hash = 0xa6570d26;
+
+static u16 option __attribute__((unused)) = 0;
+static char buffer[128] __attribute__((unused));
+static long ciclo __attribute__((unused)) = 0;
+
+/// Command buffer. Must be word aligned
+static char cmd_buf[MW_BUFLEN] __attribute__((unused));
+
+#define SCREEN_COLUMNS 20U // Número de columnas en pantalla
+#define SCREEN_ROWS 28U // Número de filas en pantalla
+
+void clearScreen();
+void println(const char *str);
+void print();
+void paint_long_char(const char *cert, u16 len, u8 line);
+u16 readButton(u16 joy);
+int readText(char* buffer, size_t lengthMax);
+void delay_ms(u16 milliseconds);
+void printStatus(union mw_msg_sys_stat * status);
+
+
+#endif // _UTILS_H_
diff --git a/sample/megawifi/menu/res/.gitkeep b/sample/megawifi/menu/res/.gitkeep
new file mode 100644
index 00000000..43bae573
--- /dev/null
+++ b/sample/megawifi/menu/res/.gitkeep
@@ -0,0 +1 @@
+# delete this file after add content to the directory
\ No newline at end of file
diff --git a/sample/megawifi/menu/src/main.c b/sample/megawifi/menu/src/main.c
new file mode 100644
index 00000000..e4d841eb
--- /dev/null
+++ b/sample/megawifi/menu/src/main.c
@@ -0,0 +1,205 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * This example demonstrates the following:
+ * - How to initialize MegaWiFi
+ * - How to configurate MegaWiFi and manage Certs
+ * - How to do ICMP tests
+ * - How to do TCP connections and TCP server
+ * - How to do HTTP queries
+ * - How to send and receive data using UDP protocol
+ * - How to get the date/time (synchronized to NTP servers)
+ * - How to get random numbers
+ * - How to work with flash store
+ * - How to get MegaWiFi Firmware updates
+ *
+ * To build this example set MODULE_MEGAWIFI to 1 in config.h and
+ * rebuild the library.
+ * You can use:
+ * - MODULE_EVERDRIVE to 1
+ * - ENABLE_BANK_SWITCH to 1
+ * in config.h to use everdive and MegaWifi Addon
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#include "genesis.h"
+#include "utils.h"
+#include "mw-api/configuration.h"
+#include "mw-api/http.h"
+#include "mw-api/tcp.h"
+#include "mw-api/udp.h"
+#include "mw-api/datetime.h"
+#include "mw-api/random.h"
+#include "mw-api/flash.h"
+#include "mw-api/upgrade.h"
+#include "mw-api/ping.h"
+
+#if (MODULE_MEGAWIFI == 0)
+#error "Set MODULE_MEGAWIFI to 1 in config.h and rebuild the library"
+#endif
+
+/// TCP port to use (set to Megadrive release year ;-)
+#define MW_CH_PORT 1985
+
+/// Idle task, run using the spare CPU time available when the main task
+/// pends or yields. See mw/tsk.h for details. Basically this task polls
+/// the WiFi module to send and receive data.
+static void idle_tsk(void)
+{
+ while (1) {
+ mw_process();
+ }
+}
+
+static void printMainMenu(bool repaint){
+ if (repaint){
+ clearScreen();
+ VDP_drawText("Show Configurations", 1u, 1u);
+ VDP_drawText("DateTime Test", 1u, 2u);
+ VDP_drawText("Random Test", 1u, 3u);
+ VDP_drawText("Flash Test", 1u, 4u);
+ VDP_drawText("Upgrade Test", 1u, 5u);
+ VDP_drawText("Ping Test", 1u, 6u);
+ VDP_drawText("TCP Test", 1u, 7u);
+ VDP_drawText("HTTP Test", 1u, 8u);
+ VDP_drawText("UDP Test", 1u, 9u);
+ VDP_drawText("Option: Ciclo: ", 15u, 28u);
+ }
+
+ VDP_drawText("*", 0, option + 1U);
+ print();
+}
+
+static bool doActionMainMenu(u16 button){
+ switch (button){
+ case BUTTON_UP:
+ if(option > 0) {
+ option--;
+ return TRUE;
+ }
+ break;
+ case BUTTON_DOWN:
+ if(option < 9u){
+ option = option+1u % 9u;
+ return TRUE;
+ }
+ break;
+ case BUTTON_START:
+ switch (option){
+ case 0U:
+ CONFIG_start();
+ break;
+ case 1U:
+ DT_start();
+ break;
+ case 2U:
+ RND_start();
+ break;
+ case 3U:
+ FLASH_start();
+ break;
+ case 4U:
+ UPGRADE_start();
+ break;
+ case 5U:
+ PING_start();
+ break;
+ case 6U:
+ TCP_start();
+ break;
+ case 7U:
+ HTTP_start();
+ break;
+ case 8U:
+ UDP_start();
+ break;
+ default:
+ break;
+ }
+ return TRUE;
+ default:
+ return FALSE;
+ }
+ return FALSE;
+}
+
+/// Associates to the AP and runs the tests
+static void run_app(void)
+{
+ //enum mw_err err;
+ bool repaint = TRUE;
+ while(1) {
+ printMainMenu(repaint);
+ repaint = doActionMainMenu(readButton(JOY_1));
+ SYS_doVBlankProcess();
+ ciclo++;
+ }
+}
+
+/// MegaWiFi initialization
+/// Returns true on error
+static bool megawifi_init(void)
+{
+ uint8_t ver_major = 0, ver_minor = 0;
+ char *variant = NULL;
+ enum mw_err err;
+ char line[] = "MegaWiFi version X.Y - zzz";
+ bool ret;
+
+ // Try detecting the module
+ err = mw_detect(&ver_major, &ver_minor, &variant);
+
+ if (MW_ERR_NONE != err) {
+ // Megawifi not found
+ println("MegaWiFi not found!");
+ ret = TRUE;
+ } else {
+ // Megawifi found
+ line[17] = ver_major + '0';
+ line[19] = ver_minor + '0';
+ memcpy(&(line[23]), variant, 3);
+ println(line);
+ ret = FALSE;
+ }
+
+ return ret;
+}
+
+/// Set idle task that polls WiFi module
+static void tasking_init(void)
+{
+ TSK_userSet(idle_tsk);
+}
+
+/// Global initialization
+static void init(void)
+{
+ // initialization
+ VDP_setScreenWidth320();
+ // Initialize MegaWiFi
+ mw_init((u16*) cmd_buf, MW_BUFLEN);
+ // Initialize multitasking (for WiFi background checks)
+ tasking_init();
+}
+
+/// Entry point
+int main(bool hard)
+{
+ UNUSED_PARAM(hard);
+ bool err;
+ init();
+ err = megawifi_init();
+ delay_ms(DEFAULT_DELAY);
+ if (!err) {
+ union mw_msg_sys_stat *status;
+ while(!(status = mw_sys_stat_get()));
+ printStatus(status);
+ run_app();
+ }
+
+ return 0;
+}
diff --git a/sample/megawifi/menu/src/mw-api/configuration.c b/sample/megawifi/menu/src/mw-api/configuration.c
new file mode 100644
index 00000000..5194758b
--- /dev/null
+++ b/sample/megawifi/menu/src/mw-api/configuration.c
@@ -0,0 +1,65 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#include "mw-api/configuration.h"
+
+void CONFIG_start(){
+ u16 button;
+ bool repaint = TRUE;
+ option = 0;
+ do{
+ CONFIG_paint(repaint);
+ button = readButton(JOY_1);
+ repaint = CONFIG_doAction(button, 2u);
+ VDP_drawText("*", 0u, option + 2);
+ print();
+ }while(button != BUTTON_A);
+
+}
+
+void CONFIG_paint(bool repaint){
+ if(repaint){
+ clearScreen();
+ VDP_drawText("Slots Configuration", 1u, 2u);
+ VDP_drawText("Cert Configuration", 1u, 3u);
+ VDP_drawText("Press START to selec", 0u, 4u);
+ VDP_drawText("Press A to return", 0u, 5u);
+ }
+}
+
+bool CONFIG_doAction(u16 button, u8 max_option){
+ switch (button){
+ case BUTTON_UP:
+ VDP_drawText(" ", 0u, option + 2);
+ if(option > 0) {
+ option--;
+ }
+ break;
+ case BUTTON_DOWN:
+ VDP_drawText(" ", 0u, option + 2);
+ if(option < max_option - 1){
+ option = option+1u % max_option;
+ }
+ break;
+ case BUTTON_START:{
+ switch(option){
+ case 0:
+ CONFIG_SLOT_start((u8)option);
+ break;
+ case 1:
+ CONFIG_CERT_start((u8)option);
+ break;
+ default:
+ }
+ return TRUE;
+ }
+ default:
+ }
+ return FALSE;
+}
\ No newline at end of file
diff --git a/sample/megawifi/menu/src/mw-api/configuration_ap.c b/sample/megawifi/menu/src/mw-api/configuration_ap.c
new file mode 100644
index 00000000..1aa70826
--- /dev/null
+++ b/sample/megawifi/menu/src/mw-api/configuration_ap.c
@@ -0,0 +1,144 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#include "mw-api/configuration_ap.h"
+
+void CONFIG_AP_paintApData(struct mw_ap_data apData, u8 line){
+
+ sprintf(buffer, "%d", apData.rssi);
+ VDP_drawText(buffer , 1, line);
+ switch(apData.auth){
+ case MW_SEC_OPEN:
+ VDP_drawText("OPEN", 5, line);
+ break;
+ case MW_SEC_WEP:
+ VDP_drawText("WEP", 5, line);
+ break;
+ case MW_SEC_WPA_PSK:
+ VDP_drawText("WPA", 5, line);
+ break;
+ case MW_SEC_WPA2_PSK:
+ VDP_drawText("WPA2", 5, line);
+ break;
+ case MW_SEC_WPA_WPA2_PSK:
+ VDP_drawText("MIX", 5, line);
+ break;
+ default:
+ VDP_drawText("UNK" , 5, line);
+ }
+ char apBuff[apData.ssid_len];
+ memcpy(apBuff,apData.ssid, apData.ssid_len);
+ VDP_drawText(apBuff, 10, line);
+}
+
+u8 CONFIG_AP_paint(bool repaint, char* ap_data, u16 apLength, u8 page, u8 total_pages, s16 *selected_ap){
+ u8 max_option = AP_MAX_ITEMS_PER_PAGE;
+ if(repaint){
+ clearScreen();
+ u8 count = 0, aux_count = 0;
+ u8 pageAux = 0;
+ s16 pos = 0;
+ do{
+ if(option == count && pageAux == page) *selected_ap = pos;
+ pos = mw_ap_fill_next(ap_data, pos ,&apData, apLength);
+ if(pos){
+ if(pageAux == page){
+ CONFIG_AP_paintApData(apData, count + 1U);
+ count++;
+ }else{
+ aux_count++;
+ if(aux_count == AP_MAX_ITEMS_PER_PAGE){
+ aux_count = 0;
+ pageAux++;
+ }
+ }
+ }
+ }while(pos && pos < apLength && count < AP_MAX_ITEMS_PER_PAGE);
+ max_option = count - 1;
+ VDP_drawText("*", 0, option + 1U);
+ VDP_drawText("Press A to return", 0u, AP_MAX_ITEMS_PER_PAGE + 2u);
+ repaint = FALSE;
+ }
+
+ sprintf(buffer, "%u/%u", page + 1,total_pages);
+ VDP_drawText(buffer, 0u, 27u);
+ print();
+ return max_option;
+}
+
+void CONFIG_AP_save(const char *ap_data, u16 data_len, u16 pos, char *pass, u8 slot, enum mw_phy_type phy_type){
+ struct mw_ap_data apd;
+ mw_ap_fill_next(ap_data, pos ,&apd, data_len);
+ char apBuff[apd.ssid_len + 1u];
+ memcpy(apBuff,apd.ssid, apd.ssid_len);
+ apBuff[apd.ssid_len]= '\0';
+ while(mw_ap_cfg_set(slot,apBuff, pass, phy_type) + mw_cfg_save());
+}
+
+bool CONFIG_AP_doAction(u16 button, u8 max_option, u8 *page, u8 total_pages, s16 selected_ap, char* ap_data, u16 apLength, u8 slot){
+ switch (button){
+ case BUTTON_UP:
+ if(option > 0) {
+ option--;
+ }
+ return TRUE;
+ case BUTTON_DOWN:
+ if(option < max_option ){
+ option = option+1u % max_option;
+ }
+ return TRUE;
+ case BUTTON_LEFT:
+ option = 0;
+ if(*page > 0) {
+ (*page)--;
+ }
+ return TRUE;
+ case BUTTON_RIGHT:
+ option = 0;
+ if((*page) < total_pages -1){
+ (*page) = (*page)+1u % total_pages;
+ }
+ return TRUE;
+ case BUTTON_START:{
+ if(selected_ap >= 0){
+ char bufferPass[MW_PASS_MAXLEN];
+ int length = readText(bufferPass, MW_PASS_MAXLEN);
+ char pass[length];
+ memcpy(pass,bufferPass, length);
+ CONFIG_AP_save(ap_data, apLength, selected_ap, pass, slot, MW_PHY_11BGN);
+ button = BUTTON_A;
+ }
+ return TRUE;
+ }
+ default:
+ }
+ return FALSE;
+}
+
+void CONFIG_AP_start(u8 slot){
+ char* ap_data;
+ s16 selected_ap = -1;
+ u8 aps = 0, page = 0;
+ bool repaint = TRUE;
+ u16 button;
+ option = 0;
+ u8 max_option = AP_MAX_ITEMS_PER_PAGE;
+ clearScreen();
+ println("Searching Aps...");
+ s16 apLength = mw_ap_scan(MW_PHY_11BGN, &ap_data, &aps);
+ if (!apLength) println("No Ap");
+ u8 total_pages = aps / AP_MAX_ITEMS_PER_PAGE;
+ if (aps % AP_MAX_ITEMS_PER_PAGE > 0) total_pages++;
+ do{
+ if (apLength) max_option = CONFIG_AP_paint(repaint, ap_data, apLength,page,total_pages, &selected_ap);
+ button = readButton(JOY_1);
+ if (apLength) repaint = CONFIG_AP_doAction(button, max_option, &page, total_pages, selected_ap, ap_data, apLength, slot);
+ ciclo++;
+ }while(button != BUTTON_A);
+}
\ No newline at end of file
diff --git a/sample/megawifi/menu/src/mw-api/configuration_cert.c b/sample/megawifi/menu/src/mw-api/configuration_cert.c
new file mode 100644
index 00000000..a3770ea1
--- /dev/null
+++ b/sample/megawifi/menu/src/mw-api/configuration_cert.c
@@ -0,0 +1,65 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#include "mw-api/configuration_cert.h"
+
+void CONFIG_CERT_start(){
+
+ u16 button;
+ bool repaint = TRUE;
+ option = 0;
+
+ do{
+ CONFIG_CERT_paint(repaint);
+ button = readButton(JOY_1);
+ repaint = CONFIG_CERT_doAction(button, 2);
+ print();
+ }while(button != BUTTON_A);
+
+}
+
+void CONFIG_CERT_paint(bool repaint){
+ if(repaint){
+ clearScreen();
+ println("Checking Cert...");
+ delay_ms(DEFAULT_DELAY);
+ u32 hash = mw_http_cert_query();
+ sprintf(buffer, "Store Cert Hash: %08lx", hash);
+ VDP_drawText(buffer, 0u, 2u);
+ VDP_drawText("Press START to Set Cert", 0u, 4u);
+ VDP_drawText("Press A to return", 0u, 6u);
+ VDP_drawText("Press B to clear Cert", 0u, 7u);
+ sprintf(buffer, "Cert Hash: %08lx len: %u", cert_hash, cert_len);
+ VDP_drawText(buffer, 0u, 9u);
+ paint_long_char(cert, cert_len, 11u);
+ repaint = false;
+ }
+}
+
+bool CONFIG_CERT_doAction(u16 button, u8 max_option){
+ switch (button){
+ case BUTTON_B:
+ CONFIG_CERT_clear();
+ break;
+ case BUTTON_START:{
+ int rety = 3;
+ while(mw_http_cert_set(cert_hash, cert, cert_len) && rety-->0);
+ return TRUE;
+ }
+ default:
+ }
+ return FALSE;
+}
+
+void CONFIG_CERT_clear(){
+ char mycert[20];
+ memset(&mycert, 0,20);
+ int rety = 3;
+ while(mw_http_cert_set(23, mycert, 20) && rety--);
+}
\ No newline at end of file
diff --git a/sample/megawifi/menu/src/mw-api/configuration_slot.c b/sample/megawifi/menu/src/mw-api/configuration_slot.c
new file mode 100644
index 00000000..5920c6ab
--- /dev/null
+++ b/sample/megawifi/menu/src/mw-api/configuration_slot.c
@@ -0,0 +1,132 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#include "mw-api/configuration_slot.h"
+
+void CONFIG_SLOT_start(){
+ u16 button;
+ bool repaint = TRUE;
+ option = 0;
+ do{
+ CONFIG_SLOT_paint(repaint);
+ button = readButton(JOY_1);
+ repaint = CONFIG_SLOT_doAction(button, MW_NUM_CFG_SLOTS);
+ VDP_drawText("*", 0u, option + 5);
+ print();
+ }while(button != BUTTON_A);
+
+}
+
+void CONFIG_SLOT_paint(bool repaint){
+ char *ssid, *pass;
+ enum mw_phy_type phyType;
+ if(repaint){
+ clearScreen();
+ println("Searching Configs...");
+ int i = 0;
+ for(i = 0; i < MW_NUM_CFG_SLOTS; i++){
+ while(mw_ap_cfg_get((u8)i, &ssid, &pass, &phyType));
+ sprintf(buffer, "%u: SSID:%s", (u8)i, ssid);
+ VDP_drawText(buffer, 1u, (u16)i + 5);
+ sprintf(buffer, "PASS: %.1s**", pass);
+ VDP_drawText(buffer, 30u, (u16)i + 5);
+ strclr(buffer);
+ }
+ s16 slotDefault = mw_def_ap_cfg_get();
+ sprintf(buffer, "Default Slot: %d", slotDefault);
+ VDP_drawText(buffer, 1u, (u16)10);
+ VDP_drawText("Press Start to Configure Slot", 0u, (u16)16);
+ VDP_drawText("Press A to Return", 0u, (u16)17);
+ VDP_drawText("Press B associate/des to AP from Slot", 0u, (u16)18);
+ VDP_drawText("Press C to Set Default AP Config Slot", 0u, (u16)19);
+ repaint = false;
+ }
+}
+
+bool CONFIG_SLOT_doAction(u16 button, u8 max_option){
+ switch (button){
+ case BUTTON_UP:
+ VDP_drawText(" ", 0u, option + 5);
+ if(option > 0) {
+ option--;
+ }
+ break;
+ case BUTTON_DOWN:
+ VDP_drawText(" ", 0u, option + 5);
+ if(option < max_option - 1){
+ option = option+1u % max_option;
+ }
+ break;
+ case BUTTON_B:{
+ CONFIG_SLOT_toogleConnection();
+ union mw_msg_sys_stat *status;
+ while (!(status = mw_sys_stat_get()));
+ printStatus(status);
+ break;
+ }
+ case BUTTON_C:
+ mw_def_ap_cfg((u8)option);
+ mw_cfg_save();
+ return TRUE;
+ case BUTTON_START:
+ CONFIG_AP_start((u8)option);
+ return TRUE;
+ default:
+ }
+ return FALSE;
+}
+
+void CONFIG_SLOT_toogleConnection(){
+
+ union mw_msg_sys_stat *status;
+ while (!(status = mw_sys_stat_get()));
+ printStatus(status);
+ if(status->online){
+ println("Disconecting... ");
+ SYS_doVBlankProcess();
+ mw_sleep(MS_TO_FRAMES(DEFAULT_MW_DELAY));
+ while (!mw_ap_disassoc());
+ println("Disconected ");
+ SYS_doVBlankProcess();
+ }else{
+ struct mw_ip_cfg *ipConf;
+ println("AP Connecting...");
+ SYS_doVBlankProcess();
+ mw_sleep(MS_TO_FRAMES(DEFAULT_MW_DELAY));
+ int i =3;
+ println("AP Waiting... ");
+ SYS_doVBlankProcess();
+ while(mw_ap_assoc((u8)option) && i--){
+ sprintf(buffer, "%d", i);
+ VDP_drawText(buffer, 22u, 0);
+ SYS_doVBlankProcess();
+ }
+ i =3;
+ if(mw_ap_assoc_wait(MS_TO_FRAMES(60000))){
+ println("ERROR ");
+ SYS_doVBlankProcess();
+ }else{
+ println("Checking IP...");
+ SYS_doVBlankProcess();
+ while(mw_ip_current(&ipConf));
+ sprintf(buffer, "IP: %u.%u.%u.%u", ipConf->addr.byte[0], ipConf->addr.byte[1], ipConf->addr.byte[2], ipConf->addr.byte[3]);
+ VDP_drawText(buffer, 0u, 21u);
+ sprintf(buffer, "D1: %u.%u.%u.%u", ipConf->dns1.byte[0], ipConf->dns1.byte[1], ipConf->dns1.byte[2], ipConf->dns1.byte[3]);
+ VDP_drawText(buffer, 0u, 22u);
+ sprintf(buffer, "D2: %u.%u.%u.%u", ipConf->dns2.byte[0], ipConf->dns2.byte[1], ipConf->dns2.byte[2], ipConf->dns2.byte[3]);
+ VDP_drawText(buffer, 0u, 23u);
+ sprintf(buffer, "GW: %u.%u.%u.%u", ipConf->gateway.byte[0], ipConf->gateway.byte[1], ipConf->gateway.byte[2], ipConf->gateway.byte[3]);
+ VDP_drawText(buffer, 0u, 24u);
+ sprintf(buffer, "MK: %u.%u.%u.%u", ipConf->mask.byte[0], ipConf->mask.byte[1], ipConf->mask.byte[2], ipConf->mask.byte[3]);
+ VDP_drawText(buffer, 0u, 25u);
+ println("IP Checked ");
+ SYS_doVBlankProcess();
+ }
+ }
+}
\ No newline at end of file
diff --git a/sample/megawifi/menu/src/mw-api/datetime.c b/sample/megawifi/menu/src/mw-api/datetime.c
new file mode 100644
index 00000000..987a545c
--- /dev/null
+++ b/sample/megawifi/menu/src/mw-api/datetime.c
@@ -0,0 +1,64 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#include "mw-api/datetime.h"
+
+void DT_start(){
+
+ u16 button;
+ bool repaint = TRUE;
+
+ do{
+ DT_paint(repaint);
+ button = readButton(JOY_1);
+ repaint = DT_doAction(button, 0);
+ print();
+ }while(button != BUTTON_A);
+
+}
+
+void DT_paint(bool repaint){
+ if(repaint){
+ clearScreen();
+ VDP_drawText("DT Test", 1u, 2u);
+ VDP_drawText("Press START to launch", 0u, 3u);
+ VDP_drawText("Press A to return", 0u, 4u);
+ }
+}
+
+bool DT_doAction(u16 button, u8 max_option){
+ switch (button){
+ case BUTTON_START:{
+ DT_test();
+ }
+ default:
+ }
+ return FALSE;
+}
+
+
+/// Waits until date/time is synchronized and gets the date/time
+void DT_test()
+{
+ const char *datetime;
+ uint32_t dt_bin[2] = {};
+ union mw_msg_sys_stat *stat;
+
+ // Wait until date/time is set
+ do {
+ mw_sleep(60);
+ stat = mw_sys_stat_get();
+ if (!stat) {
+ println("Failed to get date/time");
+ return;
+ }
+ } while (!stat->dt_ok);
+ datetime = mw_date_time_get(dt_bin);
+ println(datetime);
+}
\ No newline at end of file
diff --git a/sample/megawifi/menu/src/mw-api/flash.c b/sample/megawifi/menu/src/mw-api/flash.c
new file mode 100644
index 00000000..4541dc3a
--- /dev/null
+++ b/sample/megawifi/menu/src/mw-api/flash.c
@@ -0,0 +1,101 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#include "mw-api/flash.h"
+
+void FLASH_start(){
+ u16 button;
+ bool repaint = TRUE;
+ option = 0;
+
+ //mw_flash_info_get(); //TODO: NOT implemented ON SGDK ni RTOS
+ do{
+ FLASH_paint(repaint);
+ button = readButton(JOY_1);
+ repaint = FLASH_doAction(button, 4u);
+ VDP_drawText("*", 0u, option + 2);
+ print();
+ }while(button != BUTTON_A);
+
+}
+
+void FLASH_paint(bool repaint){
+ if(repaint){
+ clearScreen();
+ VDP_drawText("Get Flash IDS", 1u, 2u);
+ VDP_drawText("Read Flash", 1u, 3u);
+ VDP_drawText("Write Flash", 1u, 4u);
+ VDP_drawText("Erase Flash", 1u, 5u);
+ VDP_drawText("Press Start to exec", 0u, 6u);
+ VDP_drawText("Press A to return", 0u, 7u);
+
+ if(manufacturer && device){
+ sprintf(buffer, "Manufacturer: %2X Device: %4X", manufacturer, device);
+ VDP_drawText(buffer, 0u, 9u);
+ }
+ }
+}
+
+bool FLASH_doAction(u16 button, u8 max_option){
+
+ enum mw_err err;
+ switch (button){
+ case BUTTON_UP:
+ VDP_drawText(" ", 0u, option + 2);
+ if(option > 0) {
+ option--;
+ }
+ break;
+ case BUTTON_DOWN:
+ VDP_drawText(" ", 0u, option + 2);
+ if(option < max_option - 1){
+ option = option+1u % max_option;
+ }
+ break;
+ case BUTTON_START:{
+ switch(option){
+ case 0:
+ err = mw_flash_id_get(&manufacturer, &device);
+ if(err){
+ sprintf(buffer, "MW-ERROR: %u ", err);
+ println(buffer);
+ }else{
+ return TRUE;
+ }
+ break;
+ case 1:{
+ u8* response = mw_flash_read(0x0000, 512U);
+ if(!response){
+ println("FLASH READ 0x0000 512B FAIL");
+ }else{
+ paint_long_char((const char *)response, 512U, 11u);
+ }
+ break;
+ }
+ case 2:
+ err = mw_flash_write(0x0000, (u8 *)"DATA STORE ON FLASS", 20);
+ if(err){
+ sprintf(buffer, "MW-ERROR: %u ", err);
+ println(buffer);
+ }
+ break;
+ case 3:
+ err = mw_flash_sector_erase(0);
+ if(err){
+ sprintf(buffer, "MW-ERROR: %u ", err);
+ println(buffer);
+ }
+ break;
+ default:
+ }
+ }
+ default:
+ }
+ return FALSE;
+}
\ No newline at end of file
diff --git a/sample/megawifi/menu/src/mw-api/http.c b/sample/megawifi/menu/src/mw-api/http.c
new file mode 100644
index 00000000..a9d74341
--- /dev/null
+++ b/sample/megawifi/menu/src/mw-api/http.c
@@ -0,0 +1,120 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#include "mw-api/http.h"
+
+
+/// Receives data from the HTTP test
+static int http_recv(uint32_t len)
+{
+ int16_t recv_last;
+ int err = FALSE;
+ uint32_t recvd = 0;
+ uint8_t ch = MW_HTTP_CH;
+
+ u8 line = 11u;
+
+ while (recvd < len && !err) {
+ recv_last = MW_BUFLEN;
+ err = mw_recv_sync(&ch, cmd_buf, &recv_last, TSK_PEND_FOREVER) != MW_ERR_NONE;
+ paint_long_char(cmd_buf, recv_last - recvd, line);
+ line++;
+ recvd += recv_last;
+ }
+
+ return err;
+}
+
+void HTTP_start(){
+
+ u16 button;
+ bool repaint = TRUE;
+
+ do{
+ HTTP_paint(repaint);
+ button = readButton(JOY_1);
+ repaint = HTTP_doAction(button, 0);
+ print();
+ }while(button != BUTTON_A);
+
+}
+
+void HTTP_paint(bool repaint){
+ if(repaint){
+ clearScreen();
+ VDP_drawText("HTTPs Test", 1u, 2u);
+ VDP_drawText("Press START to launch", 0u, 3u);
+ VDP_drawText("Press A to return", 0u, 4u);
+ VDP_drawText("Press B by Http", 0u, 5u);
+ }
+}
+
+bool HTTP_doAction(u16 button, u8 max_option){
+ switch (button){
+ case BUTTON_START:
+ HTTP_test("https://www.example.com", TRUE);
+ break;
+ case BUTTON_B:
+ HTTP_test("http://www.example.com", FALSE);
+ break;
+ default:
+ }
+ return FALSE;
+}
+
+/// Sets the certificate for the HTTPS TLS connection
+static void http_cert_set(void)
+{
+ uint32_t hash = mw_http_cert_query();
+ if (hash != cert_hash) {
+ mw_http_cert_set(cert_hash, cert, cert_len);
+ }
+}
+
+
+/// Test an HTTP GET request to https://www.example.com
+void HTTP_test(const char* url, bool ssl) {
+ uint32_t len = 0;
+ enum mw_err err = MW_ERR_NONE;
+ s16 errHttp = -1;
+ if(ssl){
+ http_cert_set();
+ }else{
+ CONFIG_CERT_clear();
+ }
+
+ println("Setting URL ");
+ print();
+ delay_ms(DEFAULT_DELAY);
+ err = mw_http_url_set(url);
+ if (err) goto err_out;
+ println("Setting Method ");
+ print();
+ delay_ms(DEFAULT_DELAY);
+ err = mw_http_method_set(MW_HTTP_METHOD_GET);
+ if (err) goto err_out;
+ println("Open URL ");
+ print();
+ delay_ms(DEFAULT_DELAY);
+ err = mw_http_open(0);
+ if (err) goto err_out;
+ println("Finish URL ");
+ print();
+ delay_ms(DEFAULT_DELAY);
+ errHttp = mw_http_finish(&len, MS_TO_FRAMES(20000));
+ if (errHttp < 100) goto err_out;
+ if (len) {
+ if (http_recv(len)) goto err_out;
+ }
+ println("HTTP test SUCCESS ");
+ return;
+err_out:
+ sprintf(buffer, "MW-ERROR: %u HTTP-ERROR: %d", err, errHttp);
+ println(buffer);
+}
diff --git a/sample/megawifi/menu/src/mw-api/ping.c b/sample/megawifi/menu/src/mw-api/ping.c
new file mode 100644
index 00000000..662b5d92
--- /dev/null
+++ b/sample/megawifi/menu/src/mw-api/ping.c
@@ -0,0 +1,62 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#include "mw-api/ping.h"
+
+void PING_start(){
+
+ u16 button;
+ bool repaint = TRUE;
+
+ do{
+ PING_paint(repaint);
+ button = readButton(JOY_1);
+ repaint = PING_doAction(button, 0);
+ print();
+ }while(button != BUTTON_A);
+
+}
+
+void PING_paint(bool repaint){
+ if(repaint){
+ clearScreen();
+ VDP_drawText("PING Test", 1u, 2u);
+ VDP_drawText("Press START to launch", 0u, 3u);
+ VDP_drawText("Press A to return", 0u, 4u);
+ }
+}
+
+bool PING_doAction(u16 button, u8 max_option){
+ switch (button){
+ case BUTTON_START:{
+ PING_test();
+ break;
+ }
+ default:
+ }
+ return FALSE;
+}
+
+
+/// Waits until date/time is synchronized and gets the date/time
+void PING_test()
+{
+ struct mw_ping_response *ping_response;
+
+ println("PING to www.example.com ...");
+ print();
+ delay_ms(DEFAULT_DELAY);
+ ping_response = mw_ping("www.example.com", 5u);
+ if(ping_response){
+ sprintf(buffer, "t: %2lu, r: %2lu ms: %5lu", ping_response->transmitted, ping_response->received, ping_response->total_time_ms);
+ println(buffer);
+ }else{
+ println("FAIL PING to www.example.com");
+ }
+}
\ No newline at end of file
diff --git a/sample/megawifi/menu/src/mw-api/random.c b/sample/megawifi/menu/src/mw-api/random.c
new file mode 100644
index 00000000..e9f41d42
--- /dev/null
+++ b/sample/megawifi/menu/src/mw-api/random.c
@@ -0,0 +1,58 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#include "mw-api/random.h"
+
+void RND_start(){
+
+ u16 button;
+ bool repaint = TRUE;
+
+ do{
+ RND_paint(repaint);
+ button = readButton(JOY_1);
+ repaint = RND_doAction(button, 0);
+ print();
+ }while(button != BUTTON_A);
+
+}
+
+void RND_paint(bool repaint){
+ if(repaint){
+ clearScreen();
+ VDP_drawText("RANDOM Test", 1u, 2u);
+ VDP_drawText("Press START to launch", 0u, 3u);
+ VDP_drawText("Press A to return", 0u, 4u);
+ }
+}
+
+bool RND_doAction(u16 button, u8 max_option){
+ switch (button){
+ case BUTTON_START:{
+ RND_test();
+ }
+ default:
+ }
+ return FALSE;
+}
+
+
+/// Waits until date/time is synchronized and gets the date/time
+void RND_test()
+{
+ u8 *rnd;
+
+ rnd = mw_hrng_get(1u);
+ if (!rnd) {
+ println("Failed to get Random");
+ return;
+ }
+ sprintf(buffer, "Random Result: %u", *rnd);
+ println(buffer);
+}
\ No newline at end of file
diff --git a/sample/megawifi/menu/src/mw-api/tcp.c b/sample/megawifi/menu/src/mw-api/tcp.c
new file mode 100644
index 00000000..466a59d8
--- /dev/null
+++ b/sample/megawifi/menu/src/mw-api/tcp.c
@@ -0,0 +1,95 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#include "mw-api/tcp.h"
+
+void TCP_start(){
+
+ u16 button;
+ bool repaint = TRUE;
+ option = 0;
+
+ do{
+ TCP_paint(repaint);
+ button = readButton(JOY_1);
+ repaint = TCP_doAction(button, 0);
+ print();
+ }while(button != BUTTON_A);
+
+}
+
+void TCP_paint(bool repaint){
+ if(repaint){
+ clearScreen();
+ VDP_drawText("TCP Test", 1u, 2u);
+ VDP_drawText("Press START to launch", 0u, 3u);
+ VDP_drawText("Press A to return", 0u, 4u);
+ VDP_drawText("Press B to TCP SERVER", 0u, 5u);
+ }
+}
+
+bool TCP_doAction(u16 button, u8 max_option){
+ switch (button){
+ case BUTTON_START:{
+ TCP_test();
+ break;
+ }
+ case BUTTON_B:{
+ TCP_test_server();
+ }
+ default:
+ }
+ return FALSE;
+}
+
+
+/// Test an TCP GET request to TCPs://www.example.com
+void TCP_test() {
+ enum mw_err err;
+
+ // Connect to www.example.com on port 80
+ println("Connecting to www.example.com");
+ print();
+ delay_ms(DEFAULT_DELAY);
+ err = mw_tcp_connect(1, "www.example.com", "80", NULL);
+ if (err) {
+ println("TCP test FAILED ");
+ }else{
+ println("TCP test SUCCESS ");
+ }
+ //mw_send_sync(1,"a", 1, MS_TO_FRAMES(DEFAULT_MW_DELAY));
+ //mw_recv_sync(1);
+ mw_tcp_disconnect(1);
+}
+
+void TCP_test_server(){
+ println("Creating Server on port 80");
+ print();
+ delay_ms(DEFAULT_DELAY);
+ enum mw_err err = mw_tcp_bind(1u, 80u);
+ if(err)goto err;
+ println("Creating Server OK ");
+ print();
+ delay_ms(DEFAULT_DELAY);
+ println("Waiting connections... ");
+ print();
+ s16 buf_len;
+ u8 ch;
+ err = mw_recv_sync(&ch, cmd_buf, &buf_len, DEFAULT_MW_DELAY);
+ if(err)goto err;
+ println("Receving OK ");
+ paint_long_char(cmd_buf, buf_len, 11u);
+ mw_tcp_disconnect(1u);
+ return;
+err:
+ sprintf(buffer, "MW-ERROR: %u ", err);
+ println(buffer);
+ mw_tcp_disconnect(1u);
+
+}
diff --git a/sample/megawifi/menu/src/mw-api/udp.c b/sample/megawifi/menu/src/mw-api/udp.c
new file mode 100644
index 00000000..aeba4542
--- /dev/null
+++ b/sample/megawifi/menu/src/mw-api/udp.c
@@ -0,0 +1,140 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#include "mw-api/udp.h"
+
+void UDP_start(){
+
+ u16 button;
+ bool repaint = TRUE;
+ option = 0;
+
+ do{
+ UDP_paint(repaint);
+ button = readButton(JOY_1);
+ repaint = UDP_doAction(button, 0);
+ print();
+ }while(button != BUTTON_A);
+
+}
+
+void UDP_paint(bool repaint){
+ if(repaint){
+ clearScreen();
+ VDP_drawText("UDP Test", 1u, 2u);
+ VDP_drawText("Press START to launch", 0u, 3u);
+ VDP_drawText("Press A to return", 0u, 4u);
+ VDP_drawText("Press B to reuse", 0u, 5u);
+ }
+}
+
+bool UDP_doAction(u16 button, u8 max_option){
+ switch (button){
+ case BUTTON_START:
+ UDP_normal_test();
+ break;
+ case BUTTON_B:
+ UDP_reuse_test();
+ break;
+ default:
+ }
+ return FALSE;
+}
+
+
+
+/// Callback set by mw_udp_reuse_recv(), run when data is received
+void udp_recv_cb(enum lsd_status stat, uint8_t ch, char *data, uint16_t len, void *ctx) {
+ const struct mw_reuse_payload *udp =
+ (const struct mw_reuse_payload*)data;
+ UNUSED_PARAM(ctx);
+
+ // Ignore frame if not from channel 2
+ if (LSD_STAT_COMPLETE == stat && 2 == ch) {
+ mw_udp_reuse_send(2, udp, len, NULL, udp_send_complete_cb);
+ } else {
+ mw_udp_reuse_recv((struct mw_reuse_payload*)cmd_buf,
+ MW_BUFLEN, NULL, udp_recv_cb);
+ }
+}
+
+/// Callback set by mw_upd_reuse_send(), run when data is sent
+void udp_send_complete_cb(enum lsd_status stat, void *ctx)
+{
+ struct mw_reuse_payload *pkt = (struct mw_reuse_payload * const)cmd_buf;
+ UNUSED_PARAM(ctx);
+ UNUSED_PARAM(stat);
+
+ // Trigger reception of another UDP packet
+ mw_udp_reuse_recv(pkt, MW_BUFLEN, NULL, udp_recv_cb);
+}
+
+/// Sends "MegaWiFi UDP test!" string to 127.0.0.1:12345. If you are not using
+/// an emulator, change the 127.0.0.1 address with the one for your PC. On your
+/// PC you can receive UDP data e.g. by running command: $ nc -lu 12345
+void UDP_normal_test(void) {
+ char line[40];
+ int16_t len = sizeof(line);
+ uint8_t ch = 1;
+ enum mw_err err = MW_ERR_NONE, errS = MW_ERR_NONE, errR = MW_ERR_NONE;
+
+ // Make sure you are listening on the target address, e.g. with command:
+ // $ nc -lu 12345
+ println("Send to UDP 12345, waiting for reply");
+ // Send UDP data to peer and wait for reply. Localhost works only when
+ // using emulators, so change IP as needed when using the real thing.
+ err = mw_udp_set(ch, "127.0.0.1", "12345", NULL);
+ if (err) goto err;
+ errS = mw_send_sync(ch, "MegaWiFi UDP test!\n", 20, DEFAULT_MW_DELAY);
+ errR = mw_recv_sync(&ch, line, &len, DEFAULT_MW_DELAY);
+ line[min(39, len)] = '\0';
+ if (1 == ch) {
+ VDP_drawText("Got UDP reply:", 0u, 7u);
+ paint_long_char(line, len, 8u);
+ }
+ mw_close(ch);
+
+ return;
+
+err:
+ sprintf(buffer, "MW-ERROR: %u MW-ES: %u MW-ER: %u", err, errS, errR);
+ println(buffer);
+ mw_close(ch);
+}
+
+/// Implements an UDP echo server at port 8007. You can send data to this port
+/// and receive the echo e.g. by running command: $ nc -u 8007
+void UDP_reuse_test(void) {
+ struct mw_reuse_payload *pkt = (struct mw_reuse_payload * const)cmd_buf;
+
+ enum mw_err err = MW_ERR_NONE;
+ enum lsd_status errR = LSD_STAT_COMPLETE;
+
+ // You can send text and get the echo e.g. by:
+ // nc -u 8007
+ println("Doing echo on UDP port 8007");
+ print();
+ delay_ms(DEFAULT_DELAY);
+ // Start UDP echo task
+ err = mw_udp_set(2, NULL, NULL, "8007");
+ if (err) goto err;
+ println("Receiving from UDP 8007, waiting for reply");
+ print();
+ delay_ms(DEFAULT_DELAY);
+ errR = mw_udp_reuse_recv(pkt, MW_BUFLEN, NULL, udp_recv_cb);
+ if (errR) goto err;
+ paint_long_char(pkt->payload, MW_CMD_MAX_BUFLEN - 4 - 2, 11u);
+ mw_close(2);
+ return;
+
+err:
+ sprintf(buffer, "MW-ERROR: %u LSD-ER: %d", err, errR);
+ println(buffer);
+ mw_close(2);
+}
\ No newline at end of file
diff --git a/sample/megawifi/menu/src/mw-api/upgrade.c b/sample/megawifi/menu/src/mw-api/upgrade.c
new file mode 100644
index 00000000..15e5fd6c
--- /dev/null
+++ b/sample/megawifi/menu/src/mw-api/upgrade.c
@@ -0,0 +1,82 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#include "mw-api/upgrade.h"
+
+void UPGRADE_start(){
+ u16 button;
+ bool repaint = TRUE;
+ option = 0;
+ do{
+ UPGRADE_paint(repaint);
+ button = readButton(JOY_1);
+ repaint = UPGRADE_doAction(button, 2u);
+ VDP_drawText("*", 0u, option + 2);
+ print();
+ }while(button != BUTTON_A);
+
+}
+
+void UPGRADE_paint(bool repaint){
+ if(repaint){
+ clearScreen();
+ VDP_drawText("List Firmwares", 1u, 2u);
+ VDP_drawText("Upgrade", 1u, 3u);
+ VDP_drawText("Press START to select", 0u, 4u);
+ VDP_drawText("Press A to return", 0u, 5u);
+ }
+}
+
+bool UPGRADE_doAction(u16 button, u8 max_option){
+ switch (button){
+ case BUTTON_UP:
+ VDP_drawText(" ", 0u, option + 2);
+ if(option > 0) {
+ option--;
+ }
+ break;
+ case BUTTON_DOWN:
+ VDP_drawText(" ", 0u, option + 2);
+ if(option < max_option - 1){
+ option = option+1u % max_option;
+ }
+ break;
+ case BUTTON_START:{
+ switch(option){
+ case 0:
+ if(mw_fw_list_upgrades(0u, 10u, 0u, &listUpgrades, &len, &total)){
+ println("Upgrade Error");
+ }else{
+ len = 0;
+ println("Upgrade OK");
+ }
+ break;
+ case 1:
+ if(len){
+ u16 i = 0;
+ while(listUpgrades[i++]);
+ char rtosName[64];
+ memcpy(rtosName, listUpgrades, i - 1);
+ if(mw_fw_upgrade(rtosName)){
+ println("Upgrade Error");
+ }else{
+ println("Upgrade OK");
+ }
+ }else{
+ println("No Upgrades available");
+ }
+ break;
+ default:
+ }
+ return TRUE;
+ }
+ default:
+ }
+ return FALSE;
+}
\ No newline at end of file
diff --git a/sample/megawifi/menu/src/utils.c b/sample/megawifi/menu/src/utils.c
new file mode 100644
index 00000000..4bf36acb
--- /dev/null
+++ b/sample/megawifi/menu/src/utils.c
@@ -0,0 +1,166 @@
+/****************************************************************************
+ * \brief MegaWiFi2 example.
+ *
+ * \author Juan Antonio (PaCHoN)
+ * \author Jesus Alonso (doragasu)
+ *
+ * \date 01/2025
+ ****************************************************************************/
+
+#include "genesis.h"
+
+#include "utils.h"
+
+u16 readButton(u16 joy){
+ static u16 lastValue = 0;
+ u16 val = JOY_readJoypad(JOY_1);
+ if(val != lastValue){
+ lastValue = val;
+ }else{
+ return 0;
+ }
+ return lastValue;
+}
+void clearScreen(){
+ strclr(buffer);
+ //VDP_clearTextArea(0u,3u, 1u, 3u);
+ for(u16 i = 0; i< SCREEN_ROWS - 1; i++){
+ VDP_clearTextLine(i);
+ }
+}
+
+// Obtener el carácter en la posición (x, y)
+static char getCharFromPosition(u16 x, u16 y) {
+ // Calcula el carácter basado en su posición en la cuadrícula
+ // Offset por empezar en el carácter 32 (espacio)
+ u16 index = y * SCREEN_COLUMNS + x; // Filas comienzan en 1
+ char c = 32 + index;
+
+ if (c >= 32 && c <= 126) {
+ return c;
+ }
+
+ return '\0'; // Fuera del rango imprimible
+}
+
+// Actualizar la posición del cursor según la entrada del pad
+static void updateCursor(u16 *cursorX, u16 *cursorY, u16 button) {
+ if (button == BUTTON_RIGHT && *cursorX < SCREEN_COLUMNS - 1) (*cursorX)++;
+ if (button == BUTTON_LEFT && *cursorX > 0) (*cursorX)--;
+ if (button == BUTTON_DOWN && *cursorY < 5) (*cursorY)++;
+ if (button == BUTTON_UP && *cursorY > 0) (*cursorY)--; // Comienza en fila 1
+}
+
+// Dibujar el alfabeto en la pantalla
+static void drawAlphabet() {
+ char c[2] = " "; // Primer carácter imprimible (espacio)
+
+ for (u16 y = 1; y < SCREEN_ROWS; y++) { // Comienza en la fila 1 (para no tapar el buffer de texto)
+ for (u16 x = 0; x < SCREEN_COLUMNS; x++) {
+ if (c[0] > 126) return; // Detener cuando se pinten todos los caracteres
+ VDP_drawText(c, (x) * 2u + 1u, y);
+ c[0]++; // Siguiente carácter
+ }
+ }
+}
+
+void delay_ms(u16 milliseconds) {
+ u16 frames = MS_TO_FRAMES(milliseconds);
+ for (u16 i = 0; i < frames; i++) {
+ SYS_doVBlankProcess(); // Espera al siguiente VBlank
+ }
+}
+
+void println(const char *str)
+{
+ if (str) {
+ VDP_drawText(str, 1, 0);
+ }
+}
+
+int readText(char* buffer, size_t lengthMax){
+ u16 button;
+ bool next = TRUE;
+ strclr(buffer);
+ u16 textIndex = 0;
+ u16 cursorX = 0, cursorY = 0; // Posición inicial del cursor
+ u16 prevCursorX = cursorX, prevCursorY = cursorY; // Para evitar redibujos innecesarios
+ clearScreen();
+ drawAlphabet();
+ VDP_drawText(">", cursorX * 2, cursorY + 1 ); // Dibuja el nuevo cursor
+ do {
+ button = readButton(JOY_1);
+ // Actualizar la posición del cursor
+ updateCursor(&cursorX, &cursorY, button);
+
+ // Dibujar el cursor en la nueva posición
+ if (cursorX != prevCursorX || cursorY != prevCursorY) {
+ VDP_drawText(" ", prevCursorX * 2, prevCursorY + 1); // Borra el cursor anterior
+ VDP_drawText(">", cursorX * 2, cursorY + 1 ); // Dibuja el nuevo cursor
+ prevCursorX = cursorX;
+ prevCursorY = cursorY;
+ }
+ // Leer la entrada del botón A para seleccionar el carácter
+ if (button == BUTTON_A) {
+ char selectedChar = getCharFromPosition(cursorX, cursorY);
+ if (selectedChar && textIndex < lengthMax - 1) {
+ buffer[textIndex++] = selectedChar; // Agregar al buffer
+ buffer[textIndex] = '\0'; // Finalizar la cadena
+
+ // Mostrar el texto construido hasta ahora en la esquina superior izquierda
+ VDP_clearTextLine(0); // Borra la línea superior
+ VDP_drawText(buffer, 0, 0);
+ }
+ }
+ if (button == BUTTON_B) {
+ char selectedChar = getCharFromPosition(cursorX, cursorY);
+ if (selectedChar && textIndex < lengthMax - 1) {
+ textIndex--;
+ buffer[textIndex] = '\0'; // Finalizar la cadena
+ // Mostrar el texto construido hasta ahora en la esquina superior izquierda
+ VDP_clearTextLine(0); // Borra la línea superior
+ VDP_drawText(buffer, 0, 0);
+ }
+ }
+ if (button == BUTTON_START) {
+ next = FALSE;
+ }
+ SYS_doVBlankProcess();
+ }while(next);
+ return textIndex;
+}
+
+void print(){
+ ciclo++;
+ sprintf(buffer, "%2u", option);
+ VDP_drawText(buffer, 1u, 27u);
+ sprintf(buffer, "%6lu", ciclo);
+ VDP_drawText(buffer, 25u, 27u);
+ SYS_doVBlankProcess();
+}
+
+void printStatus(union mw_msg_sys_stat * status){
+ if(status!=NULL){
+ if(status->sys_stat == MW_ST_READY){
+ VDP_drawText("READY", 5u, 27u);
+ }else{
+ VDP_drawText("NO CON", 5u, 27u);
+ }
+ }
+ SYS_doVBlankProcess();
+}
+
+
+
+void paint_long_char(const char *cert, u16 len, u8 line){
+ u16 from = 0;
+ u8 cicles = 0;
+ for(u16 i = 0; i < len && cicles < 5; i++){
+ if(cert[i] == '\n' || (i + 1) % 40u == 0 || i == len - 1u){
+ VDP_drawText(cert + from, 0u, line++);
+ from = i + 1;
+ cicles++;
+ }
+ }
+ VDP_drawText("...", 0u, line);
+}
\ No newline at end of file
diff --git a/src/ext/mw/16c550.c b/src/ext/mw/16c550.c
index 29b92310..f6dae1fc 100644
--- a/src/ext/mw/16c550.c
+++ b/src/ext/mw/16c550.c
@@ -1,36 +1,36 @@
-#include "config.h"
-
-#if (MODULE_MEGAWIFI != 0)
-
-#include "ext/mw/16c550.h"
-
-/// Shadow copy of the UART registers
-UartShadow sh;
-
-void uart_init(void) {
- // Set line to BR,8N1. LCR[7] must be set to access DLX registers
- UART_LCR = 0x83;
- UART_DLM = UART_DLM_VAL;
- UART_DLL = UART_DLL_VAL;
- uart_set(LCR, 0x03);
-
- // Enable auto RTS/CTS.
- uart_set(MCR, 0x22);
-
- // Enable FIFOs, set trigger level to 14 bytes.
- // NOTE: Even though trigger level is 14 bytes, RTS is de-asserted when
- // receiving the first bit of the 16th byte entering the FIFO. See Fig. 9
- // of the SC16C550B datasheet.
- UART_FCR = 0xC1;
- // Reset FIFOs
- uart_set(FCR, 0xC7);
-
- // Set IER default value (for the shadow register to load).
- uart_set(IER, 0x00);
-
- // Ready to go! Interrupt and DMA modes were not configured since the
- // Megadrive console lacks interrupt/DMA control pins on cart connector
- // (shame on Masami Ishikawa for not including a single interrupt line!).
-}
-
+#include "config.h"
+
+#if (MODULE_MEGAWIFI == 1 && MODULE_EVERDRIVE == 0)
+
+#include "ext/mw/16c550.h"
+
+/// Shadow copy of the UART registers
+UartShadow sh;
+
+void uart_init(void) {
+ // Set line to BR,8N1. LCR[7] must be set to access DLX registers
+ UART_LCR = 0x83;
+ UART_DLM = UART_DLM_VAL;
+ UART_DLL = UART_DLL_VAL;
+ uart_set(LCR, 0x03);
+
+ // Enable auto RTS/CTS.
+ uart_set(MCR, 0x22);
+
+ // Enable FIFOs, set trigger level to 14 bytes.
+ // NOTE: Even though trigger level is 14 bytes, RTS is de-asserted when
+ // receiving the first bit of the 16th byte entering the FIFO. See Fig. 9
+ // of the SC16C550B datasheet.
+ UART_FCR = 0xC1;
+ // Reset FIFOs
+ uart_set(FCR, 0xC7);
+
+ // Set IER default value (for the shadow register to load).
+ uart_set(IER, 0x00);
+
+ // Ready to go! Interrupt and DMA modes were not configured since the
+ // Megadrive console lacks interrupt/DMA control pins on cart connector
+ // (shame on Masami Ishikawa for not including a single interrupt line!).
+}
+
#endif // MODULE_MEGAWIFI
\ No newline at end of file
diff --git a/src/ext/mw/lsd.c b/src/ext/mw/lsd.c
index 356e965c..ea94a0c1 100644
--- a/src/ext/mw/lsd.c
+++ b/src/ext/mw/lsd.c
@@ -4,7 +4,8 @@
* data link.
*
* \author Jesus Alonso (doragasu)
- * \date 2016
+ * \author Juan Antonio (PaCHoN)
+ * \date 2016~2025
* \todo Implement UART RTS/CTS handshaking.
* \todo Current implementation uses polling. Unfortunately as the Genesis/
* Megadrive does not have an interrupt pin on the cart, implementing
@@ -17,7 +18,7 @@
#include "memory.h"
-#if (MODULE_MEGAWIFI != 0)
+#if (MODULE_MEGAWIFI == 1)
#include "ext/mw/lsd.h"
/// Uart used for LSD
@@ -363,11 +364,13 @@ enum lsd_status lsd_recv_sync(char *buf, uint16_t *len, uint8_t *ch)
void lsd_line_sync(void)
{
+#if (MODULE_EVERDRIVE == 0)
for (int i = 0; i < 256; i++) {
if (uart_tx_ready()) {
uart_putc(0x55);
}
}
+#endif
}
#endif // MODULE_MEGAWIFI
\ No newline at end of file
diff --git a/src/ext/mw/megawifi.c b/src/ext/mw/megawifi.c
index 61d76f4b..a71281c2 100644
--- a/src/ext/mw/megawifi.c
+++ b/src/ext/mw/megawifi.c
@@ -2,7 +2,8 @@
* \brief MeGaWiFi API implementation.
*
* \author Jesus Alonso (doragasu)
- * \date 2015
+ * \author Juan Antonio (PaCHoN)
+ * \date 2025
*
* \note Module is not reentrant.
*
@@ -17,7 +18,7 @@
#include "memory.h"
#include "task.h"
-#if (MODULE_MEGAWIFI != 0)
+#if (MODULE_MEGAWIFI == 1)
#include "ext/mw/megawifi.h"
@@ -138,10 +139,8 @@ int16_t mw_init(uint16_t *cmd_buf, uint16_t buf_len)
uart_clr_bits(MCR, MW__PRG | MW__PD);
// Try accessing UART scratch pad register to see if it is installed
- UART_SPR = 0x55;
- if (UART_SPR != 0x55) return MW_ERR;
- UART_SPR = 0xAA;
- if (UART_SPR != 0xAA) return MW_ERR;
+ uart_test(UART_SPR, 0x55);
+ uart_test(UART_SPR, 0xAA);
// Enable control channel
lsd_ch_enable(MW_CTRL_CH);
@@ -1476,4 +1475,52 @@ enum mw_err mw_fw_upgrade(const char *name)
return MW_ERR_NONE;
}
+enum mw_err mw_fw_list_upgrades(uint8_t page, uint8_t size, uint8_t offset, char **listUpgrades, uint8_t *len, uint8_t *total)
+{
+ enum mw_err err;
+
+ if (!d.mw_ready) {
+ return MW_ERR_NOT_READY;
+ }
+
+ d.cmd->cmd = MW_CMD_UPGRADE_LIST;
+ d.cmd->data[0] = page;
+ d.cmd->data[1] = size;
+ d.cmd->data[2] = offset;
+ d.cmd->data_len = 3;
+ err = mw_command(MW_UPGRADE_TOUT);
+ if (err) {
+ return MW_ERR;
+ }
+
+ *listUpgrades = d.cmd->ug_list_response.payload;
+ *len = d.cmd->ug_list_response.len;
+ *total = d.cmd->ug_list_response.total;
+ return MW_ERR_NONE;
+}
+
+struct mw_ping_response *mw_ping(const char* domain, u8 retries)
+{
+ enum mw_err err;
+
+ if (!d.mw_ready) {
+ return NULL;
+ }
+
+ if (!domain) {
+ return NULL;
+ }
+
+ d.cmd->cmd = MW_CMD_PING;
+ d.cmd->data_len = sizeof(struct mw_ping_request);
+ strcpy(d.cmd->ping.domain, domain);
+ d.cmd->ping.retries = retries;
+ err = mw_command(MW_CONNECT_TOUT * retries);
+ if (err) {
+ return NULL;
+ }
+
+ return &d.cmd->ping_response;
+}
+
#endif // MODULE_MEGAWIFI
\ No newline at end of file
diff --git a/src/ext/mw/ssf.c b/src/ext/mw/ssf.c
new file mode 100644
index 00000000..0494e7ef
--- /dev/null
+++ b/src/ext/mw/ssf.c
@@ -0,0 +1,33 @@
+/************************************************************************
+ * \brief Simple SSF driver.
+ *
+ * \author Juan Antonio Ruiz (PaCHoN)
+ * \date 2024
+ * \defgroup SSF SSF
+ * \brief
+ * SSF Implementation.
+*************************************** */
+#include "config.h"
+
+#if (MODULE_MEGAWIFI == 1 && MODULE_EVERDRIVE == 1)
+
+#include "ext/mw/ssf.h"
+
+volatile u16 ctrl;
+volatile u16 cfg_io;
+
+void uart_init(void) {
+ ctrl = SSF_CTRL_P;
+ cfg_io = CFG_SPI_SS;
+
+ UART_REG_SSF_CTRL = ctrl;
+ UART_REG_CFG = cfg_io;
+
+ for (u8 i = 1; i < 8; i++)ssf_set_rom_bank(i, i);
+}
+
+void ssf_set_rom_bank(u8 bank, u8 val) {
+ *((volatile u16 *)(UART_BASE + UART_REG_SSF_CTRL + bank * 2u)) = val;
+}
+
+#endif // MODULE_MEGAWIFI SSF IMPL
\ No newline at end of file