Skip to content
Permalink
Browse files

drivers: modem: interface: introduce UART interface driver layer

The UART-based modem interface layer implements the modem context
interface for Zephyr's UART APIs.  This driver closely resembles
the existing modem receiver, but conforming to the modem interface
agreements.

Example modem driver setup code looks like this:

/* create modem context object */
static struct modem_context mctx;

/* create uart interface data object and buffers */
static struct modem_iface_uart_data iface_data;
static u8_t iface_isr_buf[MDM_RECV_BUF_SIZE];
static u8_t iface_rb_buf[MDM_MAX_DATA_LENGTH];

iface_data.isr_buf = &iface_isr_buf[0];
iface_data.isr_buf_len = sizeof(iface_isr_buf);
iface_data.rx_rb_buf = &iface_rb_buf[0];
iface_data.rx_rb_buf_len = sizeof(iface_rb_buf);
ret = modem_iface_uart_init(&mctx.iface, &iface_data,
			    UART_DEV_NAME);

Signed-off-by: Michael Scott <mike@foundries.io>
  • Loading branch information...
mike-scott authored and ioannisg committed Aug 7, 2019
1 parent 90e778d commit d56a05f7a7a8abe606aef1d196ff828170c5da67
Showing with 219 additions and 0 deletions.
  1. +2 −0 drivers/modem/CMakeLists.txt
  2. +11 −0 drivers/modem/Kconfig
  3. +152 −0 drivers/modem/modem_iface_uart.c
  4. +54 −0 drivers/modem/modem_iface_uart.h
@@ -8,6 +8,8 @@ zephyr_sources_ifdef(CONFIG_MODEM_CONTEXT
modem_pin.c
)

zephyr_sources_ifdef(CONFIG_MODEM_IFACE_UART modem_iface_uart.c)

if(CONFIG_MODEM_UBLOX_SARA_R4)
zephyr_library_include_directories(${ZEPHYR_BASE}/subsys/net/ip)
zephyr_library_sources(ublox-sara-r4.c)
@@ -64,6 +64,17 @@ config MODEM_CONTEXT_VERBOSE_DEBUG
Enabling this setting will turn on VERY heavy debugging from the
modem context helper. Do NOT leave on for production.

config MODEM_IFACE_UART
bool "UART-based modem interface"
depends on SERIAL_SUPPORT_INTERRUPT
select UART_INTERRUPT_DRIVEN
select RING_BUFFER
help
To configure this layer for use, create a modem_iface_uart_data
object and pass it's reference to modem_iface_uart_init()
along with the modem_iface reference from your modem_context object
and the UART device name.

endif # MODEM_CONTEXT

config MODEM_SHELL
@@ -0,0 +1,152 @@
/** @file
* @brief interface for modem context
*
* UART-based modem interface implementation for modem context driver.
*/

/*
* Copyright (c) 2019 Foundries.io
*
* SPDX-License-Identifier: Apache-2.0
*/

#include <logging/log.h>
LOG_MODULE_REGISTER(modem_iface_uart, CONFIG_MODEM_LOG_LEVEL);

#include <kernel.h>
#include <drivers/uart.h>

#include "modem_context.h"
#include "modem_iface_uart.h"

/**
* @brief Drains UART.
*
* @note Discards remaining data.
*
* @param *iface: modem interface.
*
* @retval None.
*/
static void modem_iface_uart_flush(struct modem_iface *iface)
{
u8_t c;

while (uart_fifo_read(iface->dev, &c, 1) > 0) {
continue;
}
}

/**
* @brief Modem interface interrupt handler.
*
* @note Fills interfaces ring buffer with received data.
* When ring buffer is full the data is discarded.
*
* @param *uart_dev: uart device.
*
* @retval None.
*/
static void modem_iface_uart_isr(struct device *uart_dev)
{
struct modem_context *ctx;
struct modem_iface_uart_data *data;
int rx = 0, ret;

/* lookup the modem context */
ctx = modem_context_from_iface_dev(uart_dev);
if (!ctx || !ctx->iface.iface_data) {
return;
}

data = (struct modem_iface_uart_data *)(ctx->iface.iface_data);
/* get all of the data off UART as fast as we can */
while (uart_irq_update(ctx->iface.dev) &&
uart_irq_rx_ready(ctx->iface.dev)) {
rx = uart_fifo_read(ctx->iface.dev,
data->isr_buf, data->isr_buf_len);
if (rx <= 0) {
continue;
}

ret = ring_buf_put(&data->rx_rb, data->isr_buf, rx);
if (ret != rx) {
LOG_ERR("Rx buffer doesn't have enough space. "
"Bytes pending: %d, written: %d",
rx, ret);
modem_iface_uart_flush(&ctx->iface);
k_sem_give(&data->rx_sem);
break;
}

k_sem_give(&data->rx_sem);
}
}

static int modem_iface_uart_read(struct modem_iface *iface,
u8_t *buf, size_t size, size_t *bytes_read)
{
struct modem_iface_uart_data *data;

if (!iface || !iface->iface_data) {
return -EINVAL;
}

if (size == 0) {
*bytes_read = 0;
return 0;
}

data = (struct modem_iface_uart_data *)(iface->iface_data);
*bytes_read = ring_buf_get(&data->rx_rb, buf, size);

return 0;
}

static int modem_iface_uart_write(struct modem_iface *iface,
const u8_t *buf, size_t size)
{
if (!iface || !iface->iface_data) {
return -EINVAL;
}

if (size == 0) {
return 0;
}

do {
uart_poll_out(iface->dev, *buf++);
} while (--size);

return 0;
}

int modem_iface_uart_init(struct modem_iface *iface,
struct modem_iface_uart_data *data,
const char *dev_name)
{
if (!iface || !data) {
return -EINVAL;
}

/* get UART device */
iface->dev = device_get_binding(dev_name);
if (!iface->dev) {
return -ENODEV;
}

iface->iface_data = data;
iface->read = modem_iface_uart_read;
iface->write = modem_iface_uart_write;

ring_buf_init(&data->rx_rb, data->rx_rb_buf_len, data->rx_rb_buf);
k_sem_init(&data->rx_sem, 0, 1);

uart_irq_rx_disable(iface->dev);
uart_irq_tx_disable(iface->dev);
modem_iface_uart_flush(iface);
uart_irq_callback_set(iface->dev, modem_iface_uart_isr);
uart_irq_rx_enable(iface->dev);

return 0;
}
@@ -0,0 +1,54 @@
/** @file
* @brief Modem interface for UART header file.
*
* Modem interface UART handling for modem context driver.
*/

/*
* Copyright (c) 2019 Foundries.io
*
* SPDX-License-Identifier: Apache-2.0
*/

#ifndef ZEPHYR_INCLUDE_DRIVERS_MODEM_MODEM_IFACE_UART_H_
#define ZEPHYR_INCLUDE_DRIVERS_MODEM_MODEM_IFACE_UART_H_

#include <kernel.h>

#ifdef __cplusplus
extern "C" {
#endif

struct modem_iface_uart_data {
/* ISR char buffer */
char *isr_buf;
size_t isr_buf_len;

/* ring buffer char buffer */
char *rx_rb_buf;
size_t rx_rb_buf_len;

/* ring buffer */
struct ring_buf rx_rb;

/* rx semaphore */
struct k_sem rx_sem;
};

/**
* @brief Init modem interface for UART
*
* @param *iface: modem interface to initialize.
* @param *data: modem interface data to use
*
* @retval 0 if ok, < 0 if error.
*/
int modem_iface_uart_init(struct modem_iface *iface,
struct modem_iface_uart_data *data,
const char *dev_name);

#ifdef __cplusplus
}
#endif

#endif /* ZEPHYR_INCLUDE_DRIVERS_MODEM_MODEM_IFACE_UART_H_ */

0 comments on commit d56a05f

Please sign in to comment.
You can’t perform that action at this time.