-
-
Notifications
You must be signed in to change notification settings - Fork 8.2k
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
Nrf9160 socket support #6236
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
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; | ||
} |
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() | ||
|
||
at = socket.socket(socket.AF_LTE, socket.SOCK_DGRAM, socket.PROTO_AT) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 |
||
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])) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. can GPS be a class rather than a special kind of socket? There was a problem hiding this comment. Choose a reason for hiding this commentThe 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")) |
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) |
There was a problem hiding this comment.
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?There was a problem hiding this comment.
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.