Move ARCH_RP2040 --> ARCH_PICOSDK

This commit is contained in:
Sergio R. Caprile committed 2024-11-08 14:34:33 -03:00
1 parent 7844d84798
commit 58327a1753
69 files changed
+15 -13

No files matched your search

+1
View File
@@ -0,0 +1 @@
pico-sdk
-19
View File
@@ -1,19 +0,0 @@
cmake_minimum_required(VERSION 3.13)
include(pico-sdk/pico_sdk_init.cmake)
project(firmware)
pico_sdk_init()
add_executable(firmware
driver_rp2040_rmii.c
main.c
mongoose.c)
target_include_directories(firmware PUBLIC
.)
target_link_libraries(firmware hardware_pio hardware_dma pico_stdlib pico_rand)
pico_add_extra_outputs(firmware) # create map/bin/hex file etc.
pico_enable_stdio_usb(firmware 1) # Route stdio
pico_enable_stdio_uart(firmware 0) # to USB
-20
View File
@@ -1,20 +0,0 @@
RM = rm -rf
MKBUILD = test -d build || mkdir build
ifeq ($(OS),Windows_NT)
RM = cmd /C del /Q /F /S
MKBUILD = if not exist build mkdir build
endif
all example:
true
build: pico-sdk
$(MKBUILD)
cd build && cmake -G "Unix Makefiles" .. && make
pico-sdk:
git clone --depth 1 -b 1.4.0 https://github.com/raspberrypi/pico-sdk $@
cd $@ && git submodule update --init
clean:
$(RM) pico-sdk build
-1
View File
@@ -1 +0,0 @@
See detailed tutorial (including hardware connections) at https://mongoose.ws/tutorials/rp2040/pico-rmii/
@@ -1,336 +0,0 @@
// Copyright (c) 2022 Cesanta Software Limited
// All rights reserved
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "hardware/dma.h"
#include "hardware/pio.h"
#include "pico/stdlib.h"
#include "driver_rp2040_rmii.h"
#include "mongoose.h"
#define RXSM 0
#define TXSM 1
#define SMITXSM 2
#define SMIRXSM 0 // pio1
static uint smi_wr_addr, smi_rd_addr;
static int dma_rx;
static int dma_tx;
static dma_channel_config dmacfg_rx;
static dma_channel_config dmacfg_tx;
// Max frame size with VLAN tag + CRC and excluding preamble
#define ETH_PKT_SIZE 1522
static uint8_t s_rxbuf[2][ETH_PKT_SIZE]; // ping-pong buffer
static uint8_t s_txbuf[ETH_PKT_SIZE];
static struct mg_tcpip_if *s_ifp; // MIP interface
#define rmii_tx_wrap_target 0
#define rmii_tx_wrap 7
static const uint16_t rmii_tx_program_instructions[] = {
// .wrap_target
0xe000, // 0: set pins, 0 side 0
0x80a0, // 1: pull block side 0
0xe03d, // 2: set x, 29 side 0
0xf101, // 3: set pins, 1 side 1 [1]
0x1144, // 4: jmp x--, 4 side 1 [1]
0xf103, // 5: set pins, 3 side 1 [1]
0x7002, // 6: out pins, 2 side 1
0x10e6, // 7: jmp !osre, 6 side 1
// .wrap
};
static const struct pio_program rmii_tx_program = {
.instructions = rmii_tx_program_instructions,
.length = 8,
.origin = -1,
};
static inline pio_sm_config rmii_tx_program_get_default_config(uint addr) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, addr + rmii_tx_wrap_target, addr + rmii_tx_wrap);
sm_config_set_sideset(&c, 1, false, false);
return c;
}
static inline void rmii_tx_init(PIO pio, uint sm, uint addr, uint gpio) {
pio_sm_config c = rmii_tx_program_get_default_config(addr);
pio_gpio_init(pio, gpio);
pio_gpio_init(pio, gpio + 1);
pio_gpio_init(pio, gpio + 2);
sm_config_set_out_pins(&c, gpio, 2);
sm_config_set_set_pins(&c, gpio, 2);
sm_config_set_sideset_pins(&c, gpio + 2);
pio_sm_set_consecutive_pindirs(pio, sm, gpio, 3, true);
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_TX);
sm_config_set_out_shift(&c, true, true, 8); // pull bytes, LSB first, auto
sm_config_set_clkdiv(&c,
5); // Run at 50/5 = 10MHz (2x 2-bit nibble data rate)
pio_sm_init(pio, sm, addr, &c);
pio_sm_set_enabled(pio, sm, true);
}
#define rmii_rx_wrap_target 0
#define rmii_rx_wrap 10
static const uint16_t rmii_rx_program_instructions[] = {
// .wrap_target
0x2122, // 0: wait 0 pin, 2 [1]
0x21a2, // 1: wait 1 pin, 2 [1]
0x21a0, // 2: wait 1 pin, 0 [1]
0x2121, // 3: wait 0 pin, 1 [1]
0x21a1, // 4: wait 1 pin, 1 [1]
0x4002, // 5: in pins, 2
0x00c5, // 6: jmp pin, 5
0x4002, // 7: in pins, 2
0x00c5, // 8: jmp pin, 5
0xa0c3, // 9: mov isr, null
0xc020, // 10: irq wait 0
// .wrap
};
static const struct pio_program rmii_rx_program = {
.instructions = rmii_rx_program_instructions,
.length = 11,
.origin = -1,
};
static inline pio_sm_config rmii_rx_program_get_default_config(uint addr) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, addr + rmii_rx_wrap_target, addr + rmii_rx_wrap);
return c;
}
static inline void rmii_rx_init(PIO pio, uint sm, uint addr, uint gpio) {
pio_sm_config c = rmii_rx_program_get_default_config(addr);
pio_gpio_init(pio, gpio);
pio_gpio_init(pio, gpio + 1);
pio_gpio_init(pio, gpio + 2);
sm_config_set_in_pins(&c, gpio);
pio_sm_set_consecutive_pindirs(pio, sm, gpio, 3, false);
sm_config_set_jmp_pin(&c, gpio + 2);
sm_config_set_in_shift(&c, true, true, 8); // push bytes, LSB first, auto
sm_config_set_fifo_join(&c, PIO_FIFO_JOIN_RX);
sm_config_set_clkdiv(&c,
5); // Run at 50/5 = 10MHz (2x 2-bit nibble data rate)
pio_sm_init(pio, sm, addr, &c);
pio_sm_set_enabled(pio, sm, true);
}
#define smi_wr_wrap_target 0
#define smi_wr_wrap 4
static const uint16_t smi_wr_program_instructions[] = {
// .wrap_target
0xe03f, // 0: set x, 31 side 0
0xe101, // 1: set pins, 1 side 0 [1]
0x1141, // 2: jmp x--, 1 side 1 [1]
0x6101, // 3: out pins, 1 side 0 [1]
0x1103, // 4: jmp 3 side 1 [1]
// .wrap
};
static const struct pio_program smi_wr_program = {
.instructions = smi_wr_program_instructions,
.length = 5,
.origin = -1,
};
static inline pio_sm_config smi_wr_program_get_default_config(uint addr) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, addr + smi_wr_wrap_target, addr + smi_wr_wrap);
sm_config_set_sideset(&c, 1, false, false);
return c;
}
#define smi_rd_wrap_target 13
#define smi_rd_wrap 13
static const uint16_t smi_rd_program_instructions[] = {
0xe03f, // 0: set x, 31 side 0
0xe101, // 1: set pins, 1 side 0 [1]
0x1141, // 2: jmp x--, 1 side 1 [1]
0xf02d, // 3: set x, 13 side 1
0x6101, // 4: out pins, 1 side 0 [1]
0x1144, // 5: jmp x--, 4 side 1 [1]
0xe180, // 6: set pindirs, 0 side 0 [1]
0xf101, // 7: set pins, 1 side 1 [1]
0xa142, // 8: nop side 0 [1]
0xf12f, // 9: set x, 15 side 1 [1]
0xa042, // 10: nop side 0
0x4001, // 11: in pins, 1 side 0
0x114a, // 12: jmp x--, 10 side 1 [1]
// .wrap_target
0xf081, // 13: set pindirs, 1 side 1
// .wrap
};
static const struct pio_program smi_rd_program = {
.instructions = smi_rd_program_instructions,
.length = 14,
.origin = -1,
};
static inline pio_sm_config smi_rd_program_get_default_config(uint addr) {
pio_sm_config c = pio_get_default_sm_config();
sm_config_set_wrap(&c, addr + smi_rd_wrap_target, addr + smi_rd_wrap);
sm_config_set_sideset(&c, 1, false, false);
return c;
}
static inline void smi_wr_init(PIO pio, uint sm, uint addr, uint gpio) {
pio_gpio_init(pio, gpio);
pio_gpio_init(pio, gpio + 1);
pio_sm_config c = smi_wr_program_get_default_config(addr);
sm_config_set_out_pins(&c, gpio, 1);
sm_config_set_set_pins(&c, gpio, 1);
sm_config_set_sideset_pins(&c, gpio + 1);
pio_sm_set_consecutive_pindirs(pio, sm, gpio, 2, true);
sm_config_set_out_shift(&c, false, true,
16); // pull half-words, MSB first, auto
sm_config_set_clkdiv(&c, 6); // Run at 50/6 = <10MHz (4x data rate)
pio_sm_init(pio, sm, addr, &c);
}
static inline void smi_rd_init(PIO pio, uint sm, uint addr, uint gpio) {
pio_gpio_init(pio, gpio);
pio_gpio_init(pio, gpio + 1);
pio_sm_config c = smi_rd_program_get_default_config(addr);
sm_config_set_in_pins(&c, gpio);
sm_config_set_out_pins(&c, gpio, 1);
sm_config_set_set_pins(&c, gpio, 1);
sm_config_set_sideset_pins(&c, gpio + 1);
pio_sm_set_consecutive_pindirs(pio, sm, gpio, 2, true);
sm_config_set_out_shift(&c, false, true,
16); // pull half-words, MSB first, auto
sm_config_set_in_shift(&c, false, true,
16); // push half-words, MSB first, auto
sm_config_set_clkdiv(&c, 6); // Run at 50/6 = <10MHz (4x data rate)
pio_sm_init(pio, sm, addr, &c);
}
static void eth_write_phy(int addr, int reg, int val, uint8_t gpio) {
uint16_t op = 0x5002 | (addr << 7) | (reg << 2); // b0101aaaaarrrrr10
smi_wr_init(pio0, SMITXSM, smi_wr_addr, gpio);
pio_sm_put(pio0, SMITXSM, op << 16);
pio_sm_put(pio0, SMITXSM, (uint16_t) val << 16);
pio_sm_set_enabled(pio0, SMITXSM, true);
}
static uint16_t eth_read_phy(uint addr, uint reg, uint8_t gpio) {
uint16_t op = 0x6000 | (addr << 7) | (reg << 2); // b0110aaaaarrrrr00
smi_rd_init(pio1, SMIRXSM, smi_rd_addr, gpio);
pio_sm_put(pio1, SMIRXSM, op << 16);
pio_sm_set_enabled(pio1, SMIRXSM, true);
uint16_t val = (uint16_t) pio_sm_get_blocking(pio1, SMIRXSM);
pio_sm_set_enabled(pio1, SMIRXSM, false);
return val;
}
static void rx_irq(void);
static bool mg_tcpip_driver_rp2040_rmii_init(struct mg_tcpip_if *ifp) {
struct mg_tcpip_driver_rp2040_rmii_data *d =
(struct mg_tcpip_driver_rp2040_rmii_data *) ifp->driver_data;
uint rx_sm_addr, tx_sm_addr;
s_ifp = ifp;
rx_sm_addr = pio_add_program(pio0, &rmii_rx_program);
tx_sm_addr = pio_add_program(pio0, &rmii_tx_program);
smi_wr_addr = pio_add_program(pio0, &smi_wr_program);
smi_rd_addr = pio_add_program(pio1, &smi_rd_program);
dma_tx = dma_claim_unused_channel(true);
dmacfg_tx = dma_channel_get_default_config(dma_tx);
channel_config_set_read_increment(&dmacfg_tx, true); // read from memory
channel_config_set_write_increment(&dmacfg_tx, false); // write to FIFO
channel_config_set_dreq(&dmacfg_tx, pio_get_dreq(pio0, TXSM, true));
channel_config_set_transfer_data_size(&dmacfg_tx,
DMA_SIZE_8); // transfer bytes
rmii_tx_init(pio0, TXSM, tx_sm_addr, d->tx0);
eth_write_phy(d->phy_addr, 4, 0x61,
d->mdio); // Auto Negotiation Advertisement Register: enable
// only 10BASE-T full and half duplex (two-pair), use
// IEEE 802.3 format
sleep_us(31); // give some time for PIO to work (64 bits @2.5MHz = 25.6 us)
eth_write_phy(d->phy_addr, 0, 0x1000,
d->mdio); // Basic Control Register: enable Auto-Negotiation
sleep_us(31);
dma_rx = dma_claim_unused_channel(true);
dmacfg_rx = dma_channel_get_default_config(dma_rx);
channel_config_set_read_increment(&dmacfg_rx, false); // read from FIFO
channel_config_set_write_increment(&dmacfg_rx,
true); // write to memory, increment
channel_config_set_dreq(&dmacfg_rx, pio_get_dreq(pio0, RXSM, false));
channel_config_set_transfer_data_size(&dmacfg_rx,
DMA_SIZE_8); // transfer bytes
dma_channel_configure(dma_rx, &dmacfg_rx, s_rxbuf[0],
((uint8_t *) &pio0->rxf[RXSM]) + 3, ETH_PKT_SIZE, true);
pio_set_irq0_source_enabled(pio0, pis_interrupt0,
true); // enable SM0 on PIO0_IRQ_0
irq_set_exclusive_handler(7, rx_irq); // set handler for PIO0_IRQ_0
irq_set_enabled(7, true); // enable it
rmii_rx_init(pio0, RXSM, rx_sm_addr, d->rx0);
return true;
}
static size_t mg_tcpip_driver_rp2040_rmii_tx(const void *buf, size_t len,
struct mg_tcpip_if *ifp) {
dma_channel_wait_for_finish_blocking(dma_tx);
memset(s_txbuf, 0, 60); // pre-pad
memcpy(s_txbuf, buf, len);
if (len < 60) len = 60; // pad
uint32_t crc = mg_crc32(0, s_txbuf, len); // host is little-endian
memcpy(s_txbuf + len, (uint8_t *) &crc, 4);
len += 4;
sleep_us(10); // enforce IFG in case software has been lightning fast...
dma_channel_configure(dma_tx, &dmacfg_tx, ((uint8_t *) &pio0->txf[TXSM]) + 3,
s_txbuf, len, true);
return len;
}
static uint32_t s_rxno;
// The max amount of time we should keep the PIO state machine stopped is the
// IFG time (10us) and that includes irq latency
static void rx_irq(void) {
dma_channel_hw_t *hw = dma_channel_hw_addr(dma_rx);
uint32_t rxno =
(s_rxno + 1) &
1; // 2 buffers, switch to the available one as fast as possible
size_t len = ETH_PKT_SIZE - hw->transfer_count;
dma_channel_abort(dma_rx);
dma_channel_set_write_addr(dma_rx, s_rxbuf[rxno], true); // restart DMA
pio_interrupt_clear(pio0,
0); // ACK PIO IRQ so the state machine resumes receiving
// NOTE(scaprile) Here we could check addressing to avoid queuing frames not
// for us. The max amount of time we can linger here is what it takes for the
// other buffer to fill (<8us) and that includes irq chaining
if (len >= 64 && len <= ETH_PKT_SIZE)
mg_tcpip_qwrite(s_rxbuf[s_rxno], len, s_ifp);
s_rxno = rxno;
}
static bool mg_tcpip_driver_rp2040_rmii_up(struct mg_tcpip_if *ifp) {
struct mg_tcpip_driver_rp2040_rmii_data *d =
(struct mg_tcpip_driver_rp2040_rmii_data *) ifp->driver_data;
uint32_t bsr =
eth_read_phy(d->phy_addr, 1, d->mdio); // Basic Status Register
return (bsr & (1 << 2)) ? 1 : 0; // check Link Status flag
}
struct mg_tcpip_driver mg_tcpip_driver_rp2040_rmii = {
mg_tcpip_driver_rp2040_rmii_init,
mg_tcpip_driver_rp2040_rmii_tx,
NULL,
mg_tcpip_driver_rp2040_rmii_up,
};
@@ -1,10 +0,0 @@
#pragma once
struct mg_tcpip_driver_rp2040_rmii_data {
uint8_t rx0; // RX0, RX1, CRS_DV; consecutive GPIO pins
uint8_t tx0; // TX0, TX1, TX-EN; consecutive GPIO pins
uint8_t mdio; // MDIO, MDC; consecutive GPIO pins
uint8_t phy_addr; // PHY address
};
extern struct mg_tcpip_driver mg_tcpip_driver_rp2040_rmii;
-57
View File
@@ -1,57 +0,0 @@
// Copyright (c) 2022 Cesanta Software Limited
// All rights reserved
#include "pico/stdlib.h"
#include "hardware/clocks.h"
#include "mongoose.h"
#include "driver_rp2040_rmii.h"
#define CLKREFPIN 20 // either 20 or 22
static void fn(struct mg_connection *c, int ev, void *ev_data) {
if (ev == MG_EV_HTTP_MSG) {
mg_http_reply(c, 200, "", "ok\n");
}
}
int main(void) {
// use the RMII reference clock (50MHz) as our system clock
clock_configure_gpin(clk_sys, CLKREFPIN, 50 * MHZ, 50 * MHZ);
sleep_ms(100);
stdio_init_all();
struct mg_mgr mgr; // Initialise Mongoose event manager
mg_mgr_init(&mgr); // and attach it to the interface
mg_log_set(MG_LL_DEBUG); // Set log level
MG_INFO(("Init TCP/IP"));
// Initialise Mongoose network stack and specific driver
// Set consecutive GPIOs for RMII (tx and rx) and SMI function groups
struct mg_tcpip_driver_rp2040_rmii_data driver_data = {
// see driver_rp2040_rmii.h
.rx0 = 6, // 6, 7, 8 : RX0, RX1, CRS_DV
.tx0 = 10, // 10, 11, 12 : TX0, TX1, TX-EN
.mdio = 14, // 14, 15 : MDIO, MDC
.phy_addr = 1 // check your hardware, LAN8722 is 0 or 1
};
// Specify MAC address, either set use_dhcp or enter a static config.
// For static configuration, specify IP/mask/GW in network byte order
struct mg_tcpip_if mif = {
.mac = {2, 0, 1, 2, 3, 5},
.ip = 0,
.enable_mac_check = true,
.enable_crc32_check = true,
.driver = &mg_tcpip_driver_rp2040_rmii,
.driver_data = &driver_data,
};
mg_tcpip_init(&mgr, &mif);
mg_http_listen(&mgr, "http://0.0.0.0", fn, NULL); // HTTP listener
MG_INFO(("Init done, starting main loop"));
for (;;) mg_mgr_poll(&mgr, 0); // Infinite event loop
return 0;
}
-1
View File
@@ -1 +0,0 @@
../../../mongoose.c
-1
View File
@@ -1 +0,0 @@
../../../mongoose.h
@@ -1,5 +0,0 @@
#define MG_ARCH MG_ARCH_RP2040
#define MG_ENABLE_TCPIP 1
#define MG_ENABLE_TCPIP_DRIVER_INIT 0
#define MG_ENABLE_PACKED_FS 1
@@ -1,32 +0,0 @@
cmake_minimum_required(VERSION 3.13)
include(pico-sdk/pico_sdk_init.cmake)
project(firmware)
pico_sdk_init()
add_executable(firmware
main.c
msc_disk.c
usb_descriptors.c
mongoose.c
net.c
packed_fs.c
pico-sdk/lib/tinyusb/lib/networking/rndis_reports.c)
target_include_directories(firmware PUBLIC
.
pico-sdk/lib/tinyusb/lib/networking)
target_link_libraries(firmware pico_stdlib pico_rand hardware_spi tinyusb_device)
pico_add_extra_outputs(firmware) # create map/bin/hex file etc.
pico_enable_stdio_usb(firmware 0) # Route stdio
pico_enable_stdio_uart(firmware 1) # to the UART
# Mongoose build flags in mongoose_config.h
# Example build options
add_definitions(-DHTTP_URL="http://0.0.0.0/")
# Extra build flags (enable if needed)
add_definitions(-DDUAL_CONFIG=0)
@@ -1,20 +0,0 @@
RM = rm -rf
MKBUILD = test -d build || mkdir build
ifeq ($(OS),Windows_NT)
RM = cmd /C del /Q /F /S
MKBUILD = if not exist build mkdir build
endif
all example:
true
build: pico-sdk
$(MKBUILD)
cd build && cmake -G "Unix Makefiles" .. && make
pico-sdk:
git clone --depth 1 -b 1.4.0 https://github.com/raspberrypi/pico-sdk $@
cd $@ && git submodule update --init
clean:
$(RM) pico-sdk build
@@ -1,7 +0,0 @@
# Device Dashboard via RNDIS on an RP2040
Your headless Raspberry Pi Pico-based hardware can also have a device dashboard on a web browser when you connect it to your computer via USB
- See detailed tutorial at https://mongoose.ws/tutorials/rp2040/pico-rndis-dashboard/
Note for Mac users: For this example to run on Mac, please set `DUAL_CONFIG=1` in `CMakeLists.txt` before building; this enables CDC-ECM. Please notice that Windows may not recognize the mass-storage device in that case.
@@ -1,81 +0,0 @@
// Copyright (c) 2022 Cesanta Software Limited
// All rights reserved
#include "mongoose.h"
#include "net.h"
#include "pico/stdlib.h"
#include "tusb.h"
static struct mg_tcpip_if *s_ifp;
const uint8_t tud_network_mac_address[6] = {2, 2, 0x84, 0x6A, 0x96, 0};
static void blink_cb(void *arg) { // Blink periodically
gpio_put(PICO_DEFAULT_LED_PIN, !gpio_get_out_level(PICO_DEFAULT_LED_PIN));
(void) arg;
}
bool tud_network_recv_cb(const uint8_t *buf, uint16_t len) {
mg_tcpip_qwrite((void *) buf, len, s_ifp);
// MG_INFO(("RECV %hu", len));
// mg_hexdump(buf, len);
tud_network_recv_renew();
return true;
}
void tud_network_init_cb(void) {}
uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg) {
// MG_INFO(("SEND %hu", arg));
memcpy(dst, ref, arg);
return arg;
}
static size_t usb_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) {
if (!tud_ready()) return 0;
while (!tud_network_can_xmit(len)) tud_task();
tud_network_xmit((void *) buf, len);
(void) ifp;
return len;
}
static bool usb_up(struct mg_tcpip_if *ifp) {
(void) ifp;
return tud_inited() && tud_ready() && tud_connected();
}
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_dta) {
if (ev == MG_EV_HTTP_MSG) return mg_http_reply(c, 200, "", "ok\n");
}
int main(void) {
gpio_init(PICO_DEFAULT_LED_PIN);
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
stdio_init_all();
struct mg_mgr mgr; // Initialise Mongoose event manager
mg_mgr_init(&mgr); // and attach it to the interface
mg_timer_add(&mgr, 500, MG_TIMER_REPEAT, blink_cb, &mgr);
struct mg_tcpip_driver driver = {.tx = usb_tx, .up = usb_up};
struct mg_tcpip_if mif = {.mac = {2, 0, 1, 2, 3, 0x77},
.ip = mg_htonl(MG_U32(192, 168, 3, 1)),
.mask = mg_htonl(MG_U32(255, 255, 255, 0)),
.enable_dhcp_server = true,
.driver = &driver,
.recv_queue.size = 4096};
s_ifp = &mif;
mg_tcpip_init(&mgr, &mif);
tusb_init();
MG_INFO(("Initialising application..."));
web_init(&mgr);
MG_INFO(("Starting event loop"));
for (;;) {
mg_mgr_poll(&mgr, 0);
tud_task();
}
return 0;
}
@@ -1 +0,0 @@
../../../mongoose.c
@@ -1 +0,0 @@
../../../mongoose.h
@@ -1,6 +0,0 @@
#define MG_ARCH MG_ARCH_RP2040
#define MG_ENABLE_TCPIP 1
#define MG_ENABLE_TCPIP_DRIVER_INIT 0
#define MG_ENABLE_PACKED_FS 1
#define MG_ENABLE_POSIX_FS 0
@@ -1,252 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
// Modified by Cesanta Software
#include "tusb.h"
// Some MCU doesn't have enough 8KB SRAM to store the whole disk
enum
{
DISK_BLOCK_NUM = 16, // 8KB is the smallest size that Windows allows to mount
DISK_BLOCK_SIZE = 512
};
#define INDEX_CONTENTS \
"<head><meta http-equiv=\"Refresh\" content=\"0;url=http://192.168.3.1\"></head><body></body>"
// readonly
const uint8_t msc_disk0[DISK_BLOCK_NUM][DISK_BLOCK_SIZE] =
{
//------------- Block0: Boot Sector -------------//
// byte_per_sector = DISK_BLOCK_SIZE; fat12_sector_num_16 = DISK_BLOCK_NUM;
// sector_per_cluster = 1; reserved_sectors = 1;
// fat_num = 1; fat12_root_entry_num = 16;
// sector_per_fat = 1; sector_per_track = 1; head_num = 1; hidden_sectors = 0;
// drive_number = 0x80; media_type = 0xf8; extended_boot_signature = 0x29;
// filesystem_type = "FAT12 "; volume_serial_number = 0x1234; volume_label = "TinyUSB 0 ";
// FAT magic code at offset 510-511
{
0xEB, 0x3C, 0x90, 0x4D, 0x53, 0x44, 0x4F, 0x53, 0x35, 0x2E, 0x30, 0x00, 0x02, 0x01, 0x01, 0x00,
0x01, 0x10, 0x00, 0x10, 0x00, 0xF8, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x29, 0x34, 0x12, 0x00, 0x00, 'T' , 'i' , 'n' , 'y' , 'U' ,
'S' , 'B' , ' ' , 'C' , ' ' , ' ' , 0x46, 0x41, 0x54, 0x31, 0x32, 0x20, 0x20, 0x20, 0x00, 0x00,
// Zero up to 2 last bytes of FAT magic code
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x55, 0xAA
},
//------------- Block1: FAT12 Table -------------//
{
0xF8, 0xFF, 0xFF, 0xFF, 0x0F // // first 2 entries must be F8FF, third entry is cluster end of readme file
},
//------------- Block2: Root Directory -------------//
{
// first entry is volume label
'M' , 'o' , 'n' , 'g' , 'o' , 'o' , 's' , 'e' , ' ' , ' ' , ' ' , 0x08, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x4F, 0x6D, 0x65, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
// second entry is our file
'I' , 'N' , 'D' , 'E' , 'X' , ' ' , ' ' , ' ' , 'H' , 'T' , 'M' , 0x20, 0x00, 0xC6, 0x52, 0x6D,
0x65, 0x43, 0x65, 0x43, 0x00, 0x00, 0x88, 0x6D, 0x65, 0x43, 0x02, 0x00,
sizeof(INDEX_CONTENTS)-1, 0x00, 0x00, 0x00 // readme's files size (4 Bytes)
},
//------------- Block3: file Content -------------//
INDEX_CONTENTS
};
// Invoked to determine max LUN
uint8_t tud_msc_get_maxlun_cb(void)
{
return 1; // single LUN
}
// Invoked when received SCSI_CMD_INQUIRY
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4])
{
(void) lun; // use same ID for both LUNs
const char vid[] = "TinyUSB";
const char pid[] = "Mass Storage";
const char rev[] = "1.0";
memcpy(vendor_id , vid, strlen(vid));
memcpy(product_id , pid, strlen(pid));
memcpy(product_rev, rev, strlen(rev));
}
// Invoked when received Test Unit Ready command.
// return true allowing host to read/write this LUN e.g SD card inserted
bool tud_msc_test_unit_ready_cb(uint8_t lun)
{
(void) lun;
return true; // Flash/RAM disks are always ready
}
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
// Application update block count and block size
void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size)
{
(void) lun;
*block_count = DISK_BLOCK_NUM;
*block_size = DISK_BLOCK_SIZE;
}
// Invoked when received Start Stop Unit command
// - Start = 0 : stopped power mode, if load_eject = 1 : unload disk storage
// - Start = 1 : active mode, if load_eject = 1 : load disk storage
bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject)
{
(void) lun;
(void) power_condition;
if ( load_eject )
{
if (start)
{
// load disk storage
}else
{
// unload disk storage
}
}
return true;
}
// Callback invoked when received READ10 command.
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize)
{
// out of ramdisk
if ( lba >= DISK_BLOCK_NUM ) return -1;
(void) lun;
uint8_t const* addr = msc_disk0[lba] + offset;
memcpy(buffer, addr, bufsize);
return (int32_t) bufsize;
}
bool tud_msc_is_writable_cb (uint8_t lun)
{
(void) lun;
// readonly
return false;
}
// Callback invoked when received WRITE10 command.
// Process data in buffer to disk's storage and return number of written bytes
int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize)
{
// out of ramdisk
if ( lba >= DISK_BLOCK_NUM ) return -1;
#if 0
uint8_t* addr = (lun ? msc_disk1[lba] : msc_disk0[lba]) + offset;
memcpy(addr, buffer, bufsize);
#else // readonly
(void) lun; (void) lba; (void) offset; (void) buffer;
#endif
return (int32_t) bufsize;
}
// Callback invoked when received an SCSI command not in built-in list below
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
// - READ10 and WRITE10 has their own callbacks
int32_t tud_msc_scsi_cb (uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize)
{
// read10 & write10 has their own callback and MUST not be handled here
void const* response = NULL;
int32_t resplen = 0;
// most scsi handled is input
bool in_xfer = true;
switch (scsi_cmd[0])
{
default:
// Set Sense = Invalid Command Operation
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
// negative means error -> tinyusb could stall and/or response with failed status
resplen = -1;
break;
}
// return resplen must not larger than bufsize
if ( resplen > bufsize ) resplen = bufsize;
if ( response && (resplen > 0) )
{
if(in_xfer)
{
memcpy(buffer, response, (size_t) resplen);
}else
{
// SCSI output
}
}
return resplen;
}
@@ -1 +0,0 @@
../../device-dashboard/net.c
@@ -1 +0,0 @@
../../device-dashboard/net.h
@@ -1,2 +0,0 @@
#pragma once
#define SIZEOF_ETH_HDR 14
@@ -1 +0,0 @@
../../device-dashboard/packed_fs.c
@@ -1,12 +0,0 @@
#pragma once
// Windows only supports RNDIS, and apparently doesn't like composite devices with two configurations.
// Mac only supports CDC-ECM, which we present as the second config in a dual configuration device
// Linux supports either RNDIS, CDC-ECM or CDC-NCM
#define CFG_TUD_ECM_RNDIS 1
#define CFG_TUD_MSC 1 // This enables mass storage
#define CFG_TUD_MSC_EP_BUFSIZE 512 // Also Add msc_disk.c and descritors
#define CFG_TUD_NCM 0
#define BOARD_DEVICE_RHPORT_NUM 0
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
@@ -1,271 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
// Modified by Cesanta Software
#include "tusb.h"
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
*
* Auto ProductID layout's Bitmap:
* [MSB] NET | VENDOR | MIDI | HID | MSC | CDC [LSB]
*/
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) | _PID_MAP(ECM_RNDIS, 5) | _PID_MAP(NCM, 5) )
// String Descriptor Index
enum
{
STRID_LANGID = 0,
STRID_MANUFACTURER,
STRID_PRODUCT,
STRID_SERIAL,
STRID_INTERFACE,
STRID_MAC
};
enum
{
ITF_NUM_CDC = 0,
ITF_NUM_CDC_DATA,
ITF_NUM_MSC,
ITF_NUM_TOTAL
};
enum
{
#if CFG_TUD_ECM_RNDIS
CONFIG_ID_RNDIS = 0,
#if DUAL_CONFIG
CONFIG_ID_ECM = 1,
#endif
#else
CONFIG_ID_NCM = 0,
#endif
CONFIG_ID_COUNT
};
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
// Use Interface Association Descriptor (IAD) device class
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = 0xCafe,
.idProduct = USB_PID,
.bcdDevice = 0x0101,
.iManufacturer = STRID_MANUFACTURER,
.iProduct = STRID_PRODUCT,
.iSerialNumber = STRID_SERIAL,
.bNumConfigurations = CONFIG_ID_COUNT // multiple configurations
};
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const * tud_descriptor_device_cb(void)
{
return (uint8_t const *) &desc_device;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
#define MAIN_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN + TUD_RNDIS_DESC_LEN)
#define ALT_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN + TUD_CDC_ECM_DESC_LEN)
#define NCM_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_MSC_DESC_LEN + TUD_CDC_NCM_DESC_LEN)
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In, 5 Bulk etc ...
#define EPNUM_NET_NOTIF 0x81
#define EPNUM_NET_OUT 0x02
#define EPNUM_NET_IN 0x82
#define EPNUM_MSC_OUT 0x05
#define EPNUM_MSC_IN 0x85
#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
// SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
#define EPNUM_NET_NOTIF 0x81
#define EPNUM_NET_OUT 0x02
#define EPNUM_NET_IN 0x83
#define EPNUM_MSC_OUT 0x04
#define EPNUM_MSC_IN 0x85
#else
#define EPNUM_NET_NOTIF 0x81
#define EPNUM_NET_OUT 0x02
#define EPNUM_NET_IN 0x82
#define EPNUM_MSC_OUT 0x03
#define EPNUM_MSC_IN 0x83
#endif
// Interface number, string index, EP Out & EP In address, EP size
# define MSCDESC TUD_MSC_DESCRIPTOR(ITF_NUM_MSC, 0, EPNUM_MSC_OUT, EPNUM_MSC_IN, 64)
#if CFG_TUD_ECM_RNDIS
static uint8_t const rndis_configuration[] =
{
// Config number (index+1), interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_RNDIS+1, ITF_NUM_TOTAL, 0, MAIN_CONFIG_TOTAL_LEN, 0, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_RNDIS_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, EPNUM_NET_NOTIF, 8, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE),
MSCDESC
};
#if DUAL_CONFIG
static uint8_t const ecm_configuration[] =
{
// Config number (index+1), interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_ECM+1, ITF_NUM_TOTAL, 0, ALT_CONFIG_TOTAL_LEN, 0, 100),
// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
TUD_CDC_ECM_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, STRID_MAC, EPNUM_NET_NOTIF, 64, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE, CFG_TUD_NET_MTU),
MSCDESC
};
#endif
#else
static uint8_t const ncm_configuration[] =
{
// Config number (index+1), interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_NCM+1, ITF_NUM_TOTAL, 0, NCM_CONFIG_TOTAL_LEN, 0, 100),
// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
TUD_CDC_NCM_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, STRID_MAC, EPNUM_NET_NOTIF, 64, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE, CFG_TUD_NET_MTU),
MSCDESC
};
#endif
// Configuration array: RNDIS and CDC-ECM
// - Windows only works with RNDIS
// - MacOS only works with CDC-ECM
// - Linux will work on both
static uint8_t const * const configuration_arr[2] =
{
#if CFG_TUD_ECM_RNDIS
[CONFIG_ID_RNDIS] = rndis_configuration
#if DUAL_CONFIG
, [CONFIG_ID_ECM ] = ecm_configuration
#endif
#else
[CONFIG_ID_NCM ] = ncm_configuration
#endif
};
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
return (index < CONFIG_ID_COUNT) ? configuration_arr[index] : NULL;
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
// array of pointer to string descriptors
static char const* string_desc_arr [] =
{
[STRID_LANGID] = (const char[]) { 0x09, 0x04 }, // supported language is English (0x0409)
[STRID_MANUFACTURER] = "TinyUSB", // Manufacturer
[STRID_PRODUCT] = "TinyUSB Device", // Product
[STRID_SERIAL] = "123456", // Serial
[STRID_INTERFACE] = "TinyUSB Network Interface" // Interface Description
// STRID_MAC index is handled separately
};
static uint16_t _desc_str[32];
// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
{
(void) langid;
unsigned int chr_count = 0;
if (STRID_LANGID == index)
{
memcpy(&_desc_str[1], string_desc_arr[STRID_LANGID], 2);
chr_count = 1;
}
else if (STRID_MAC == index)
{
// Convert MAC address into UTF-16
for (unsigned i=0; i<sizeof(tud_network_mac_address); i++)
{
_desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[i] >> 4) & 0xf];
_desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[i] >> 0) & 0xf];
}
}
else
{
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
const char* str = string_desc_arr[index];
// Cap at max char
chr_count = (uint8_t) strlen(str);
if ( chr_count > (TU_ARRAY_SIZE(_desc_str) - 1)) chr_count = TU_ARRAY_SIZE(_desc_str) - 1;
// Convert ASCII string into UTF-16
for (unsigned int i=0; i<chr_count; i++)
{
_desc_str[1+i] = str[i];
}
}
// first byte is length (including header), second byte is string type
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8 ) | (2*chr_count + 2));
return _desc_str;
}
@@ -1,26 +0,0 @@
cmake_minimum_required(VERSION 3.13)
include(pico-sdk/pico_sdk_init.cmake)
project(firmware)
pico_sdk_init()
add_executable(firmware
main.c
usb_descriptors.c
mongoose.c
net.c
pico-sdk/lib/tinyusb/lib/networking/rndis_reports.c)
target_include_directories(firmware PUBLIC
.
pico-sdk/lib/tinyusb/lib/networking)
target_link_libraries(firmware pico_stdlib pico_rand hardware_spi tinyusb_device)
pico_add_extra_outputs(firmware) # create map/bin/hex file etc.
pico_enable_stdio_usb(firmware 0) # Route stdio
pico_enable_stdio_uart(firmware 1) # to the UART
# Mongoose build flags in mongoose_config.h
# Example build options
@@ -1,20 +0,0 @@
RM = rm -rf
MKBUILD = test -d build || mkdir build
ifeq ($(OS),Windows_NT)
RM = cmd /C del /Q /F /S
MKBUILD = if not exist build mkdir build
endif
all example:
true
build: pico-sdk
$(MKBUILD)
cd build && cmake -G "Unix Makefiles" .. && make
pico-sdk:
git clone --depth 1 -b 1.4.0 https://github.com/raspberrypi/pico-sdk $@
cd $@ && git submodule update --init
clean:
$(RM) pico-sdk build
@@ -1,30 +0,0 @@
# Remote MQTT Device on an RP2040
Your headless Raspberry Pi Pico-based hardware can also be a remote gadget when you connect it to your computer via USB
For the USB specifics, see this related tutorial at https://mongoose.ws/tutorials/rp2040/pico-rndis-dashboard/
See this tutorial to control your device: https://mongoose.ws/tutorials/mqtt-dashboard/
For this to work, you need your computer to act as a router (gateway) and NAT for your device.
## Linux setup
Enable "masquerading"; the quick and simple options are:
``` bash
sudo iptables --flush
sudo iptables --table nat --flush
sudo iptables --delete-chain
sudo iptables --table nat --delete-chain
# Do masquerading
sudo iptables -t nat -A POSTROUTING -o yourifc -j MASQUERADE
# enable routing
sudo echo 1 > /proc/sys/net/ipv4/ip_forward
```
Where `yourifc` is the interface that is connected to your network
## MacOS setup
-11
View File
@@ -1,11 +0,0 @@
// Copyright (c) 2023 Cesanta Software Limited
// All rights reserved
#define LED PICO_DEFAULT_LED_PIN
static inline int gpio_read(uint16_t pin) {
return gpio_get_out_level(pin);
}
static inline void gpio_write(uint16_t pin, bool val) {
gpio_put(pin, val);
}
-94
View File
@@ -1,94 +0,0 @@
// Copyright (c) 2022 Cesanta Software Limited
// All rights reserved
#include "mongoose.h"
#include "net.h"
#include "pico/stdlib.h"
#include "tusb.h"
bool hal_gpio_read(int pin) {
return (pin >= 0 && pin <= 29) ? gpio_get_out_level((uint) pin) : false;
}
bool hal_gpio_write(int pin, bool val) {
if (pin >= 0 && pin <= 29) {
gpio_put((uint) pin, val);
return true;
} else {
return false;
}
}
int hal_led_pin(void) {
return PICO_DEFAULT_LED_PIN;
}
static struct mg_tcpip_if *s_ifp;
const uint8_t tud_network_mac_address[6] = {2, 2, 0x84, 0x6A, 0x96, 0};
bool tud_network_recv_cb(const uint8_t *buf, uint16_t len) {
mg_tcpip_qwrite((void *) buf, len, s_ifp);
// MG_INFO(("RECV %hu", len));
// mg_hexdump(buf, len);
tud_network_recv_renew();
return true;
}
void tud_network_init_cb(void) {
}
uint16_t tud_network_xmit_cb(uint8_t *dst, void *ref, uint16_t arg) {
// MG_INFO(("SEND %hu", arg));
memcpy(dst, ref, arg);
return arg;
}
static size_t usb_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) {
if (!tud_ready()) return 0;
while (!tud_network_can_xmit(len)) tud_task();
tud_network_xmit((void *) buf, len);
(void) ifp;
return len;
}
static bool usb_up(struct mg_tcpip_if *ifp) {
(void) ifp;
return tud_inited() && tud_ready() && tud_connected();
}
static void fn(struct mg_connection *c, int ev, void *ev_data, void *fn_dta) {
if (ev == MG_EV_HTTP_MSG) return mg_http_reply(c, 200, "", "ok\n");
}
int main(void) {
gpio_init(PICO_DEFAULT_LED_PIN);
gpio_set_dir(PICO_DEFAULT_LED_PIN, GPIO_OUT);
stdio_init_all();
struct mg_mgr mgr; // Initialise Mongoose event manager
mg_mgr_init(&mgr); // and attach it to the interface
struct mg_tcpip_driver driver = {.tx = usb_tx, .up = usb_up};
struct mg_tcpip_if mif = {.mac = {2, 0, 1, 2, 3, 0x77},
.ip = mg_htonl(MG_U32(192, 168, 3, 1)),
.mask = mg_htonl(MG_U32(255, 255, 255, 0)),
.enable_dhcp_server = true,
.enable_get_gateway = true,
.driver = &driver,
.recv_queue.size = 4096};
s_ifp = &mif;
mg_tcpip_init(&mgr, &mif);
tusb_init();
MG_INFO(("Initialising application..."));
web_init(&mgr);
MG_INFO(("Starting event loop"));
for (;;) {
mg_mgr_poll(&mgr, 0);
tud_task();
}
return 0;
}
@@ -1 +0,0 @@
../../../mongoose.c
@@ -1 +0,0 @@
../../../mongoose.h
@@ -1,6 +0,0 @@
#define MG_ARCH MG_ARCH_RP2040
#define MG_ENABLE_TCPIP 1
#define MG_ENABLE_TCPIP_DRIVER_INIT 0
#define MG_ENABLE_PACKED_FS 1
#define MG_ENABLE_POSIX_FS 0
-1
View File
@@ -1 +0,0 @@
../../mqtt-dashboard/device/net.c
-1
View File
@@ -1 +0,0 @@
../../mqtt-dashboard/device/net.h
@@ -1,2 +0,0 @@
#pragma once
#define SIZEOF_ETH_HDR 14
@@ -1,9 +0,0 @@
#pragma once
// Windows only supports RNDIS
// Mac only supports CDC-ECM
// Linux supports either RNDIS, CDC-ECM or CDC-NCM
#define CFG_TUD_ECM_RNDIS 1
#define BOARD_DEVICE_RHPORT_NUM 0
#define BOARD_DEVICE_RHPORT_SPEED OPT_MODE_FULL_SPEED
#define CFG_TUSB_RHPORT0_MODE (OPT_MODE_DEVICE | BOARD_DEVICE_RHPORT_SPEED)
@@ -1,248 +0,0 @@
/*
* The MIT License (MIT)
*
* Copyright (c) 2019 Ha Thach (tinyusb.org)
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*
*/
#include "tusb.h"
/* A combination of interfaces must have a unique product id, since PC will save device driver after the first plug.
* Same VID/PID with different interface e.g MSC (first), then CDC (later) will possibly cause system error on PC.
*
* Auto ProductID layout's Bitmap:
* [MSB] NET | VENDOR | MIDI | HID | MSC | CDC [LSB]
*/
#define _PID_MAP(itf, n) ( (CFG_TUD_##itf) << (n) )
#define USB_PID (0x4000 | _PID_MAP(CDC, 0) | _PID_MAP(MSC, 1) | _PID_MAP(HID, 2) | \
_PID_MAP(MIDI, 3) | _PID_MAP(VENDOR, 4) | _PID_MAP(ECM_RNDIS, 5) | _PID_MAP(NCM, 5) )
// String Descriptor Index
enum
{
STRID_LANGID = 0,
STRID_MANUFACTURER,
STRID_PRODUCT,
STRID_SERIAL,
STRID_INTERFACE,
STRID_MAC
};
enum
{
ITF_NUM_CDC = 0,
ITF_NUM_CDC_DATA,
ITF_NUM_TOTAL
};
enum
{
#if CFG_TUD_ECM_RNDIS
CONFIG_ID_RNDIS = 0,
CONFIG_ID_ECM = 1,
#else
CONFIG_ID_NCM = 0,
#endif
CONFIG_ID_COUNT
};
//--------------------------------------------------------------------+
// Device Descriptors
//--------------------------------------------------------------------+
tusb_desc_device_t const desc_device =
{
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
// Use Interface Association Descriptor (IAD) device class
.bDeviceClass = TUSB_CLASS_MISC,
.bDeviceSubClass = MISC_SUBCLASS_COMMON,
.bDeviceProtocol = MISC_PROTOCOL_IAD,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = 0xCafe,
.idProduct = USB_PID,
.bcdDevice = 0x0101,
.iManufacturer = STRID_MANUFACTURER,
.iProduct = STRID_PRODUCT,
.iSerialNumber = STRID_SERIAL,
.bNumConfigurations = CONFIG_ID_COUNT // multiple configurations
};
// Invoked when received GET DEVICE DESCRIPTOR
// Application return pointer to descriptor
uint8_t const * tud_descriptor_device_cb(void)
{
return (uint8_t const *) &desc_device;
}
//--------------------------------------------------------------------+
// Configuration Descriptor
//--------------------------------------------------------------------+
#define MAIN_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_RNDIS_DESC_LEN)
#define ALT_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_ECM_DESC_LEN)
#define NCM_CONFIG_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_CDC_NCM_DESC_LEN)
#if CFG_TUSB_MCU == OPT_MCU_LPC175X_6X || CFG_TUSB_MCU == OPT_MCU_LPC177X_8X || CFG_TUSB_MCU == OPT_MCU_LPC40XX
// LPC 17xx and 40xx endpoint type (bulk/interrupt/iso) are fixed by its number
// 0 control, 1 In, 2 Bulk, 3 Iso, 4 In etc ...
#define EPNUM_NET_NOTIF 0x81
#define EPNUM_NET_OUT 0x02
#define EPNUM_NET_IN 0x82
#elif CFG_TUSB_MCU == OPT_MCU_SAMG || CFG_TUSB_MCU == OPT_MCU_SAMX7X
// SAMG & SAME70 don't support a same endpoint number with different direction IN and OUT
// e.g EP1 OUT & EP1 IN cannot exist together
#define EPNUM_NET_NOTIF 0x81
#define EPNUM_NET_OUT 0x02
#define EPNUM_NET_IN 0x83
#else
#define EPNUM_NET_NOTIF 0x81
#define EPNUM_NET_OUT 0x02
#define EPNUM_NET_IN 0x82
#endif
#if CFG_TUD_ECM_RNDIS
static uint8_t const rndis_configuration[] =
{
// Config number (index+1), interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_RNDIS+1, ITF_NUM_TOTAL, 0, MAIN_CONFIG_TOTAL_LEN, 0, 100),
// Interface number, string index, EP notification address and size, EP data address (out, in) and size.
TUD_RNDIS_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, EPNUM_NET_NOTIF, 8, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE),
};
static uint8_t const ecm_configuration[] =
{
// Config number (index+1), interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_ECM+1, ITF_NUM_TOTAL, 0, ALT_CONFIG_TOTAL_LEN, 0, 100),
// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
TUD_CDC_ECM_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, STRID_MAC, EPNUM_NET_NOTIF, 64, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE, CFG_TUD_NET_MTU),
};
#else
static uint8_t const ncm_configuration[] =
{
// Config number (index+1), interface count, string index, total length, attribute, power in mA
TUD_CONFIG_DESCRIPTOR(CONFIG_ID_NCM+1, ITF_NUM_TOTAL, 0, NCM_CONFIG_TOTAL_LEN, 0, 100),
// Interface number, description string index, MAC address string index, EP notification address and size, EP data address (out, in), and size, max segment size.
TUD_CDC_NCM_DESCRIPTOR(ITF_NUM_CDC, STRID_INTERFACE, STRID_MAC, EPNUM_NET_NOTIF, 64, EPNUM_NET_OUT, EPNUM_NET_IN, CFG_TUD_NET_ENDPOINT_SIZE, CFG_TUD_NET_MTU),
};
#endif
// Configuration array: RNDIS and CDC-ECM
// - Windows only works with RNDIS
// - MacOS only works with CDC-ECM
// - Linux will work on both
static uint8_t const * const configuration_arr[2] =
{
#if CFG_TUD_ECM_RNDIS
[CONFIG_ID_RNDIS] = rndis_configuration,
[CONFIG_ID_ECM ] = ecm_configuration
#else
[CONFIG_ID_NCM ] = ncm_configuration
#endif
};
// Invoked when received GET CONFIGURATION DESCRIPTOR
// Application return pointer to descriptor
// Descriptor contents must exist long enough for transfer to complete
uint8_t const * tud_descriptor_configuration_cb(uint8_t index)
{
return (index < CONFIG_ID_COUNT) ? configuration_arr[index] : NULL;
}
//--------------------------------------------------------------------+
// String Descriptors
//--------------------------------------------------------------------+
// array of pointer to string descriptors
static char const* string_desc_arr [] =
{
[STRID_LANGID] = (const char[]) { 0x09, 0x04 }, // supported language is English (0x0409)
[STRID_MANUFACTURER] = "TinyUSB", // Manufacturer
[STRID_PRODUCT] = "TinyUSB Device", // Product
[STRID_SERIAL] = "123456", // Serial
[STRID_INTERFACE] = "TinyUSB Network Interface" // Interface Description
// STRID_MAC index is handled separately
};
static uint16_t _desc_str[32];
// Invoked when received GET STRING DESCRIPTOR request
// Application return pointer to descriptor, whose contents must exist long enough for transfer to complete
uint16_t const* tud_descriptor_string_cb(uint8_t index, uint16_t langid)
{
(void) langid;
unsigned int chr_count = 0;
if (STRID_LANGID == index)
{
memcpy(&_desc_str[1], string_desc_arr[STRID_LANGID], 2);
chr_count = 1;
}
else if (STRID_MAC == index)
{
// Convert MAC address into UTF-16
for (unsigned i=0; i<sizeof(tud_network_mac_address); i++)
{
_desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[i] >> 4) & 0xf];
_desc_str[1+chr_count++] = "0123456789ABCDEF"[(tud_network_mac_address[i] >> 0) & 0xf];
}
}
else
{
// Note: the 0xEE index string is a Microsoft OS 1.0 Descriptors.
// https://docs.microsoft.com/en-us/windows-hardware/drivers/usbcon/microsoft-defined-usb-descriptors
if ( !(index < sizeof(string_desc_arr)/sizeof(string_desc_arr[0])) ) return NULL;
const char* str = string_desc_arr[index];
// Cap at max char
chr_count = (uint8_t) strlen(str);
if ( chr_count > (TU_ARRAY_SIZE(_desc_str) - 1)) chr_count = TU_ARRAY_SIZE(_desc_str) - 1;
// Convert ASCII string into UTF-16
for (unsigned int i=0; i<chr_count; i++)
{
_desc_str[1+i] = str[i];
}
}
// first byte is length (including header), second byte is string type
_desc_str[0] = (uint16_t) ((TUSB_DESC_STRING << 8 ) | (2*chr_count + 2));
return _desc_str;
}
@@ -1,29 +0,0 @@
cmake_minimum_required(VERSION 3.13)
include(pico-sdk/pico_sdk_init.cmake)
project(firmware)
pico_sdk_init()
add_executable(firmware
driver_pico-w.c
main.c
mongoose.c
net.c
packed_fs.c
)
target_include_directories(firmware PUBLIC
.
)
target_link_libraries(firmware hardware_pio hardware_dma pico_stdlib pico_rand cyw43_driver_picow)
pico_add_extra_outputs(firmware) # create map/bin/hex file etc.
pico_enable_stdio_usb(firmware 1) # Route stdio
pico_enable_stdio_uart(firmware 0) # to USB
# Mongoose build flags in mongoose_config.h
# Example build options
add_definitions(-DHTTP_URL="http://0.0.0.0/")
@@ -1,22 +0,0 @@
RM = rm -rf
MKBUILD = rm -rf build && mkdir -p build # test -d build || mkdir build
ifeq ($(OS),Windows_NT)
RM = cmd /C del /Q /F /S
MKBUILD = if not exist build mkdir build
endif
all example:
true
build: pico-sdk build/firmware.uf2
build/firmware.uf2:
$(MKBUILD)
cd build && cmake -G "Unix Makefiles" .. && make
pico-sdk:
git clone --depth 1 -b 1.5.1 https://github.com/raspberrypi/pico-sdk $@
cd $@ && git submodule update --init
clean:
$(RM) pico-sdk build
@@ -1,4 +0,0 @@
# Mongoose on PICO W
@@ -1,164 +0,0 @@
/*
* Copyright (c) 2022 Raspberry Pi (Trading) Ltd.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
// This header is included by cyw43_driver to setup its environment
// THIS FILE HAS BEEN EDITED, ORIGINAL FILE IN PICO-SDK
#ifndef _CYW43_CONFIGPORT_H
#define _CYW43_CONFIGPORT_H
#include "boards/pico_w.h"
#include "hardware/gpio.h"
#include "pico/error.h"
#include "pico/time.h"
#ifdef __cplusplus
extern "C" {
#endif
// Use our own TCP/IP stack
#define CYW43_LWIP 0
#ifndef CYW43_HOST_NAME
#define CYW43_HOST_NAME "Mongoose"
#endif
#ifndef CYW43_GPIO
#define CYW43_GPIO 1
#endif
#ifndef CYW43_LOGIC_DEBUG
#define CYW43_LOGIC_DEBUG 0
#endif
#ifndef CYW43_USE_OTP_MAC
#define CYW43_USE_OTP_MAC 1
#endif
#ifndef CYW43_NO_NETUTILS
#define CYW43_NO_NETUTILS 1
#endif
#ifndef CYW43_IOCTL_TIMEOUT_US
#define CYW43_IOCTL_TIMEOUT_US 1000000
#endif
#ifndef CYW43_USE_STATS
#define CYW43_USE_STATS 0
#endif
// todo should this be user settable?
#ifndef CYW43_HAL_MAC_WLAN0
#define CYW43_HAL_MAC_WLAN0 0
#endif
#ifndef STATIC
#define STATIC static
#endif
#ifndef CYW43_USE_SPI
#define CYW43_USE_SPI 1
#endif
#ifndef CYW43_SPI_PIO
#define CYW43_SPI_PIO 1
#endif
#ifndef CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE
#if CYW43_ENABLE_BLUETOOTH
#define CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE "wb43439A0_7_95_49_00_combined.h"
#else
#define CYW43_CHIPSET_FIRMWARE_INCLUDE_FILE "w43439A0_7_95_49_00_combined.h"
#endif
#endif
#ifndef CYW43_WIFI_NVRAM_INCLUDE_FILE
#define CYW43_WIFI_NVRAM_INCLUDE_FILE "wifi_nvram_43439.h"
#endif
// Note, these are negated, because cyw43_driver negates them before returning!
#define CYW43_EPERM (-PICO_ERROR_NOT_PERMITTED) // Operation not permitted
#define CYW43_EIO (-PICO_ERROR_IO) // I/O error
#define CYW43_EINVAL (-PICO_ERROR_INVALID_ARG) // Invalid argument
#define CYW43_ETIMEDOUT (-PICO_ERROR_TIMEOUT) // Connection timed out
#define CYW43_NUM_GPIOS CYW43_WL_GPIO_COUNT
#define cyw43_hal_pin_obj_t uint
// get the number of elements in a fixed-size array
#define CYW43_ARRAY_SIZE(a) count_of(a)
static inline uint32_t cyw43_hal_ticks_us(void) {
return time_us_32();
}
static inline uint32_t cyw43_hal_ticks_ms(void) {
return to_ms_since_boot(get_absolute_time());
}
static inline int cyw43_hal_pin_read(cyw43_hal_pin_obj_t pin) {
return gpio_get(pin);
}
static inline void cyw43_hal_pin_low(cyw43_hal_pin_obj_t pin) {
gpio_clr_mask(1 << pin);
}
static inline void cyw43_hal_pin_high(cyw43_hal_pin_obj_t pin) {
gpio_set_mask(1 << pin);
}
#define CYW43_HAL_PIN_MODE_INPUT (GPIO_IN)
#define CYW43_HAL_PIN_MODE_OUTPUT (GPIO_OUT)
#define CYW43_HAL_PIN_PULL_NONE (0)
#define CYW43_HAL_PIN_PULL_UP (1)
#define CYW43_HAL_PIN_PULL_DOWN (2)
static inline void cyw43_hal_pin_config(cyw43_hal_pin_obj_t pin, uint32_t mode, uint32_t pull, __unused uint32_t alt) {
assert((mode == CYW43_HAL_PIN_MODE_INPUT || mode == CYW43_HAL_PIN_MODE_OUTPUT) && alt == 0);
gpio_set_dir(pin, mode);
gpio_set_pulls(pin, pull == CYW43_HAL_PIN_PULL_UP, pull == CYW43_HAL_PIN_PULL_DOWN);
}
void cyw43_hal_get_mac(int idx, uint8_t buf[6]);
void cyw43_hal_generate_laa_mac(int idx, uint8_t buf[6]);
// documentation is king
#define CYW43_THREAD_ENTER
#define CYW43_THREAD_EXIT
#define CYW43_THREAD_LOCK_CHECK
// ??? and the ';' at the end is needed
#define CYW43_SDPCM_SEND_COMMON_WAIT (void) 0;
#define CYW43_DO_IOCTL_WAIT (void) 0;
#define cyw43_delay_ms sleep_ms
#define cyw43_delay_us sleep_us
static inline void cyw43_schedule_internal_poll_dispatch(void (*func)(void)){
(void)func; // do nothing, we'll call it anyway
}
#define CYW43_POST_POLL_HOOK
// Allow malloc and free to be changed
#ifndef cyw43_malloc
#define cyw43_malloc malloc
#endif
#ifndef cyw43_free
#define cyw43_free free
#endif
#ifdef __cplusplus
}
#endif
#endif
@@ -1,79 +0,0 @@
// Copyright (c) 2024 Cesanta Software Limited
// All rights reserved
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include "pico/stdlib.h"
#include "pico/unique_id.h"
#include "cyw43.h"
#include "cyw43_country.h"
#include "mongoose.h"
#include "driver_pico-w.h"
static struct mg_tcpip_if *s_ifp;
static bool mg_tcpip_driver_pico_w_init(struct mg_tcpip_if *ifp) {
struct mg_tcpip_driver_pico_w_data *d = (struct mg_tcpip_driver_pico_w_data *) ifp->driver_data;
s_ifp = ifp;
// initialize WiFi chip and connect to network
cyw43_init(&cyw43_state);
cyw43_wifi_set_up(&cyw43_state, CYW43_ITF_STA, true, CYW43_COUNTRY_WORLDWIDE);
cyw43_wifi_join(&cyw43_state, strlen(d->ssid), d->ssid, strlen(d->pass), d->pass, CYW43_AUTH_WPA2_AES_PSK, NULL, CYW43_ITF_STA);
cyw43_wifi_get_mac(&cyw43_state, CYW43_ITF_STA, ifp->mac);
return true;
}
static size_t mg_tcpip_driver_pico_w_tx(const void *buf, size_t len,
struct mg_tcpip_if *ifp) {
return cyw43_send_ethernet(&cyw43_state, CYW43_ITF_STA, len, buf, false) ? 0 : len;
(void) ifp;
}
static bool mg_tcpip_driver_pico_w_up(struct mg_tcpip_if *ifp) {
return cyw43_wifi_link_status(&cyw43_state, CYW43_ITF_STA) == CYW43_LINK_JOIN ? 1 : 0;
}
void driver_pico_w_poll(void) {
cyw43_poll();
}
struct mg_tcpip_driver mg_tcpip_driver_pico_w = {
mg_tcpip_driver_pico_w_init,
mg_tcpip_driver_pico_w_tx,
NULL,
mg_tcpip_driver_pico_w_up,
};
void cyw43_cb_tcpip_init(cyw43_t *self, int itf) {}
void cyw43_cb_tcpip_deinit(cyw43_t *self, int itf) {}
void cyw43_cb_tcpip_set_link_up(cyw43_t *self, int itf) {}
void cyw43_cb_tcpip_set_link_down(cyw43_t *self, int itf) {}
// Called once per outstanding frame during a call to cyw43_poll
void cyw43_cb_process_ethernet(void *cb_data, int itf, size_t len, const uint8_t *buf) {
if (itf != CYW43_ITF_STA) return;
mg_tcpip_qwrite((void *) buf, len, s_ifp);
(void) cb_data;
}
// Return mac address
void cyw43_hal_get_mac(__unused int idx, uint8_t buf[6]) {
memcpy(buf, cyw43_state.mac, 6);
}
// Generate a mac address if one is not set in otp
void cyw43_hal_generate_laa_mac(__unused int idx, uint8_t buf[6]) {
pico_unique_board_id_t board_id;
MG_DEBUG(("No MAC in cyw43 OTP, generated from board id"));
pico_get_unique_board_id(&board_id);
memcpy(buf, &board_id.id[2], 6);
buf[0] &= (uint8_t)~0x1; // unicast
buf[0] |= 0x2; // locally administered
}
// there's life beyond lwIP
void pbuf_copy_partial(void){(void)0;}
@@ -1,10 +0,0 @@
#pragma once
struct mg_tcpip_driver_pico_w_data {
char *ssid;
char *pass;
};
extern struct mg_tcpip_driver mg_tcpip_driver_pico_w;
void driver_pico_w_poll(void);
-52
View File
@@ -1,52 +0,0 @@
// Copyright (c) 2024 Cesanta Software Limited
// All rights reserved
#include "pico/stdlib.h"
#include "mongoose.h"
#include "net.h"
#include "driver_pico-w.h"
#define WIFI_SSID "yourWiFiSSID"
#define WIFI_PASS "yourWiFiPassword"
int main(void) {
// initialize stdio
stdio_init_all();
struct mg_mgr mgr; // Initialise Mongoose event manager
mg_mgr_init(&mgr); // and attach it to the interface
mg_log_set(MG_LL_DEBUG); // Set log level
// Initialise WiFi creds
struct mg_tcpip_driver_pico_w_data driver_data = {
.ssid = WIFI_SSID,
.pass = WIFI_PASS
};
// Initialise Mongoose network stack
// Either set use_dhcp or enter a static config.
// For static configuration, specify IP/mask/GW in network byte order
struct mg_tcpip_if mif = {
.ip = 0,
.driver = &mg_tcpip_driver_pico_w,
.driver_data = &driver_data,
.recv_queue.size = 8192
};
mg_tcpip_init(&mgr, &mif);
MG_INFO(("Init done, starting main loop"));
MG_INFO(("Initialising application..."));
web_init(&mgr);
MG_INFO(("Starting event loop"));
for (;;) {
driver_pico_w_poll();
mg_mgr_poll(&mgr, 0);
}
return 0;
}
@@ -1 +0,0 @@
../../../mongoose.c
@@ -1 +0,0 @@
../../../mongoose.h
@@ -1,5 +0,0 @@
#define MG_ARCH MG_ARCH_RP2040
#define MG_ENABLE_TCPIP 1
#define MG_ENABLE_TCPIP_DRIVER_INIT 0
#define MG_ENABLE_PACKED_FS 1
-1
View File
@@ -1 +0,0 @@
../../device-dashboard/net.c
-1
View File
@@ -1 +0,0 @@
../../device-dashboard/net.h
@@ -1 +0,0 @@
../../device-dashboard/packed_fs.c
@@ -1,73 +0,0 @@
# This is a copy of <PICO_SDK_PATH>/external/pico_sdk_import.cmake
# This can be dropped into an external project to help locate this SDK
# It should be include()ed prior to project()
if (DEFINED ENV{PICO_SDK_PATH} AND (NOT PICO_SDK_PATH))
set(PICO_SDK_PATH $ENV{PICO_SDK_PATH})
message("Using PICO_SDK_PATH from environment ('${PICO_SDK_PATH}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT} AND (NOT PICO_SDK_FETCH_FROM_GIT))
set(PICO_SDK_FETCH_FROM_GIT $ENV{PICO_SDK_FETCH_FROM_GIT})
message("Using PICO_SDK_FETCH_FROM_GIT from environment ('${PICO_SDK_FETCH_FROM_GIT}')")
endif ()
if (DEFINED ENV{PICO_SDK_FETCH_FROM_GIT_PATH} AND (NOT PICO_SDK_FETCH_FROM_GIT_PATH))
set(PICO_SDK_FETCH_FROM_GIT_PATH $ENV{PICO_SDK_FETCH_FROM_GIT_PATH})
message("Using PICO_SDK_FETCH_FROM_GIT_PATH from environment ('${PICO_SDK_FETCH_FROM_GIT_PATH}')")
endif ()
set(PICO_SDK_PATH "${PICO_SDK_PATH}" CACHE PATH "Path to the Raspberry Pi Pico SDK")
set(PICO_SDK_FETCH_FROM_GIT "${PICO_SDK_FETCH_FROM_GIT}" CACHE BOOL "Set to ON to fetch copy of SDK from git if not otherwise locatable")
set(PICO_SDK_FETCH_FROM_GIT_PATH "${PICO_SDK_FETCH_FROM_GIT_PATH}" CACHE FILEPATH "location to download SDK")
if (NOT PICO_SDK_PATH)
if (PICO_SDK_FETCH_FROM_GIT)
include(FetchContent)
set(FETCHCONTENT_BASE_DIR_SAVE ${FETCHCONTENT_BASE_DIR})
if (PICO_SDK_FETCH_FROM_GIT_PATH)
get_filename_component(FETCHCONTENT_BASE_DIR "${PICO_SDK_FETCH_FROM_GIT_PATH}" REALPATH BASE_DIR "${CMAKE_SOURCE_DIR}")
endif ()
# GIT_SUBMODULES_RECURSE was added in 3.17
if (${CMAKE_VERSION} VERSION_GREATER_EQUAL "3.17.0")
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG master
GIT_SUBMODULES_RECURSE FALSE
)
else ()
FetchContent_Declare(
pico_sdk
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk
GIT_TAG master
)
endif ()
if (NOT pico_sdk)
message("Downloading Raspberry Pi Pico SDK")
FetchContent_Populate(pico_sdk)
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
endif ()
set(FETCHCONTENT_BASE_DIR ${FETCHCONTENT_BASE_DIR_SAVE})
else ()
message(FATAL_ERROR
"SDK location was not specified. Please set PICO_SDK_PATH or set PICO_SDK_FETCH_FROM_GIT to on to fetch from git."
)
endif ()
endif ()
get_filename_component(PICO_SDK_PATH "${PICO_SDK_PATH}" REALPATH BASE_DIR "${CMAKE_BINARY_DIR}")
if (NOT EXISTS ${PICO_SDK_PATH})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' not found")
endif ()
set(PICO_SDK_INIT_CMAKE_FILE ${PICO_SDK_PATH}/pico_sdk_init.cmake)
if (NOT EXISTS ${PICO_SDK_INIT_CMAKE_FILE})
message(FATAL_ERROR "Directory '${PICO_SDK_PATH}' does not appear to contain the Raspberry Pi Pico SDK")
endif ()
set(PICO_SDK_PATH ${PICO_SDK_PATH} CACHE PATH "Path to the Raspberry Pi Pico SDK" FORCE)
include(${PICO_SDK_INIT_CMAKE_FILE})
-13
View File
@@ -1,13 +0,0 @@
NAME = raspberry-pi-pico-w
$(NAME):
git clone --depth 1 https://github.com/mongoose-examples/$(NAME)
build: | $(NAME)
cp ./../../../mongoose.[ch] $(NAME)
cp ./../../device-dashboard/packed_fs.c $(NAME)
cp ./../../device-dashboard/net.[ch] $(NAME)
make -C $(NAME) build
clean:
rm -rf $(NAME)
-1
View File
@@ -1 +0,0 @@
See detailed tutorial at https://mongoose.ws/tutorials/rp2040/pico-w/
-19
View File
@@ -1,19 +0,0 @@
cmake_minimum_required(VERSION 3.13)
include(pico-sdk/pico_sdk_init.cmake)
project(firmware)
pico_sdk_init()
add_executable(firmware main.c mongoose.c net.c packed_fs.c)
target_include_directories(firmware PUBLIC .)
target_link_libraries(firmware pico_stdlib hardware_spi pico_rand)
pico_add_extra_outputs(firmware) # create map/bin/hex file etc.
pico_enable_stdio_usb(firmware 0) # Route stdio
pico_enable_stdio_uart(firmware 1) # to the UART, for remote testing
# Mongoose build flags in mongoose_config.h
# Example build options
add_definitions(-DHTTP_URL="http://0.0.0.0/")
add_definitions(-DHTTPS_URL="https://0.0.0.0/")
-34
View File
@@ -1,34 +0,0 @@
RM = rm -rf
MKBUILD = test -d build || mkdir build
ifeq ($(OS),Windows_NT)
RM = cmd /C del /Q /F /S
MKBUILD = if not exist build mkdir build
endif
.PHONY: build
all example:
true
build build/firmware.uf2: pico-sdk main.c net.c
$(MKBUILD)
cd build && cmake -G "Unix Makefiles" .. && make
pico-sdk:
git clone --depth 1 -b 1.5.0 https://github.com/raspberrypi/pico-sdk $@
cd $@ && git submodule update --init
flash: build/firmware.uf2
picotool load $< -f
# Automated remote test. Requires env variable VCON_API_KEY set. See https://vcon.io/automated-firmware-tests/
DEVICE_URL ?= https://dash.vcon.io/api/v3/devices/3
update: build/firmware.uf2
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/ota?uf2=1 --data-binary @$<
test: update
curl --fail-with-body -su :$(VCON_API_KEY) $(DEVICE_URL)/tx?t=5 | tee /tmp/output.txt
grep 'READY, IP:' /tmp/output.txt # Check for network init
# grep 'MQTT connected' /tmp/output.txt # Check for MQTT connection success
clean:
$(RM) pico-sdk build
-3
View File
@@ -1,3 +0,0 @@
# RP2040 + W5500 Ethernet chip
- See detailed tutorial (including hardware connections) at https://mongoose.ws/tutorials/rp2040/pico-w5500/
-103
View File
@@ -1,103 +0,0 @@
// Copyright (c) 2023 Cesanta Software Limited
// All rights reserved
#include <stdio.h>
#include <string.h>
#include "hardware/spi.h"
#include "pico/rand.h"
#include "pico/stdlib.h"
#include "pico/unique_id.h"
#include "mongoose.h"
#include "net.h"
enum { BLINK_PERIOD_MS = 1000 };
enum { LED = 25, SPI_CS = 17, SPI_CLK = 18, SPI_TX = 19, SPI_RX = 16 }; // Pins
static void spi_begin(void *spi) {
gpio_put(SPI_CS, 0);
}
static void spi_end(void *spi) {
gpio_put(SPI_CS, 1);
}
static uint8_t spi_txn(void *spi, uint8_t byte) {
uint8_t result = 0;
spi_write_read_blocking(spi0, &byte, &result, 1);
return result;
}
bool mg_random(void *buf, size_t len) {
for (size_t n = 0; n < len; n += sizeof(uint32_t)) {
uint32_t r = get_rand_32();
memcpy((char *) buf + n, &r, n + sizeof(r) > len ? len - n : sizeof(r));
}
return true;
}
static void timer_fn(void *arg) {
gpio_put(PICO_DEFAULT_LED_PIN,
!gpio_get_out_level(PICO_DEFAULT_LED_PIN)); // Blink LED
struct mg_tcpip_if *ifp = arg; // And show
const char *names[] = {"down", "up", "req", "ready"}; // network stats
MG_INFO(("Ethernet: %s, IP: %M, rx:%u, tx:%u, dr:%u, er:%u",
names[ifp->state], mg_print_ip4, &ifp->ip, ifp->nrecv, ifp->nsent,
ifp->ndrop, ifp->nerr));
}
static void eth_spi_init(void) {
// Init SPI pins
spi_init(spi0, 500 * 1000);
gpio_set_function(SPI_RX, GPIO_FUNC_SPI); // MISO
gpio_set_function(SPI_TX, GPIO_FUNC_SPI); // MOSI
gpio_set_function(SPI_CLK, GPIO_FUNC_SPI); // CLK
gpio_init(SPI_CS); // CS
gpio_set_dir(SPI_CS, GPIO_OUT); // Set CS to output
gpio_put(SPI_CS, 1); // And drive CS high (inactive)
}
// Helper macro for MAC generation
#define GENERATE_LOCALLY_ADMINISTERED_MAC(id) \
{ 2, id[3], id[4], id[5], id[6], id[7] }
int main(void) {
stdio_init_all();
gpio_init(LED); // Setup board LED
gpio_set_dir(LED, GPIO_OUT);
eth_spi_init(); // Initialise SPI pins
MG_INFO(("Starting ..."));
pico_unique_board_id_t board_id;
pico_get_unique_board_id(&board_id);
uint8_t *id = board_id.id;
struct mg_mgr mgr; // Initialise
mg_mgr_init(&mgr); // Mongoose event manager
mg_log_set(MG_LL_DEBUG); // Set log level
// Initialise Mongoose network stack
struct mg_tcpip_spi spi = {NULL, spi_begin, spi_end, spi_txn};
struct mg_tcpip_if mif = {.mac = GENERATE_LOCALLY_ADMINISTERED_MAC(id),
// Uncomment below for static configuration:
// .ip = mg_htonl(MG_U32(192, 168, 0, 223)),
// .mask = mg_htonl(MG_U32(255, 255, 255, 0)),
// .gw = mg_htonl(MG_U32(192, 168, 0, 1)),
.driver = &mg_tcpip_driver_w5500,
.driver_data = &spi};
mg_tcpip_init(&mgr, &mif);
mg_timer_add(&mgr, BLINK_PERIOD_MS, MG_TIMER_REPEAT, timer_fn, &mif);
MG_INFO(("MAC: %M. Waiting for IP...", mg_print_mac, mif.mac));
while (mif.state != MG_TCPIP_STATE_READY) {
mg_mgr_poll(&mgr, 0);
}
MG_INFO(("Initialising application..."));
web_init(&mgr);
MG_INFO(("Starting event loop"));
for (;;) {
mg_mgr_poll(&mgr, 1);
}
return 0;
}
-1
View File
@@ -1 +0,0 @@
../../../mongoose.c
-1
View File
@@ -1 +0,0 @@
../../../mongoose.h
@@ -1,8 +0,0 @@
#define MG_ARCH MG_ARCH_RP2040
#define MG_ENABLE_TCPIP 1
#define MG_ENABLE_TCPIP_DRIVER_INIT 0
#define MG_ENABLE_DRIVER_W5500 1
#define MG_ENABLE_CUSTOM_RANDOM 1
#define MG_ENABLE_PACKED_FS 1
#define MG_ENABLE_POSIX_FS 0
-1
View File
@@ -1 +0,0 @@
../../device-dashboard/net.c
-1
View File
@@ -1 +0,0 @@
../../device-dashboard/net.h
-1
View File
@@ -1 +0,0 @@
../../device-dashboard/packed_fs.c