Merge pull request #947 from pimoroni/test/network-ppp

PPP-enabled Pico build.
main
Philip Howard 2024-10-31 12:19:50 +00:00 zatwierdzone przez GitHub
commit 1495805d2b
Nie znaleziono w bazie danych klucza dla tego podpisu
ID klucza GPG: B5690EEEBB952194
13 zmienionych plików z 327 dodań i 43 usunięć

Wyświetl plik

@ -22,6 +22,8 @@ jobs:
board: RPI_PICO
- name: pico_usb
board: RPI_PICO_USB
- name: pico_ppp
board: RPI_PICO_PPP
- name: picow
board: RPI_PICO_W
- name: tiny2040_8mb

Wyświetl plik

@ -0,0 +1,20 @@
{
"deploy": [
"../deploy.md"
],
"docs": "",
"features": [
"Breadboard friendly",
"Castellated Pads",
"Micro USB"
],
"id": "rp2-pico",
"images": [
"rp2-pico.jpg"
],
"mcu": "rp2040",
"product": "Pico",
"thumbnail": "",
"url": "https://www.raspberrypi.com/products/raspberry-pi-pico/",
"vendor": "Raspberry Pi"
}

Wyświetl plik

@ -0,0 +1,7 @@
include("$(PORT_DIR)/boards/manifest.py")
require("bundle-networking")
include("../manifest_pico.py")
freeze("../../modules_py", "lte.py")

Wyświetl plik

@ -0,0 +1,9 @@
# cmake file for Raspberry Pi Pico
set(PICO_BOARD "pico")
set(MICROPY_PY_LWIP ON)
# Board specific version of the frozen manifest
set(MICROPY_FROZEN_MANIFEST ${MICROPY_BOARD_DIR}/manifest.py)
set(MICROPY_C_HEAP_SIZE 4096)

Wyświetl plik

@ -0,0 +1,16 @@
// Board and hardware specific configuration
#define MICROPY_HW_BOARD_NAME "Raspberry Pi Pico"
#define MICROPY_HW_FLASH_STORAGE_BYTES (1024 * 1024)
// Enable networking.
#define MICROPY_PY_NETWORK 1
#define MICROPY_PY_NETWORK_HOSTNAME_DEFAULT "Pico"
#define MICROPY_PY_NETWORK_PPP_LWIP 1
#define MICROPY_HW_NIC_PPP { MP_ROM_QSTR(MP_QSTR_PINT), MP_ROM_PTR(&mp_network_ppp_lwip_type) },
#define MICROPY_BOARD_NETWORK_INTERFACES \
MICROPY_HW_NIC_PPP
#define MICROPY_PY_SOCKET_EXTENDED_STATE 1

Wyświetl plik

@ -0,0 +1,28 @@
GP0,GPIO0
GP1,GPIO1
GP2,GPIO2
GP3,GPIO3
GP4,GPIO4
GP5,GPIO5
GP6,GPIO6
GP7,GPIO7
GP8,GPIO8
GP9,GPIO9
GP10,GPIO10
GP11,GPIO11
GP12,GPIO12
GP13,GPIO13
GP14,GPIO14
GP15,GPIO15
GP16,GPIO16
GP17,GPIO17
GP18,GPIO18
GP19,GPIO19
GP20,GPIO20
GP21,GPIO21
GP22,GPIO22
GP25,GPIO25
GP26,GPIO26
GP27,GPIO27
GP28,GPIO28
LED,GPIO25
1 GP0 GPIO0
2 GP1 GPIO1
3 GP2 GPIO2
4 GP3 GPIO3
5 GP4 GPIO4
6 GP5 GPIO5
7 GP6 GPIO6
8 GP7 GPIO7
9 GP8 GPIO8
10 GP9 GPIO9
11 GP10 GPIO10
12 GP11 GPIO11
13 GP12 GPIO12
14 GP13 GPIO13
15 GP14 GPIO14
16 GP15 GPIO15
17 GP16 GPIO16
18 GP17 GPIO17
19 GP18 GPIO18
20 GP19 GPIO19
21 GP20 GPIO20
22 GP21 GPIO21
23 GP22 GPIO22
24 GP25 GPIO25
25 GP26 GPIO26
26 GP27 GPIO27
27 GP28 GPIO28
28 LED GPIO25

Wyświetl plik

@ -31,6 +31,9 @@ include(wakeup/micropython)
# Configure wakeup for Enviro
target_compile_definitions(usermod_wakeup INTERFACE
-DWAKEUP_HAS_RTC=1
-DWAKEUP_PIN_MASK=0b01000100
-DWAKEUP_PIN_DIR=0b01000100
-DWAKEUP_PIN_VALUE=0b01000100
)
# LEDs & Matrices

Wyświetl plik

@ -33,6 +33,9 @@ include(wakeup/micropython)
target_compile_definitions(usermod_wakeup INTERFACE
-DWAKEUP_HAS_RTC=1
-DWAKEUP_HAS_SHIFT_REGISTER=1
-DWAKEUP_PIN_MASK=0b01000100
-DWAKEUP_PIN_DIR=0b01000100
-DWAKEUP_PIN_VALUE=0b01000100
)
# LEDs & Matrices

Wyświetl plik

@ -0,0 +1,16 @@
include_directories(${CMAKE_CURRENT_LIST_DIR}/../../)
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../")
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_LIST_DIR}/../../")
set(CMAKE_C_STANDARD 11)
set(CMAKE_CXX_STANDARD 17)
include(micropython-common)
# C++ Magic Memory
include(cppmem/micropython)
# Disable build-busting C++ exceptions
include(micropython-disable-exceptions)

Wyświetl plik

@ -5,7 +5,6 @@ add_library(usermod_${MOD_NAME} INTERFACE)
target_sources(usermod_${MOD_NAME} INTERFACE
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.c
${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.cpp
#${CMAKE_CURRENT_LIST_DIR}/${MOD_NAME}.S
)
target_include_directories(usermod_${MOD_NAME} INTERFACE

Wyświetl plik

@ -1,36 +0,0 @@
.syntax unified
.cpu cortex-m0plus
.thumb
#include "pico/asm_helper.S"
// This macro tells the pico runtime to call __wakeup_gpio_latch very early in boot
__pre_init __wakeup_gpio_latch, 00000
.section .data.wakeup_gpio_latch
.global wakeup_gpio_state
.align 4
wakeup_gpio_state:
.word 0x00000000
.section .text
.thumb_func
__wakeup_gpio_latch:
// Read GPIO state for front buttons and store
movs r3, 0xd0 // Load 0xd0 into r3
lsls r3, r3, 24 // Shift left 24 to get 0xd0000000
ldr r1, [r3, 4] // Load GPIO state (0xd0000004) into r1
ldr r2, =wakeup_gpio_state // Load output var addr into r2
str r1, [r2] // Store r1 to r2
// Enable 3v3 pin on the badger
ldr r1, =0x40014054 // GPIO control register 10
movs r2, 5 // SIO function
str r2, [r1] // Set Enable 3v3 to SIO // https://github.com/raspberrypi/pico-sdk/blob/2e6142b15b8a75c1227dd3edbe839193b2bf9041/src/rp2_common/hardware_gpio/include/hardware/gpio.h#L96
str r2, [r1, 120] // Also set LED (25) to SIO
ldr r2, =0x02000400 // Pins 25 and 10
str r2, [r3, 36] // Enable pins out
str r2, [r3, 20] // Set pins high
bx lr // Return

Wyświetl plik

@ -1,18 +1,30 @@
#include "hardware/gpio.h"
#include "wakeup.config.hpp"
extern uint32_t runtime_wakeup_gpio_state;
namespace {
struct Wakeup {
public:
uint8_t shift_register_state = 0b0;
uint32_t gpio_state = 0;
Wakeup() {
// Assert wakeup pins (indicator LEDs, VSYS hold etc)
//gpio_init_mask(WAKEUP_PIN_MASK);
//gpio_set_dir_masked(WAKEUP_PIN_MASK, WAKEUP_PIN_DIR);
//gpio_put_masked(WAKEUP_PIN_MASK, WAKEUP_PIN_VALUE);
gpio_init_mask(WAKEUP_PIN_MASK);
gpio_set_dir_masked(WAKEUP_PIN_MASK, WAKEUP_PIN_DIR);
gpio_put_masked(WAKEUP_PIN_MASK, WAKEUP_PIN_VALUE);
// Init all GPIOS not specified in the wakeup mask
#if PICO_RP2350
gpio_init_mask(~WAKEUP_PIN_MASK);
gpio_set_dir_in_masked(~WAKEUP_PIN_MASK);
#endif
gpio_state = gpio_get_all();
sleep_ms(5);
gpio_state |= gpio_get_all();
#if PICO_RP2350
gpio_init_mask(~WAKEUP_PIN_MASK);
#endif
#if WAKEUP_HAS_RTC==1
// Set up RTC I2C pins and send reset command
@ -59,11 +71,11 @@ extern "C" {
#include "wakeup.h"
mp_obj_t Wakeup_get_gpio_state() {
return mp_obj_new_int(runtime_wakeup_gpio_state);
return mp_obj_new_int(wakeup.gpio_state);
}
mp_obj_t Wakeup_reset_gpio_state() {
runtime_wakeup_gpio_state = 0;
wakeup.gpio_state = 0;
return mp_const_none;
}

Wyświetl plik

@ -0,0 +1,205 @@
import time
from machine import UART, Pin
from network import PPP
from micropython import const
DEFAULT_PIN_RST = 35
DEFAULT_PIN_NETLIGHT = 34
DEFAULT_PIN_RX = 33
DEFAULT_PIN_TX = 32
DEFAULT_UART_ID = 0
DEFAULT_UART_TIMEOUT = const(1)
DEFAULT_UART_TIMEOUT_CHAR = const(1)
DEFAULT_UART_RXBUF = const(1024)
DEFAULT_UART_STARTUP_BAUD = const(115200)
DEFAULT_UART_BAUD = const(460800)
class CellularError(Exception):
def __init__(self, message=None):
self.message = "CellularError: " + message
class LTE():
def __init__(self, apn, uart=None, reset_pin=None, netlight_pin=None, netlight_led=None, skip_reset=False):
self._apn = apn
self._reset = reset_pin or Pin(DEFAULT_PIN_RST, Pin.OUT)
self._uart = uart or UART(
DEFAULT_UART_ID,
tx=Pin(DEFAULT_PIN_TX, Pin.OUT),
rx=Pin(DEFAULT_PIN_RX, Pin.OUT))
# Set PPP timeouts and rxbuf
self._uart.init(
timeout=DEFAULT_UART_TIMEOUT,
timeout_char=DEFAULT_UART_TIMEOUT_CHAR,
rxbuf=DEFAULT_UART_RXBUF)
if not skip_reset:
self._reset.value(0)
time.sleep(1.0)
self._reset.value(1)
if netlight_led:
self._led = netlight_led
self._netlight = netlight_pin or Pin(DEFAULT_PIN_NETLIGHT, Pin.IN)
self._netlight.irq(self._netlight_irq)
def _netlight_irq(self, pin):
self._led.value(pin.value())
def ipconfig(self, *args, **kwargs):
if len(args):
return self._ppp.ipconfig(*args)
else:
return self._ppp.ipconfig(**kwargs)
def iccid(self):
try:
return self._send_at_command("AT+CICCID", 1)
except CellularError:
return None
def status(self):
lte_status = self._send_at_command("AT+CEREG?", 1)
gsm_status = self._send_at_command("AT+CGREG?", 1)
return lte_status, gsm_status
def signal_quality(self):
try:
response = self._send_at_command("AT+CSQ", 1)
quality = int(response.split(":")[1].split(",")[0])
# Conversion as per AT command set datasheet
db = -113 + (2 * quality)
return db
except CellularError:
pass
return None
def stop_ppp(self):
self._ppp.disconnect()
self._send_at_command(f"AT+IPR={DEFAULT_UART_STARTUP_BAUD}")
self._flush_uart()
def start_ppp(self, baudrate=DEFAULT_UART_BAUD, connect=True):
self._wait_ready(poll_time=1.0, timeout=30)
# Switch to a faster baudrate
self._send_at_command(f"AT+IPR={baudrate}")
self._flush_uart()
self._uart.init(
baudrate=baudrate,
timeout=DEFAULT_UART_TIMEOUT,
timeout_char=DEFAULT_UART_TIMEOUT_CHAR,
rxbuf=DEFAULT_UART_RXBUF)
self._wait_ready(poll_time=1.0)
# Connect!
if connect:
self.connect()
# Force PPP to use modem's default settings...
self._flush_uart()
self._uart.write("ATD*99#\r")
self._uart.flush()
self._ppp = PPP(self._uart)
self._ppp.connect()
while self._ppp.status() != 4:
time.sleep(1.0)
return self._ppp.ifconfig()
def connect(self, timeout=60):
print(" - setting up cellular uart")
# Connect to and flush the uart
# Discard any unsolicited messages first, we don't need those
self._flush_uart()
print(" - waiting for cellular module to be ready")
# Wait for the cellular module to respond to AT commands
self._wait_ready()
self._send_at_command("ATE0") # Disable local echo
self._send_at_command(f"AT+CGDCONT=1,\"IP\",\"{self._apn}\"") # Set apn and activate pdp context
# Wait for roaming lte connection to be established
giveup = time.time() + timeout
status = None
while status != "+CEREG: 0,5" and status != "+CEREG: 0,1":
status = self._send_at_command("AT+CEREG?", 1)
time.sleep(0.25)
if time.time() > giveup:
raise CellularError("timed out getting network registration")
# Disable server and client certification validation
self._send_at_command("AT+CSSLCFG=\"authmode\",0,0")
self._send_at_command("AT+CSSLCFG=\"enableSNI\",0,1")
print(f" - SIM ICCID is {self.iccid()}")
def _wait_ready(self, poll_time=0.25, timeout=10):
giveup = time.time() + timeout
while time.time() <= giveup:
try:
self._send_at_command("AT")
return # If __send_at_command doesn't throw an exception then we're good!
except CellularError as e:
print(e)
time.sleep(poll_time)
raise CellularError("timed out waiting for AT response")
def _flush_uart(self):
self._uart.flush()
time.sleep(0.25)
while self._uart.any():
self._uart.read(self._uart.any())
time.sleep(0.25)
def _send_at_command(self, command, result_lines=0, timeout=5.0):
# Discard any unsolicited messages first, we don't need those
self._flush_uart()
self._uart.write(command + "\r")
self._uart.flush()
status, data = self._read_result(result_lines, timeout=timeout)
print(" -", command, status, data)
if status == "TIMEOUT":
raise CellularError(f"cellular module timed out for command {command}")
if status not in ["OK", "DOWNLOAD"]:
raise CellularError(f"non 'OK' or 'DOWNLOAD' result for command {command}")
if result_lines == 1:
return data[0]
if result_lines > 1:
return data
return None
def _read_result(self, result_lines, timeout=1.0):
status = None
result = []
start = time.ticks_ms()
timeout *= 1000
while len(result) < result_lines or status is None:
if (time.ticks_ms() - start) > timeout:
return "TIMEOUT", []
line = self._uart.readline()
if line:
line = line.strip()
if line in [b"OK", b"ERROR", b"DOWNLOAD"]:
status = line.decode("ascii")
elif line != b"":
result.append(str(line, "ascii"))
start = time.ticks_ms()
return status, result