8000 Nrf9160 socket support by glennrub · Pull Request #6236 · micropython/micropython · GitHub
[go: up one dir, main page]

Skip to content

Nrf9160 socket support #6236

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,6 @@
[submodule "lib/nxp_driver"]
path = lib/nxp_driver
url = https://github.com/hathach/nxp_driver.git
[submodule "lib/nrfxlib"]
path = lib/nrfxlib
url = https://github.com/nrfconnect/sdk-nrfxlib.git
1 change: 1 addition & 0 deletions lib/nrfxlib
Submodule nrfxlib added at dae7bf
20 changes: 19 additions & 1 deletion ports/nrf/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ endif
# include py core make definitions
include ../../py/py.mk

GIT_SUBMODULES = lib/nrfx lib/tinyusb
GIT_SUBMODULES = lib/nrfx lib/tinyusb lib/nrfxlib

MICROPY_VFS_FAT ?= 0
MPY_CROSS = ../../mpy-cross/mpy-cross
Expand Down Expand Up @@ -162,6 +162,13 @@ endif

ifeq ( 8000 $(MCU_VARIANT), nrf91)

LIBBSD_FILE_NAME = $(TOP)/lib/nrfxlib/bsdlib/lib/cortex-m33/hard-float/libbsd_nrf9160_xxaa.a

LIBS += -L $(dir $(LIBGCC_FILE_NAME)) -lc
LIBS += -L $(dir $(LIBBSD_FILE_NAME)) -lbsd_nrf9160_xxaa

INC += -I$(TOP)/lib/nrfxlib/bsdlib/include

SRC_LIB += $(addprefix lib/,\
libm/math.c \
libm/fmodf.c \
Expand All @@ -183,6 +190,17 @@ SRC_LIB += $(addprefix lib/,\
libm/atan2f.c \
)

SRC_C += \
drivers/lte/bsd_os.c

DRIVERS_SRC_C += $(addprefix modules/,\
socket/modnetwork.c \
socket/modusocket.c \
socket/modnwlte.c \
)

INC += -I./modules/socket

SRC_NRFX += $(addprefix lib/nrfx/drivers/src/,\
nrfx_uarte.c \
nrfx_twim.c \
Expand Down
4 changes: 4 additions & 0 deletions ports/nrf/boards/actinius_icarus/mpconfigboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,10 @@
#define MICROPY_HW_ENABLE_DAC (0)
#define MICROPY_HW_ENABLE_CAN (0)

#define MICROPY_PY_USOCKET (1)
#define MICROPY_PY_NETWORK (1)
#define MICROPY_PY_LTE_SOCKET (1)

#define MICROPY_HW_LED_TRICOLOR (1)
#define MICROPY_HW_LED_PULLUP (1)

Expand Down
4 changes: 4 additions & 0 deletions ports/nrf/boards/pca10090/mpconfigboard.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@
#define MICROPY_HW_ENABLE_DAC (0)
#define MICROPY_HW_ENABLE_CAN (0)

#define MICROPY_PY_USOCKET (1)
#define MICROPY_PY_NETWORK (1)
#define MICROPY_PY_LTE_SOCKET (1)

#define MICROPY_HW_LED_COUNT (4)
#define MICROPY_HW_LED_PULLUP (0)

Expand Down
187 changes: 187 additions & 0 deletions ports/nrf/drivers/lte/bsd_os.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,187 @@
#include <bsd_os.h>
#include <nrf_errno.h>
#include <bsd_platform.h>
#include <bsd_limits.h>

#include <nrf.h>
#include "nrf_gpio.h"
#include "errno.h"
#include "py/mphal.h"

#define BSD_OS_TRACE_ENABLED 0

#if BSD_OS_TRACE_ENABLED

#include <nrfx_uarte.h>

#define BSD_OS_TRACE_IRQ EGU2_IRQn
#define BSD_OS_TRACE_IRQ_PRIORITY 6
#define BSD_OS_TRACE_IRQ_HANDLER EGU2_IRQHandler

#define BSD_OS_TRACE_UART_IRQ_PRIORITY 3
#define BSD_OS_TRACE_UART_FLOW_CONTROL 0
#define BSD_OS_TRACE_UART_INSTANCE 3
#define BSD_OS_TRACE_UART_IRQ_PRIORITY 3

#define BSD_OS_TRACE_PIN_RX 0
#define BSD_OS_TRACE_PIN_TX 1
#define BSD_OS_TRACE_PIN_RTS 14
#define BSD_OS_TRACE_PIN_CTS 15

static nrfx_uarte_t m_uarte_instance = NRFX_UARTE_INSTANCE(BSD_OS_TRACE_UART_INSTANCE);

#endif // BSD_OS_TRACE_ENABLED

typedef struct {
uint32_t context;
mp_uint_t prev_time;
} bsd_os_timer_t;

static bsd_os_timer_t timers[8];

void read_task_create(void) {
// The read task is achieved using SW interrupt.
NVIC_SetPriority(BSD_APPLICATION_IRQ, BSD_APPLICATION_IRQ_PRIORITY);
NVIC_ClearPendingIRQ(BSD_APPLICATION_IRQ);
NVIC_EnableIRQ(BSD_APPLICATION_IRQ);
}

#if BSD_OS_TRACE_ENABLED
void trace_uart_init(void) {
const nrfx_uarte_config_t config = {
.pseltxd = BSD_OS_TRACE_PIN_TX,
.pselrxd = BSD_OS_TRACE_PIN_RX,
.pselcts = BSD_OS_TRACE_PIN_CTS,
.pselrts = BSD_OS_TRACE_PIN_RTS,
.hwfc = BSD_OS_TRACE_UART_FLOW_CONTROL,
.parity = NRF_UARTE_PARITY_EXCLUDED,
.baudrate = NRF_UARTE_BAUDRATE_1000000,
.interrupt_priority = BSD_OS_TRACE_UART_IRQ_PRIORITY,
.p_context = NULL,
};

nrfx_uarte_init(&m_uarte_instance, &config, NULL);
}

void trace_task_create(void) {
NVIC_SetPriority(BSD_OS_TRACE_IRQ, BSD_OS_TRACE_IRQ_PRIORITY);
NVIC_ClearPendingIRQ(BSD_OS_TRACE_IRQ);
NVIC_EnableIRQ(BSD_OS_TRACE_IRQ);
}
#endif
void bsd_os_init(void) {
read_task_create();
#if BSD_OS_TRACE_ENABLED
trace_uart_init();
trace_task_create();
#endif
}

int32_t locate_timer(uint32_t context) {
for (int i = 0; i < 8; i++)
{
if (timers[i].context == context) {
return i;
}
}
return -1;
}

int32_t locate_free(void) {
for (int i = 0; i < 8; i++)
{
if (timers[i].context == 0) {
return i;
}
}
return -1;
}

int32_t bsd_os_timedwait(uint32_t context, int32_t *timeout) {
if (*timeout == BSD_OS_FOREVER) {
return 0;
}

if (*timeout == 0) {
return NRF_ETIMEDOUT;
}

mp_uint_t tick = mp_hal_ticks_ms();
// Locate timer or free spot.
int32_t timer = locate_timer(context);
if (timer == -1) {
timer = locate_free();

if (timer == -1) {
return NRF_ENOMEM;
}

timers[timer].context = context;
timers[timer].prev_time = tick;
// First time, only allocate.
return 0;
}
mp_uint_t diff = tick - timers[timer].prev_time;

if (diff > *timeout) {

timers[timer].context = 0;
timers[timer].prev_time = 0;
return NRF_ETIMEDOUT;
}
return 0;
}

int nrf_errno;

void bsd_os_errno_set(int errno_val) {
nrf_errno = errno_val;
}

void bsd_os_application_irq_set(void) {
NVIC_SetPendingIRQ(BSD_APPLICATION_IRQ);
}


void bsd_os_application_irq_clear(void) {
NVIC_ClearPendingIRQ(BSD_APPLICATION_IRQ);
}

void BSD_APPLICATION_IRQ_HANDLER(void) {
bsd_os_application_irq_handler();
}

void bsd_os_trace_irq_set(void) {
#if BSD_OS_TRACE_ENABLED
NVIC_SetPendingIRQ(BSD_OS_TRACE_IRQ);
#else
bsd_os_trace_irq_handler();
#endif
}

void bsd_os_trace_irq_clear(void) {
#if BSD_OS_TRACE_ENABLED
NVIC_ClearPendingIRQ(BSD_OS_TRACE_IRQ);
#endif
}

#if BSD_OS_TRACE_ENABLED
void BSD_OS_TRACE_IRQ_HANDLER(void) {
bsd_os_trace_irq_handler();
}
#endif

int32_t bsd_os_trace_put(const uint8_t *const p_buffer, uint32_t buf_len) {
#if BSD_OS_TRACE_ENABLED
uint32_t remaining_bytes = buf_len;

while (remaining_bytes) {
uint8_t transfered_len = MIN(remaining_bytes, UINT8_MAX);
uint32_t index = buf_len - remaining_bytes;

nrfx_uarte_tx(&m_uarte_instance, &p_buffer[index], transfered_len);
remaining_bytes -= transfered_len;
}
#endif
return 0;
}
46 changes: 46 additions & 0 deletions ports/nrf/examples/nrf9160_gps.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
# GNSS sample for pca10090

import network
import socket

n = network.NRF91()
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe this should be network.Cellular() so it can be consistent with other ports that may eventually provide such a network class?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great suggestion! I never came up with a good name for it.


at = socket.socket(socket.AF_LTE, socket.SOCK_DGRAM, socket.PROTO_AT)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it the right pattern to have a socket for the AT connection/commands? Wouldn't it be simpler to have the method on the n cellular network object, eg n.at_send(...) and n.at_recv(...)? Again I'm thinking about other ports that may have cellular, even as an external component.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah, this is the pattern to create a AT-socket. Directly dispatched to the BSD-library. I did actually add a convenience function similar to what you suggest, modnwlte.c:828.

It's a one shot though, which only returns the response, then closes the at-socket again. But it should not be a problem to keep this open for a longer time in case you also want to do subscriptions. One reason for doing a socket instead of a convenience function like this is that you might want to also add it to a socket poll() mask.

at.send("AT+CFUN=4") # Flight mode.
at.recv(20)

# Enable LTE + GNSS, persistently stored.
# Mask of "0, 0, 1, 0" also possible if
# only GNSS is of interest.
at.send("AT%XSYSTEMMODE=1,0,1,0")
at.recv(20)

# Antenna tuning for pca10090 GNSS.
at.send("AT%XMAGPIO=1,0,0,1,1,1574,1577")
at.recv(20)

# Implicit CFUN=1. GNSS sockets can respond, and LTE starts to connect.
# Returns when LTE link has been established. Alternativly, set a timeout
# on connect; n.connect(seconds).
n.connect()

gps = socket.socket(socket.AF_LOCAL, socket.SOCK_DGRAM, socket.PROTO_GNSS)
gps.setsockopt(socket.SOL_GNSS, socket.SO_GNSS_FIX_RETRY, bytearray([0, 0]))
gps.setsockopt(socket.SOL_GNSS, socket.SO_GNSS_FIX_INTERVAL, bytearray([1, 0]))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can GPS be a class rather than a special kind of socket?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, GPS class is a good idea. Do we have anything on this from before?

It is also a binary format which also provides much more information. I used NMEA variant here, to show something well known.


nmea_mask = (
socket.GNSS_NMEA_CONFIG_GGA_FLAG
| socket.GNSS_NMEA_CONFIG_GLL_FLAG
| socket.GNSS_NMEA_CONFIG_GSA_FLAG
| socket.GNSS_NMEA_CONFIG_GSV_FLAG
| socket.GNSS_NMEA_CONFIG_RMC_FLAG
)

gps.setsockopt(socket.SOL_GNSS, socket.SO_GNSS_NMEA_MASK, bytearray([nmea_mask, 0]))
gps.setsockopt(socket.SOL_GNSS, socket.SO_GNSS_START, bytearray([0, 0, 0, 0]))
count = 0
while 1:
count += 1
bytes = gps.recv(580)
if bytes[0] == 2:
print("NMEA:%s" % str(bytes[8:], "utf-8"))
13 changes: 13 additions & 0 deletions ports/nrf/examples/nrf9160_http.py
E300 Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# HTTP GET sample.

import network, socket

n = network.NRF91()
n.connect()

addr = socket.getaddrinfo("micropython.org", 80)
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM, socket.IPPROTO_TCP)
s.connect(addr[0][-1])
s.send("GET / HTTP/1.1\r\nHost: micropython.org\r\n\r\n")
res = s.recv(1000)
print(res)
8 changes: 8 additions & 0 deletions ports/nrf/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,10 @@
#include "usb_cdc.h"
#endif

#if MICROPY_PY_NETWORK
#include "modnetwork.h"
#endif

void do_str(const char *src, mp_parse_input_kind_t input_kind) {
mp_lexer_t *lex = mp_lexer_new_from_str_len(MP_QSTR__lt_stdin_gt_, src, strlen(src), 0);
if (lex == NULL) {
Expand Down Expand Up @@ -233,6 +237,10 @@ int main(int argc, char **argv) {

led_state(1, 0);

#if MICROPY_PY_NETWORK
mod_network_init();
#endif

#if MICROPY_VFS || MICROPY_MBFS || MICROPY_MODULE_FROZEN
// run boot.py and main.py if they exist.
pyexec_file_if_exists("boot.py");
Expand Down
Loading
0