BLE_TYQ_BJQ_CH32V303/packages/at_device-2.1.0/at_device.c

300 lines
7.4 KiB
C
Raw Permalink Normal View History

2024-12-01 13:49:43 +08:00
/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2019-05-08 chenyong first version
*/
#include <stdlib.h>
#include <string.h>
#include "cpuport.h"
#include <at_device.h>
#include <rthw.h>
#define DBG_TAG "at.dev"
#define DBG_LVL DBG_INFO
#include <rtdbg.h>
/* The global list of at device */
static rt_slist_t at_device_list = RT_SLIST_OBJECT_INIT(at_device_list);
/* The global list of at device class */
static rt_slist_t at_device_class_list = RT_SLIST_OBJECT_INIT(at_device_class_list);
/**
* This function will get the first initialized AT device.
*
* @return the AT device structure pointer
*/
struct at_device *at_device_get_first_initialized(void)
{
rt_base_t level;
rt_slist_t *node = RT_NULL;
struct at_device *device = RT_NULL;
level = rt_hw_interrupt_disable();
rt_slist_for_each(node, &at_device_list)
{
device = rt_slist_entry(node, struct at_device, list);
if (device && device->is_init == RT_TRUE)
{
rt_hw_interrupt_enable(level);
return device;
}
}
rt_hw_interrupt_enable(level);
return RT_NULL;
}
/**
* This function will get AT device by device name.
*
* @param type the name type
* @param name the device name or the client name
*
* @return the AT device structure pointer
*/
struct at_device *at_device_get_by_name(int type, const char *name)
{
rt_base_t level;
rt_slist_t *node = RT_NULL;
struct at_device *device = RT_NULL;
RT_ASSERT(name);
level = rt_hw_interrupt_disable();
rt_slist_for_each(node, &at_device_list)
{
device = rt_slist_entry(node, struct at_device, list);
if (device)
{
if (((type == AT_DEVICE_NAMETYPE_DEVICE) || (type == AT_DEVICE_NAMETYPE_NETDEV)) &&
(rt_strncmp(device->name, name, rt_strlen(name)) == 0))
{
rt_hw_interrupt_enable(level);
return device;
}
else if ((type == AT_DEVICE_NAMETYPE_CLIENT) &&
(rt_strncmp(device->client->device->parent.name, name, rt_strlen(name)) == 0))
{
rt_hw_interrupt_enable(level);
return device;
}
}
}
rt_hw_interrupt_enable(level);
return RT_NULL;
}
#ifdef AT_USING_SOCKET
/**
* This function will get AT device by ip address.
*
* @param ip_addr input ip address
* network
* @return != NULL: network interface device object
* NULL: get failed
*/
struct at_device *at_device_get_by_ipaddr(ip_addr_t *ip_addr)
{
rt_base_t level;
rt_slist_t *node = RT_NULL;
struct at_device *device = RT_NULL;
level = rt_hw_interrupt_disable();
rt_slist_for_each(node, &at_device_list)
{
device = rt_slist_entry(node, struct at_device, list);
if (device && ip_addr_cmp(ip_addr, &(device->netdev->ip_addr)))
{
rt_hw_interrupt_enable(level);
return device;
}
}
rt_hw_interrupt_enable(level);
return RT_NULL;
}
#endif /* AT_USING_SOCKET */
/**
* This function will perform a variety of control functions on AT devices.
*
* @param device the pointer of AT device structure
* @param cmd the command sent to AT device
* @param arg the argument of command
*
* @return = 0: perform successfully
* < 0: perform failed
*/
int at_device_control(struct at_device *device, int cmd, void *arg)
{
if (device->class->device_ops->control)
{
return device->class->device_ops->control(device, cmd, arg);
}
else
{
LOG_W("AT device(%s) not support control operations.", device->name);
return RT_EOK;
}
}
/**
* This function registers an AT device class with specified device class ID.
*
* @param class the pointer of AT device class structure
* @param class_id AT device class ID
*
* @return 0: register successfully
*/
int at_device_class_register(struct at_device_class *class, uint16_t class_id)
{
rt_base_t level;
RT_ASSERT(class);
/* Fill AT device class */
class->class_id = class_id;
/* Initialize current AT device class single list */
rt_slist_init(&(class->list));
level = rt_hw_interrupt_disable();
/* Add current AT device class to list */
rt_slist_append(&at_device_class_list, &(class->list));
rt_hw_interrupt_enable(level);
return RT_EOK;
}
/* Get AT device class by client ID */
static struct at_device_class *at_device_class_get(uint16_t class_id)
{
rt_base_t level;
rt_slist_t *node = RT_NULL;
struct at_device_class *class = RT_NULL;
level = rt_hw_interrupt_disable();
/* Get AT device class by class ID */
rt_slist_for_each(node, &at_device_class_list)
{
class = rt_slist_entry(node, struct at_device_class, list);
if (class && class->class_id == class_id)
{
rt_hw_interrupt_enable(level);
return class;
}
}
rt_hw_interrupt_enable(level);
return RT_NULL;
}
/**
* This function registers an AT device with specified device name and AT client name.
*
* @param device the pointer of AT device structure
* @param device_name AT device name
* @param at_client_name AT device client name
* @param class_id AT device class ID
* @param user_data user-specific data
*
* @return = 0: register successfully
* < 0: register failed
*/
int at_device_register(struct at_device *device, const char *device_name,
const char *at_client_name, uint16_t class_id, void *user_data)
{
rt_base_t level;
int result = 0;
#ifdef AT_USING_SOCKET
static int device_counts = 0;
char name[RT_NAME_MAX] = {0};
#endif
struct at_device_class *class = RT_NULL;
RT_ASSERT(device);
RT_ASSERT(device_name);
RT_ASSERT(at_client_name);
class = at_device_class_get(class_id);
if (class == RT_NULL)
{
LOG_E("get AT device class(%d) failed.", class_id);
result = -RT_ERROR;
goto __exit;
}
/* Fill AT device object*/
#ifdef AT_USING_SOCKET
device->sockets = (struct at_socket *) rt_calloc(class->socket_num, sizeof(struct at_socket));
if (device->sockets == RT_NULL)
{
LOG_E("no memory for AT Socket number(%d) create.", class->socket_num);
result = -RT_ENOMEM;
goto __exit;
}
/* create AT device socket event */
rt_snprintf(name, RT_NAME_MAX, "at_se%d", device_counts++);
device->socket_event = rt_event_create(name, RT_IPC_FLAG_FIFO);
if (device->socket_event == RT_NULL)
{
LOG_E("no memory for AT device(%s) socket event create.", device_name);
result = -RT_ENOMEM;
goto __exit;
}
#endif /* AT_USING_SOCKET */
rt_memcpy(device->name, device_name, rt_strlen(device_name));
device->class = class;
device->user_data = user_data;
/* Initialize current AT device single list */
rt_slist_init(&(device->list));
level = rt_hw_interrupt_disable();
/* Add current AT device to device list */
rt_slist_append(&at_device_list, &(device->list));
rt_hw_interrupt_enable(level);
/* Initialize AT device */
result = class->device_ops->init(device);
if (result < 0)
{
goto __exit;
}
__exit:
if (result < 0)
{
device->is_init = RT_FALSE;
}
else
{
device->is_init = RT_TRUE;
}
return result;
}