476 lines
14 KiB
C
476 lines
14 KiB
C
/***************************************************************************//**
|
|
* @file iio_app.c
|
|
* @brief C file of iio_app
|
|
* @author Mihail Chindris (mihail.chindris@analog.com)
|
|
********************************************************************************
|
|
* Copyright 2020(c) Analog Devices, Inc.
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright notice,
|
|
* this list of conditions and the following disclaimer.
|
|
*
|
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
|
* this list of conditions and the following disclaimer in the documentation
|
|
* and/or other materials provided with the distribution.
|
|
*
|
|
* 3. Neither the name of Analog Devices, Inc. nor the names of its
|
|
* contributors may be used to endorse or promote products derived from this
|
|
* software without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY ANALOG DEVICES, INC. “AS IS” AND ANY EXPRESS OR
|
|
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
|
* EVENT SHALL ANALOG DEVICES, INC. BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
|
|
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
|
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
|
|
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
|
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
|
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
|
*******************************************************************************/
|
|
|
|
#ifdef IIO_SUPPORT
|
|
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include "iio_app.h"
|
|
#include "parameters.h"
|
|
#include "no_os_alloc.h"
|
|
|
|
#if defined(ADUCM_PLATFORM)
|
|
#include "aducm3029_uart.h"
|
|
#include "aducm3029_irq.h"
|
|
#endif
|
|
#if defined(XILINX_PLATFORM)
|
|
#include "xilinx_uart.h"
|
|
#include "xilinx_irq.h"
|
|
#endif
|
|
#if defined(STM32_PLATFORM)
|
|
#include <errno.h>
|
|
#include "stm32_uart.h"
|
|
#include "stm32_irq.h"
|
|
#endif
|
|
#if defined(MAXIM_PLATFORM)
|
|
#include "maxim_irq.h"
|
|
#include "maxim_uart.h"
|
|
#endif
|
|
|
|
#ifdef NO_OS_NETWORKING
|
|
/* Fix: Use static buffers instead of calloc for new connections */
|
|
#warning "iio may not work with WIFI on aducm3029."
|
|
#ifdef ADUCM_PLATFORM
|
|
#include "wifi.h"
|
|
#endif
|
|
#include "tcp_socket.h"
|
|
#endif
|
|
|
|
#ifdef LINUX_PLATFORM
|
|
#include "linux_socket.h"
|
|
#include "tcp_socket.h"
|
|
#endif
|
|
|
|
#ifdef NO_OS_LWIP_NETWORKING
|
|
#include "lwip_socket.h"
|
|
#endif
|
|
|
|
// The default baudrate iio_app will use to print messages to console.
|
|
#define UART_BAUDRATE_DEFAULT 115200
|
|
#define UART_STOPBITS_DEFAULT NO_OS_UART_STOP_1_BIT
|
|
|
|
static inline uint32_t _calc_uart_xfer_time(uint32_t len, uint32_t baudrate)
|
|
{
|
|
uint32_t ms = 1000ul * len * 8 / UART_BAUDRATE_DEFAULT;
|
|
ms += ms / 10; // overhead
|
|
return ms;
|
|
}
|
|
|
|
#if !defined(LINUX_PLATFORM) && !defined(NO_OS_NETWORKING) && !defined(NO_OS_USB_UART)
|
|
static int32_t iio_print_uart_info_message(struct no_os_uart_desc **uart_desc,
|
|
struct no_os_uart_init_param *user_uart_params,
|
|
char *message, int32_t msglen)
|
|
{
|
|
int32_t status;
|
|
uint32_t delay_ms;
|
|
|
|
status = no_os_uart_write(*uart_desc, (uint8_t *)message, msglen);
|
|
if (status < 0)
|
|
return status;
|
|
|
|
delay_ms = _calc_uart_xfer_time(msglen, UART_BAUDRATE_DEFAULT);
|
|
no_os_mdelay(delay_ms);
|
|
|
|
/** Reinitialize UART with parameters required by the IIO application */
|
|
no_os_uart_remove(*uart_desc);
|
|
return no_os_uart_init(uart_desc, user_uart_params);
|
|
}
|
|
#endif
|
|
|
|
static int32_t print_uart_hello_message(struct no_os_uart_desc **uart_desc,
|
|
struct no_os_uart_init_param *user_uart_params)
|
|
{
|
|
#if defined(LINUX_PLATFORM) || defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) || defined(NO_OS_USB_UART)
|
|
return 0;
|
|
#else
|
|
const char *uart_data_size[] = { "5", "6", "7", "8", "9" };
|
|
const char *uart_parity[] = { "none", "mark", "space", "odd", "even" };
|
|
const char *uart_stop[] = { "1", "2" };
|
|
char message[512];
|
|
uint32_t msglen = sprintf(message,
|
|
"Running IIOD server...\n"
|
|
"If successful, you may connect an IIO client application by:\n"
|
|
"1. Disconnecting the serial terminal you use to view this message.\n"
|
|
"2. Connecting the IIO client application using the serial backend configured as shown:\n"
|
|
"\tBaudrate: %lu\n"
|
|
"\tData size: %s bits\n"
|
|
"\tParity: %s\n"
|
|
"\tStop bits: %s\n"
|
|
"\tFlow control: none\n",
|
|
user_uart_params->baud_rate,
|
|
uart_data_size[user_uart_params->size],
|
|
uart_parity[user_uart_params->parity],
|
|
uart_stop[user_uart_params->stop]);
|
|
|
|
return iio_print_uart_info_message(uart_desc, user_uart_params,
|
|
message, msglen);
|
|
#endif
|
|
}
|
|
|
|
static int32_t print_uart_error_message(struct no_os_uart_desc **uart_desc,
|
|
struct no_os_uart_init_param *user_uart_params,
|
|
int32_t status)
|
|
{
|
|
char message[512];
|
|
uint32_t msglen = sprintf(message,
|
|
"IIOD server failed with code %d.\n",
|
|
(int)status);
|
|
#if defined(LINUX_PLATFORM) || defined(NO_OS_NETWORKING) || defined(NO_OS_LWIP_NETWORKING) || defined(NO_OS_USB_UART)
|
|
(void)msglen;
|
|
printf("%s", message);
|
|
return 0;
|
|
#else
|
|
return iio_print_uart_info_message(uart_desc, user_uart_params,
|
|
message, msglen);
|
|
#endif
|
|
}
|
|
|
|
#if defined(NO_OS_LWIP_NETWORKING)
|
|
static int32_t lwip_network_setup(struct iio_app_desc *app,
|
|
struct iio_app_init_param param,
|
|
struct iio_init_param *iio_init_param)
|
|
{
|
|
static struct tcp_socket_init_param socket_param;
|
|
static struct lwip_network_desc lwip_desc;
|
|
static bool is_initialized = false;
|
|
int ret;
|
|
|
|
if (NO_OS_LWIP_INIT_ONETIME && is_initialized) {
|
|
socket_param.net = &lwip_desc.no_os_net;
|
|
} else {
|
|
ret = no_os_lwip_init(&app->lwip_desc, ¶m.lwip_param);
|
|
if (ret)
|
|
return ret;
|
|
|
|
socket_param.net = &app->lwip_desc->no_os_net;
|
|
memcpy(&lwip_desc, app->lwip_desc, sizeof(lwip_desc));
|
|
}
|
|
|
|
is_initialized = true;
|
|
socket_param.max_buff_size = 0;
|
|
|
|
iio_init_param->phy_type = USE_NETWORK;
|
|
iio_init_param->tcp_socket_init_param = &socket_param;
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
#if defined(NO_OS_NETWORKING) || defined(LINUX_PLATFORM)
|
|
static int32_t network_setup(struct iio_init_param *iio_init_param,
|
|
struct no_os_uart_desc *uart_desc,
|
|
void *irq_desc)
|
|
{
|
|
static struct tcp_socket_init_param socket_param;
|
|
|
|
#ifdef LINUX_PLATFORM
|
|
socket_param.net = &linux_net;
|
|
#endif
|
|
#ifdef ADUCM_PLATFORM
|
|
int32_t status;
|
|
static struct wifi_desc *wifi;
|
|
struct wifi_init_param wifi_param = {
|
|
.irq_desc = irq_desc,
|
|
.uart_desc = uart_desc,
|
|
.uart_irq_conf = uart_desc,
|
|
.uart_irq_id = UART_IRQ_ID,
|
|
.sw_reset_en = true
|
|
};
|
|
status = wifi_init(&wifi, &wifi_param);
|
|
if (status < 0)
|
|
return status;
|
|
|
|
status = wifi_connect(wifi, WIFI_SSID, WIFI_PWD);
|
|
if (status < 0)
|
|
return status;
|
|
|
|
char buff[100];
|
|
wifi_get_ip(wifi, buff, 100);
|
|
printf("iiod ip is: %s\n", buff);
|
|
|
|
wifi_get_network_interface(wifi, &socket_param.net);
|
|
#endif
|
|
|
|
socket_param.max_buff_size = 0;
|
|
iio_init_param->phy_type = USE_NETWORK;
|
|
iio_init_param->tcp_socket_init_param = &socket_param;
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
static int32_t uart_setup(struct no_os_uart_desc **uart_desc,
|
|
struct no_os_uart_init_param *uart_init_par)
|
|
{
|
|
#if defined(LINUX_PLATFORM) || defined(NO_OS_LWIP_NETWORKING)
|
|
*uart_desc = NULL;
|
|
return 0;
|
|
#endif
|
|
struct no_os_uart_init_param luart_par = {
|
|
.device_id = uart_init_par->device_id,
|
|
/* TODO: remove this ifdef when asynchrounous rx is implemented on every platform. */
|
|
#if defined(STM32_PLATFORM) || defined(MAXIM_PLATFORM) || defined(ADUCM_PLATFORM) || defined(PICO_PLATFORM)
|
|
.irq_id = uart_init_par->irq_id,
|
|
.asynchronous_rx = true,
|
|
#endif
|
|
.baud_rate = UART_BAUDRATE_DEFAULT,
|
|
.size = NO_OS_UART_CS_8,
|
|
.parity = NO_OS_UART_PAR_NO,
|
|
.stop = NO_OS_UART_STOP_1_BIT,
|
|
.platform_ops = uart_init_par->platform_ops,
|
|
#ifndef ADUCM_PLATFORM
|
|
.extra = uart_init_par->extra
|
|
#endif
|
|
};
|
|
|
|
return no_os_uart_init(uart_desc, &luart_par);
|
|
}
|
|
|
|
#if defined(ADUCM_PLATFORM) || (defined(STM32_PLATFORM)) || defined(MAXIM_PLATFORM)
|
|
static int32_t irq_setup(struct no_os_irq_ctrl_desc **irq_desc)
|
|
{
|
|
int32_t status;
|
|
#if defined(ADUCM_PLATFORM)
|
|
void *platform_irq_init_par = NULL;
|
|
const struct no_os_irq_platform_ops *platform_irq_ops = &aducm_irq_ops;
|
|
#elif defined(STM32_PLATFORM)
|
|
void *platform_irq_init_par = NULL;
|
|
const struct no_os_irq_platform_ops *platform_irq_ops = &stm32_irq_ops;
|
|
#elif defined(MAXIM_PLATFORM)
|
|
void *platform_irq_init_par = NULL;
|
|
const struct no_os_irq_platform_ops *platform_irq_ops = &max_irq_ops;
|
|
#endif
|
|
|
|
struct no_os_irq_init_param irq_init_param = {
|
|
.irq_ctrl_id = INTC_DEVICE_ID,
|
|
.platform_ops = platform_irq_ops,
|
|
.extra = platform_irq_init_par
|
|
};
|
|
|
|
status = no_os_irq_ctrl_init(irq_desc, &irq_init_param);
|
|
if (status < 0)
|
|
return status;
|
|
|
|
return no_os_irq_global_enable(*irq_desc);
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* @brief Register devices for an iio application
|
|
*
|
|
* Configuration for communication is done in parameters.h
|
|
* @param app - the iio application descriptor
|
|
* @param app_init_param - the iio application initialization parameters
|
|
* @return 0 on success, negative value otherwise
|
|
*/
|
|
int iio_app_init(struct iio_app_desc **app,
|
|
struct iio_app_init_param app_init_param)
|
|
{
|
|
struct iio_device_init *iio_init_devs = NULL;
|
|
struct iio_init_param iio_init_param;
|
|
struct no_os_uart_desc *uart_desc;
|
|
struct iio_app_desc *application;
|
|
struct iio_data_buffer *buff;
|
|
unsigned int i;
|
|
int status;
|
|
void *irq_desc = app_init_param.irq_desc;
|
|
|
|
application = (struct iio_app_desc *)no_os_calloc(1, sizeof(*application));
|
|
if (!application)
|
|
return -ENOMEM;
|
|
|
|
application->post_step_callback = app_init_param.post_step_callback;
|
|
application->arg = app_init_param.arg;
|
|
|
|
#if defined(ADUCM_PLATFORM) || defined(STM32_PLATFORM)
|
|
/* Only one irq controller can exist and be initialized in
|
|
* any of the iio_devices. */
|
|
for (i = 0; i < app_init_param.nb_devices; i++) {
|
|
if (app_init_param.devices[i].dev_descriptor->irq_desc) {
|
|
irq_desc = (struct no_os_irq_ctrl_desc *)
|
|
app_init_param.devices[i].dev_descriptor->irq_desc;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!irq_desc) {
|
|
status = irq_setup((struct no_os_irq_ctrl_desc **)&irq_desc);
|
|
if (status < 0)
|
|
return status;
|
|
}
|
|
#endif
|
|
|
|
status = uart_setup(&uart_desc, &app_init_param.uart_init_params);
|
|
if (status < 0)
|
|
goto error_uart;
|
|
|
|
status = print_uart_hello_message(&uart_desc,
|
|
&app_init_param.uart_init_params);
|
|
if (status < 0)
|
|
goto error;
|
|
|
|
application->uart_desc = uart_desc;
|
|
#if defined(NO_OS_LWIP_NETWORKING)
|
|
status = lwip_network_setup(application, app_init_param, &iio_init_param);
|
|
if (status)
|
|
goto error;
|
|
#elif defined(NO_OS_NETWORKING) || defined(LINUX_PLATFORM)
|
|
status = network_setup(&iio_init_param, uart_desc, application->irq_desc);
|
|
if (status < 0)
|
|
goto error;
|
|
#else
|
|
iio_init_param.phy_type = USE_UART;
|
|
iio_init_param.uart_desc = uart_desc;
|
|
#endif
|
|
|
|
iio_init_devs = no_os_calloc(app_init_param.nb_devices, sizeof(*iio_init_devs));
|
|
if (!iio_init_devs) {
|
|
status = -ENOMEM;
|
|
goto error;
|
|
}
|
|
|
|
for (i = 0; i < app_init_param.nb_devices; ++i) {
|
|
/*
|
|
* iio_app_device is from iio_app.h and we don't want to include
|
|
* this in iio.h.
|
|
* At the moment iio_device_init has the same parameters but
|
|
* it will change.
|
|
* When changes are done in iio. iio_app_device may be removed
|
|
*iio_init_param and use iio_device_init instead.
|
|
* This way faster changes can be done without changing all
|
|
* project for each change.
|
|
*/
|
|
iio_init_devs[i].name = app_init_param.devices[i].name;
|
|
iio_init_devs[i].dev = app_init_param.devices[i].dev;
|
|
iio_init_devs[i].dev_descriptor = app_init_param.devices[i].dev_descriptor;
|
|
iio_init_devs[i].trigger_id = app_init_param.devices[i].default_trigger_id;
|
|
buff = app_init_param.devices[i].read_buff ?
|
|
app_init_param.devices[i].read_buff :
|
|
app_init_param.devices[i].write_buff;
|
|
if (buff) {
|
|
iio_init_devs[i].raw_buf = buff->buff;
|
|
iio_init_devs[i].raw_buf_len = buff->size;
|
|
} else {
|
|
iio_init_devs[i].raw_buf = NULL;
|
|
iio_init_devs[i].raw_buf_len = 0;
|
|
}
|
|
}
|
|
|
|
iio_init_param.devs = iio_init_devs;
|
|
iio_init_param.nb_devs = app_init_param.nb_devices;
|
|
iio_init_param.trigs = app_init_param.trigs;
|
|
iio_init_param.nb_trigs = app_init_param.nb_trigs;
|
|
iio_init_param.ctx_attrs = app_init_param.ctx_attrs;
|
|
iio_init_param.nb_ctx_attr = app_init_param.nb_ctx_attr;
|
|
|
|
status = iio_init(&application->iio_desc, &iio_init_param);
|
|
if (status < 0)
|
|
goto error;
|
|
|
|
no_os_free(iio_init_devs);
|
|
|
|
*app = application;
|
|
|
|
return 0;
|
|
error_uart:
|
|
/** We might have to reinit UART, settings might have changed for IIO */
|
|
uart_setup(&uart_desc, &app_init_param.uart_init_params);
|
|
error:
|
|
no_os_free(iio_init_devs);
|
|
|
|
no_os_free(application);
|
|
|
|
print_uart_error_message(&uart_desc, &app_init_param.uart_init_params, status);
|
|
no_os_uart_remove(uart_desc);
|
|
|
|
return status;
|
|
}
|
|
|
|
/**
|
|
* @brief Start an IIO application
|
|
*
|
|
* Configuration for communication is done through iio_app_init_param
|
|
* @param app - the iio application parameters
|
|
* @return 0 on success, negative value otherwise
|
|
*/
|
|
int iio_app_run(struct iio_app_desc *app)
|
|
{
|
|
int status;
|
|
|
|
do {
|
|
status = iio_step(app->iio_desc);
|
|
if (status && status != -EAGAIN && status != -ENOTCONN
|
|
&& status != -NO_OS_EOVERRUN)
|
|
return status;
|
|
if (app->post_step_callback) {
|
|
status = app->post_step_callback(app->arg);
|
|
if (status)
|
|
return status;
|
|
}
|
|
} while (true);
|
|
}
|
|
|
|
/**
|
|
* @brief Remove resources allocated by the IIO application
|
|
*
|
|
* Configuration for communication is done through iio_app_init_param
|
|
* @param app - the iio application parameters
|
|
* @return 0 on success, negative value otherwise
|
|
*/
|
|
int iio_app_remove(struct iio_app_desc *app)
|
|
{
|
|
int ret;
|
|
|
|
#if defined(ADUCM_PLATFORM) || (defined(XILINX_PLATFORM) && !defined(PLATFORM_MB)) || defined(STM32_PLATFORM)
|
|
ret = no_os_irq_ctrl_remove(app->irq_desc);
|
|
if (ret)
|
|
return ret;
|
|
#endif
|
|
|
|
if (app->uart_desc) {
|
|
ret = no_os_uart_remove(app->uart_desc);
|
|
if (ret)
|
|
return ret;
|
|
}
|
|
|
|
ret = iio_remove(app->iio_desc);
|
|
if (ret)
|
|
return ret;
|
|
|
|
no_os_free(app);
|
|
|
|
return 0;
|
|
}
|
|
|
|
#endif
|