forked from xuos/xiuos
Merge branch 'prepare_for_master' of https://git.trustie.net/xuos/xiuos into prepare_for_master
This commit is contained in:
commit
3735f221e0
|
@ -10,3 +10,6 @@
|
||||||
[submodule "Ubiquitous/Nuttx/nuttx"]
|
[submodule "Ubiquitous/Nuttx/nuttx"]
|
||||||
path = Ubiquitous/Nuttx/nuttx
|
path = Ubiquitous/Nuttx/nuttx
|
||||||
url = https://gitlink.org.cn/wgzAIIT/incubator-nuttx.git
|
url = https://gitlink.org.cn/wgzAIIT/incubator-nuttx.git
|
||||||
|
[submodule "Ubiquitous/RT_Thread/aiit_board/aiit-riscv64-board/kendryte-sdk/kendryte-sdk-source"]
|
||||||
|
path = Ubiquitous/RT_Thread/aiit_board/aiit-riscv64-board/kendryte-sdk/kendryte-sdk-source
|
||||||
|
url = https://code.gitlink.org.cn/chunyexixiaoyu/kendryte-sdk-source.git
|
||||||
|
|
|
@ -18,5 +18,5 @@ menu "Applications"
|
||||||
source "$APP_DIR/Applications/control_app/Kconfig"
|
source "$APP_DIR/Applications/control_app/Kconfig"
|
||||||
source "$APP_DIR/Applications/knowing_app/Kconfig"
|
source "$APP_DIR/Applications/knowing_app/Kconfig"
|
||||||
source "$APP_DIR/Applications/sensor_app/Kconfig"
|
source "$APP_DIR/Applications/sensor_app/Kconfig"
|
||||||
|
source "$APP_DIR/Applications/embedded_database_app/Kconfig"
|
||||||
endmenu
|
endmenu
|
||||||
|
|
|
@ -56,5 +56,6 @@ void test_adc()
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN),
|
|
||||||
// test_adc, test_adc, read 3.3 voltage data from adc);
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN),
|
||||||
|
adc, test_adc, read 3.3 voltage data from adc);
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
* @author AIIT XUOS Lab
|
* @author AIIT XUOS Lab
|
||||||
* @date 2021-05-29
|
* @date 2021-05-29
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <transform.h>
|
#include <transform.h>
|
||||||
#include <xizi.h>
|
#include <xizi.h>
|
||||||
#include "board.h"
|
#include "board.h"
|
||||||
|
@ -24,27 +25,13 @@
|
||||||
#include <lwip/sockets.h>
|
#include <lwip/sockets.h>
|
||||||
#include "lwip/sys.h"
|
#include "lwip/sys.h"
|
||||||
|
|
||||||
/*******************************************************************************
|
#define TCP_DEMO_BUF_SIZE 65535
|
||||||
* Definitions
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
* Prototypes
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
* Variables
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
char tcp_socket_ip[] = {192, 168, 250, 252};
|
char tcp_socket_ip[] = {192, 168, 250, 252};
|
||||||
|
|
||||||
#define TCP_DEMO_BUF_SIZE 65535
|
/******************************************************************************/
|
||||||
|
|
||||||
/*******************************************************************************
|
static void TCPSocketRecvTask(void *arg)
|
||||||
* Code
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
static void tcp_recv_demo(void *arg)
|
|
||||||
{
|
{
|
||||||
int fd = -1, clientfd;
|
int fd = -1, clientfd;
|
||||||
int recv_len;
|
int recv_len;
|
||||||
|
@ -80,7 +67,7 @@ static void tcp_recv_demo(void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
lw_print("tcp bind success, start to receive.\n");
|
lw_print("tcp bind success, start to receive.\n");
|
||||||
lw_print("\n\nLocal Port:%d\n\n", LWIP_LOCAL_PORT);
|
lw_pr_info("\n\nLocal Port:%d\n\n", LWIP_LOCAL_PORT);
|
||||||
|
|
||||||
// setup socket fd as listening mode
|
// setup socket fd as listening mode
|
||||||
if (listen(fd, 5) != 0 )
|
if (listen(fd, 5) != 0 )
|
||||||
|
@ -91,7 +78,7 @@ static void tcp_recv_demo(void *arg)
|
||||||
|
|
||||||
// accept client connection
|
// accept client connection
|
||||||
clientfd = accept(fd, (struct sockaddr *)&tcp_addr, (socklen_t*)&addr_len);
|
clientfd = accept(fd, (struct sockaddr *)&tcp_addr, (socklen_t*)&addr_len);
|
||||||
lw_print("client %s connected\n", inet_ntoa(tcp_addr.sin_addr));
|
lw_pr_info("client %s connected\n", inet_ntoa(tcp_addr.sin_addr));
|
||||||
|
|
||||||
while(1)
|
while(1)
|
||||||
{
|
{
|
||||||
|
@ -114,7 +101,7 @@ static void tcp_recv_demo(void *arg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void tcp_socket_recv_run(int argc, char *argv[])
|
void TCPSocketRecvTest(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
pthread_t th_id;
|
pthread_t th_id;
|
||||||
|
@ -126,15 +113,14 @@ void tcp_socket_recv_run(int argc, char *argv[])
|
||||||
sscanf(argv[1], "%d.%d.%d.%d", &tcp_socket_ip[0], &tcp_socket_ip[1], &tcp_socket_ip[2], &tcp_socket_ip[3]);
|
sscanf(argv[1], "%d.%d.%d.%d", &tcp_socket_ip[0], &tcp_socket_ip[1], &tcp_socket_ip[2], &tcp_socket_ip[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ETH_BSP_Config();
|
|
||||||
lwip_config_tcp(lwip_ipaddr, lwip_netmask, lwip_gwaddr);
|
lwip_config_tcp(lwip_ipaddr, lwip_netmask, lwip_gwaddr);
|
||||||
sys_thread_new("tcp_recv_demo", tcp_recv_demo, NULL, LWIP_TASK_STACK_SIZE, LWIP_DEMO_TASK_PRIO);
|
sys_thread_new("TCPSocketRecvTask", TCPSocketRecvTask, NULL, LWIP_TASK_STACK_SIZE, LWIP_DEMO_TASK_PRIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
||||||
TCPSocketRecv, tcp_socket_recv_run, TCP recv echo);
|
TCPSocketRecv, TCPSocketRecvTest, TCP recv echo);
|
||||||
|
|
||||||
static void tcp_send_demo(void *arg)
|
static void TCPSocketSendTask(void *arg)
|
||||||
{
|
{
|
||||||
int cnt = LWIP_DEMO_TIMES;
|
int cnt = LWIP_DEMO_TIMES;
|
||||||
int fd = -1;
|
int fd = -1;
|
||||||
|
@ -163,7 +149,7 @@ static void tcp_send_demo(void *arg)
|
||||||
}
|
}
|
||||||
|
|
||||||
lw_print("tcp connect success, start to send.\n");
|
lw_print("tcp connect success, start to send.\n");
|
||||||
lw_pr_info("\n\nTarget Port:%d\n\n", tcp_sock.sin_port);
|
lw_pr_info("\n\nTarget Port:%d\n\n", LWIP_TARGET_PORT);
|
||||||
|
|
||||||
while (cnt --)
|
while (cnt --)
|
||||||
{
|
{
|
||||||
|
@ -182,7 +168,7 @@ __exit:
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void tcp_socket_send_run(int argc, char *argv[])
|
void TCPSocketSendTest(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
if(argc == 2)
|
if(argc == 2)
|
||||||
{
|
{
|
||||||
|
@ -190,11 +176,10 @@ void tcp_socket_send_run(int argc, char *argv[])
|
||||||
sscanf(argv[1], "%d.%d.%d.%d", &tcp_socket_ip[0], &tcp_socket_ip[1], &tcp_socket_ip[2], &tcp_socket_ip[3]);
|
sscanf(argv[1], "%d.%d.%d.%d", &tcp_socket_ip[0], &tcp_socket_ip[1], &tcp_socket_ip[2], &tcp_socket_ip[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
ETH_BSP_Config();
|
|
||||||
lwip_config_tcp(lwip_ipaddr, lwip_netmask, tcp_socket_ip);
|
lwip_config_tcp(lwip_ipaddr, lwip_netmask, tcp_socket_ip);
|
||||||
sys_thread_new("tcp socket", tcp_send_demo, NULL, LWIP_TASK_STACK_SIZE, LWIP_DEMO_TASK_PRIO);
|
sys_thread_new("tcp socket", TCPSocketSendTask, NULL, LWIP_TASK_STACK_SIZE, LWIP_DEMO_TASK_PRIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(0),
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(0),
|
||||||
TCPSocketSend, tcp_socket_send_run, TCP send demo);
|
TCPSocketSend, TCPSocketSendTest, TCP send demo);
|
||||||
|
|
||||||
|
|
|
@ -23,36 +23,20 @@
|
||||||
#include "sys_arch.h"
|
#include "sys_arch.h"
|
||||||
#include "lwip/udp.h"
|
#include "lwip/udp.h"
|
||||||
#include "lwip/opt.h"
|
#include "lwip/opt.h"
|
||||||
|
#include <lwip/sockets.h>
|
||||||
|
#include "lwip/sys.h"
|
||||||
|
|
||||||
/*******************************************************************************
|
#define UDP_BUF_SIZE 65536
|
||||||
* Definitions
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
* Prototypes
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
* Variables
|
|
||||||
******************************************************************************/
|
|
||||||
extern char udp_target[];
|
extern char udp_target[];
|
||||||
static struct udp_pcb *udpecho_raw_pcb;
|
static struct udp_pcb *udpecho_raw_pcb;
|
||||||
char udp_socket_ip[] = {192, 168, 250, 252};
|
char udp_socket_ip[] = {192, 168, 250, 252};
|
||||||
|
|
||||||
/*******************************************************************************
|
/******************************************************************************/
|
||||||
* Code
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
#include <lwip/sockets.h>
|
static void UdpSocketRecvTask(void *arg)
|
||||||
#include "lwip/sys.h"
|
|
||||||
|
|
||||||
#define LWIP_UDP_TASK_STACK 4096
|
|
||||||
#define LWIP_UDP_TASK_PRIO 25
|
|
||||||
#define UDP_BUF_SIZE 1024
|
|
||||||
|
|
||||||
static void udp_recv_demo(void *arg)
|
|
||||||
{
|
{
|
||||||
lw_print("udp_recv_demo start.\n");
|
lw_print("UdpSocketRecvTask start.\n");
|
||||||
|
|
||||||
int socket_fd = -1;
|
int socket_fd = -1;
|
||||||
char *recv_buf;
|
char *recv_buf;
|
||||||
|
@ -94,28 +78,25 @@ static void udp_recv_demo(void *arg)
|
||||||
{
|
{
|
||||||
memset(recv_buf, 0, UDP_BUF_SIZE);
|
memset(recv_buf, 0, UDP_BUF_SIZE);
|
||||||
recv_len = recvfrom(socket_fd, recv_buf, UDP_BUF_SIZE, 0, (struct sockaddr *)&server_addr, &addr_len);
|
recv_len = recvfrom(socket_fd, recv_buf, UDP_BUF_SIZE, 0, (struct sockaddr *)&server_addr, &addr_len);
|
||||||
lw_print("Receive from : %s\n", inet_ntoa(server_addr.sin_addr));
|
lw_pr_info("Receive from : %s\n", inet_ntoa(server_addr.sin_addr));
|
||||||
lw_print("Receive data : %s\n\n", recv_buf);
|
lw_pr_info("Receive data : %s\n\n", recv_buf);
|
||||||
sendto(socket_fd, recv_buf, recv_len, 0, (struct sockaddr*)&server_addr, addr_len);
|
sendto(socket_fd, recv_buf, recv_len, 0, (struct sockaddr*)&server_addr, addr_len);
|
||||||
}
|
}
|
||||||
|
|
||||||
__exit:
|
__exit:
|
||||||
if(socket_fd >= 0)
|
if(socket_fd >= 0)
|
||||||
|
{
|
||||||
closesocket(socket_fd);
|
closesocket(socket_fd);
|
||||||
|
}
|
||||||
|
|
||||||
if(recv_buf)
|
if(recv_buf)
|
||||||
|
{
|
||||||
free(recv_buf);
|
free(recv_buf);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void udp_recv_demo_thread(void* param)
|
|
||||||
{
|
|
||||||
ETH_BSP_Config();
|
|
||||||
lwip_config_tcp(lwip_ipaddr, lwip_netmask, lwip_gwaddr);
|
|
||||||
sys_thread_new("udp_recv_demo", udp_recv_demo, NULL, LWIP_UDP_TASK_STACK, LWIP_UDP_TASK_PRIO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void udp_socket_recv_run(int argc, char *argv[])
|
void UdpSocketRecvTask(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
pthread_t th_id;
|
pthread_t th_id;
|
||||||
|
@ -127,18 +108,19 @@ void udp_socket_recv_run(int argc, char *argv[])
|
||||||
sscanf(argv[1], "%d.%d.%d.%d", &udp_socket_ip[0], &udp_socket_ip[1], &udp_socket_ip[2], &udp_socket_ip[3]);
|
sscanf(argv[1], "%d.%d.%d.%d", &udp_socket_ip[0], &udp_socket_ip[1], &udp_socket_ip[2], &udp_socket_ip[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
sys_thread_new("udp socket send", udp_recv_demo_thread, NULL, 4096, 15);
|
lwip_config_tcp(lwip_ipaddr, lwip_netmask, lwip_gwaddr);
|
||||||
|
sys_thread_new("UdpSocketRecvTask", UdpSocketRecvTask, NULL, LWIP_TASK_STACK_SIZE, LWIP_DEMO_TASK_PRIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
||||||
UDPSocketRecv, udp_socket_recv_run, UDP recv echo);
|
UDPSocketRecv, UdpSocketRecvTask, UDP recv echo);
|
||||||
|
|
||||||
static void udp_send_demo(void *arg)
|
static void UdpSocketSendTask(void *arg)
|
||||||
{
|
{
|
||||||
int cnt = LWIP_DEMO_TIMES;
|
int cnt = LWIP_DEMO_TIMES;
|
||||||
char send_str[128];
|
char send_str[128];
|
||||||
|
|
||||||
lw_print("udp_send_demo start.\n");
|
lw_print("UdpSocketSendTask start.\n");
|
||||||
|
|
||||||
int socket_fd = -1;
|
int socket_fd = -1;
|
||||||
memset(send_str, 0, sizeof(send_str));
|
memset(send_str, 0, sizeof(send_str));
|
||||||
|
@ -182,14 +164,7 @@ __exit:
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void udp_send_demo_thread(void* param)
|
void UdpSocketSendTest(int argc, char *argv[])
|
||||||
{
|
|
||||||
ETH_BSP_Config();
|
|
||||||
lwip_config_tcp(lwip_ipaddr, lwip_netmask, lwip_gwaddr);
|
|
||||||
sys_thread_new("udp_send_demo", udp_send_demo, NULL, LWIP_UDP_TASK_STACK, LWIP_UDP_TASK_PRIO);
|
|
||||||
}
|
|
||||||
|
|
||||||
void udp_socket_send_run(int argc, char *argv[])
|
|
||||||
{
|
{
|
||||||
int result = 0;
|
int result = 0;
|
||||||
pthread_t th_id;
|
pthread_t th_id;
|
||||||
|
@ -201,9 +176,10 @@ void udp_socket_send_run(int argc, char *argv[])
|
||||||
sscanf(argv[1], "%d.%d.%d.%d", &udp_socket_ip[0], &udp_socket_ip[1], &udp_socket_ip[2], &udp_socket_ip[3]);
|
sscanf(argv[1], "%d.%d.%d.%d", &udp_socket_ip[0], &udp_socket_ip[1], &udp_socket_ip[2], &udp_socket_ip[3]);
|
||||||
}
|
}
|
||||||
|
|
||||||
sys_thread_new("udp socket send", udp_send_demo_thread, NULL, 4096, 15);
|
lwip_config_tcp(lwip_ipaddr, lwip_netmask, lwip_gwaddr);
|
||||||
|
sys_thread_new("UdpSocketSendTask", UdpSocketSendTask, NULL, LWIP_TASK_STACK_SIZE, LWIP_DEMO_TASK_PRIO);
|
||||||
}
|
}
|
||||||
|
|
||||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
||||||
UDPSocketSend, udp_socket_send_run, UDP send echo);
|
UDPSocketSend, UdpSocketSendTest, UDP send echo);
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@ SRC_DIR :=
|
||||||
ifeq ($(CONFIG_RESOURCES_LWIP),y)
|
ifeq ($(CONFIG_RESOURCES_LWIP),y)
|
||||||
|
|
||||||
ifeq ($(CONFIG_USING_CONTROL_PLC_OPCUA), y)
|
ifeq ($(CONFIG_USING_CONTROL_PLC_OPCUA), y)
|
||||||
SRC_DIR += opcua_demo
|
SRC_DIR += opcua_demo plc_demo
|
||||||
endif
|
endif
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -31,6 +31,8 @@
|
||||||
|
|
||||||
#define TCP_LOCAL_PORT 4840
|
#define TCP_LOCAL_PORT 4840
|
||||||
#define UA_URL_SIZE 100
|
#define UA_URL_SIZE 100
|
||||||
|
#define UA_STACK_SIZE 4096
|
||||||
|
#define UA_TASK_PRIO 15
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Prototypes
|
* Prototypes
|
||||||
|
@ -40,20 +42,18 @@
|
||||||
* Variables
|
* Variables
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
char test_ua_ip[] = {192, 168, 250, 5};
|
char test_ua_ip[] = {192, 168, 250, 2};
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* Code
|
* Code
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
static void test_ua_connect(void *arg)
|
static void UaConnectTestTask(void* arg)
|
||||||
{
|
{
|
||||||
struct netif net;
|
struct netif net;
|
||||||
UA_StatusCode retval;
|
UA_StatusCode retval;
|
||||||
char ua_uri[UA_URL_SIZE];
|
char ua_uri[UA_URL_SIZE];
|
||||||
|
|
||||||
memset(ua_uri, 0, sizeof(ua_uri));
|
memset(ua_uri, 0, sizeof(ua_uri));
|
||||||
|
|
||||||
UA_Client* client = UA_Client_new();
|
UA_Client* client = UA_Client_new();
|
||||||
|
|
||||||
if(client == NULL)
|
if(client == NULL)
|
||||||
|
@ -64,43 +64,35 @@ static void test_ua_connect(void *arg)
|
||||||
|
|
||||||
UA_ClientConfig* config = UA_Client_getConfig(client);
|
UA_ClientConfig* config = UA_Client_getConfig(client);
|
||||||
UA_ClientConfig_setDefault(config);
|
UA_ClientConfig_setDefault(config);
|
||||||
|
snprintf(ua_uri, sizeof(ua_uri), "opc.tcp://%d.%d.%d.%d:4840",
|
||||||
snprintf(ua_uri, UA_URL_SIZE, "opc.tcp://%d.%d.%d.%d:4840",
|
|
||||||
test_ua_ip[0], test_ua_ip[1], test_ua_ip[2], test_ua_ip[3]);
|
test_ua_ip[0], test_ua_ip[1], test_ua_ip[2], test_ua_ip[3]);
|
||||||
|
ua_pr_info("ua uri: %d %s\n", strlen(ua_uri), ua_uri);
|
||||||
retval = UA_Client_connect(client,ua_uri);
|
retval = UA_Client_connect(client,ua_uri);
|
||||||
|
|
||||||
if(retval != UA_STATUSCODE_GOOD)
|
if(retval != UA_STATUSCODE_GOOD)
|
||||||
{
|
{
|
||||||
ua_print("ua: [%s] ret %x\n", __func__, retval);
|
ua_pr_info("ua: [%s] connected failed %x\n", __func__, retval);
|
||||||
|
UA_Client_delete(client);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ua_print("ua: [%s] start Ua Test!\n", __func__);
|
ua_pr_info("ua: [%s] connected ok!\n", __func__);
|
||||||
UA_Client_disconnect(client);
|
UA_Client_disconnect(client);
|
||||||
UA_Client_delete(client);
|
UA_Client_delete(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
void test_ua_connect_thr(void *arg)
|
void UaConnectTest(void* arg)
|
||||||
{
|
{
|
||||||
ETH_BSP_Config();
|
|
||||||
lwip_config_tcp(lwip_ipaddr, lwip_netmask, test_ua_ip);
|
lwip_config_tcp(lwip_ipaddr, lwip_netmask, test_ua_ip);
|
||||||
test_ua_connect(NULL);
|
sys_thread_new("ua test", UaConnectTestTask, NULL, UA_STACK_SIZE, UA_TASK_PRIO);
|
||||||
}
|
|
||||||
|
|
||||||
void test_sh_ua_connect(void)
|
|
||||||
{
|
|
||||||
int result = 0;
|
|
||||||
pthread_t th_id;
|
|
||||||
pthread_attr_t attr;
|
|
||||||
sys_thread_new("ua test", test_ua_connect_thr, NULL, 4096, 15);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(0),
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(0),
|
||||||
UaConnect, test_sh_ua_connect, Test Opc UA connection);
|
UaConnect, UaConnectTest, Test Opc UA connection);
|
||||||
|
|
||||||
void test_ua_browser_objects(void *param)
|
void UaBrowserObjectsTestTask(void* param)
|
||||||
{
|
{
|
||||||
UA_Client* client = UA_Client_new();
|
UA_Client* client = UA_Client_new();
|
||||||
|
|
||||||
ua_pr_info("ua: [%s] start ...\n", __func__);
|
ua_pr_info("ua: [%s] start ...\n", __func__);
|
||||||
|
|
||||||
if(client == NULL)
|
if(client == NULL)
|
||||||
|
@ -111,9 +103,10 @@ void test_ua_browser_objects(void *param)
|
||||||
|
|
||||||
UA_ClientConfig* config = UA_Client_getConfig(client);
|
UA_ClientConfig* config = UA_Client_getConfig(client);
|
||||||
UA_ClientConfig_setDefault(config);
|
UA_ClientConfig_setDefault(config);
|
||||||
|
UA_StatusCode retval = UA_Client_connect(client, opc_server_url);
|
||||||
|
|
||||||
UA_StatusCode retval = UA_Client_connect(client, OPC_SERVER);
|
if(retval != UA_STATUSCODE_GOOD)
|
||||||
if(retval != UA_STATUSCODE_GOOD) {
|
{
|
||||||
ua_print("ua: [%s] connect failed %#x\n", __func__, retval);
|
ua_print("ua: [%s] connect failed %#x\n", __func__, retval);
|
||||||
UA_Client_delete(client);
|
UA_Client_delete(client);
|
||||||
return;
|
return;
|
||||||
|
@ -121,18 +114,15 @@ void test_ua_browser_objects(void *param)
|
||||||
|
|
||||||
ua_print("ua: [%s] connect ok!\n", __func__);
|
ua_print("ua: [%s] connect ok!\n", __func__);
|
||||||
ua_pr_info("--- start read time ---\n", __func__);
|
ua_pr_info("--- start read time ---\n", __func__);
|
||||||
|
|
||||||
ua_read_time(client);
|
ua_read_time(client);
|
||||||
|
|
||||||
ua_pr_info("--- get server info ---\n", __func__);
|
ua_pr_info("--- get server info ---\n", __func__);
|
||||||
ua_browser_objects(client);
|
ua_test_browser_objects(client);
|
||||||
|
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
UA_Client_disconnect(client);
|
UA_Client_disconnect(client);
|
||||||
UA_Client_delete(client); /* Disconnects the client internally */
|
UA_Client_delete(client); /* Disconnects the client internally */
|
||||||
}
|
}
|
||||||
|
|
||||||
void *test_sh_ua_brower_objects(int argc, char *argv[])
|
void* UaBrowserObjectsTest(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
if(argc == 2)
|
if(argc == 2)
|
||||||
{
|
{
|
||||||
|
@ -146,19 +136,17 @@ void *test_sh_ua_brower_objects(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ETH_BSP_Config();
|
|
||||||
lwip_config_tcp(lwip_ipaddr, lwip_netmask, test_ua_ip);
|
lwip_config_tcp(lwip_ipaddr, lwip_netmask, test_ua_ip);
|
||||||
sys_thread_new("ua object", test_ua_browser_objects, NULL, 4096, 15);
|
sys_thread_new("ua object", UaBrowserObjectsTestTask, NULL, UA_STACK_SIZE, UA_TASK_PRIO);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
||||||
UaObj, test_sh_ua_brower_objects, UaObj [IP]);
|
UaObj, UaBrowserObjectsTest, UaObj [IP]);
|
||||||
|
|
||||||
void test_ua_get_info(void *param)
|
void UaGetInfoTestTask(void* param)
|
||||||
{
|
{
|
||||||
UA_Client* client = UA_Client_new();
|
UA_Client* client = UA_Client_new();
|
||||||
|
|
||||||
ua_pr_info("ua: [%s] start ...\n", __func__);
|
ua_pr_info("ua: [%s] start ...\n", __func__);
|
||||||
|
|
||||||
if(client == NULL)
|
if(client == NULL)
|
||||||
|
@ -169,24 +157,24 @@ void test_ua_get_info(void *param)
|
||||||
|
|
||||||
UA_ClientConfig* config = UA_Client_getConfig(client);
|
UA_ClientConfig* config = UA_Client_getConfig(client);
|
||||||
UA_ClientConfig_setDefault(config);
|
UA_ClientConfig_setDefault(config);
|
||||||
|
UA_StatusCode retval = UA_Client_connect(client, opc_server_url);
|
||||||
|
|
||||||
UA_StatusCode retval = UA_Client_connect(client, OPC_SERVER);
|
if(retval != UA_STATUSCODE_GOOD)
|
||||||
if(retval != UA_STATUSCODE_GOOD) {
|
{
|
||||||
ua_print("ua: [%s] connect failed %#x\n", __func__, retval);
|
ua_print("ua: [%s] connect failed %#x\n", __func__, retval);
|
||||||
UA_Client_delete(client);
|
UA_Client_delete(client);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ua_print("ua: [%s] connect ok!\n", __func__);
|
ua_print("ua: [%s] connect ok!\n", __func__);
|
||||||
ua_pr_info("--- get server info ---\n", __func__);
|
ua_pr_info("--- interactive server ---\n", __func__);
|
||||||
ua_get_server_info(client);
|
ua_test_interact_server(client);
|
||||||
|
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
UA_Client_disconnect(client);
|
UA_Client_disconnect(client);
|
||||||
UA_Client_delete(client); /* Disconnects the client internally */
|
UA_Client_delete(client); /* Disconnects the client internally */
|
||||||
}
|
}
|
||||||
|
|
||||||
void *test_sh_ua_get_info(int argc, char *argv[])
|
void* UaGetInfoTest(int argc, char* argv[])
|
||||||
{
|
{
|
||||||
if(argc == 2)
|
if(argc == 2)
|
||||||
{
|
{
|
||||||
|
@ -200,12 +188,63 @@ void *test_sh_ua_get_info(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ETH_BSP_Config();
|
|
||||||
lwip_config_tcp(lwip_ipaddr, lwip_netmask, test_ua_ip);
|
lwip_config_tcp(lwip_ipaddr, lwip_netmask, test_ua_ip);
|
||||||
sys_thread_new("ua object", test_ua_browser_objects, NULL, 4096, 15);
|
sys_thread_new("ua info", UaGetInfoTestTask, NULL, UA_STACK_SIZE, UA_TASK_PRIO);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
||||||
UaInfo, test_sh_ua_get_info, UaInfo [IP]);
|
UaInfo, UaGetInfoTest, UaInfo [IP]);
|
||||||
|
|
||||||
|
void UaAddNodesTask(void* param)
|
||||||
|
{
|
||||||
|
UA_Client* client = UA_Client_new();
|
||||||
|
ua_pr_info("ua: [%s] start ...\n", __func__);
|
||||||
|
|
||||||
|
if(client == NULL)
|
||||||
|
{
|
||||||
|
ua_print("ua: [%s] tcp client null\n", __func__);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UA_ClientConfig* config = UA_Client_getConfig(client);
|
||||||
|
UA_ClientConfig_setDefault(config);
|
||||||
|
UA_StatusCode retval = UA_Client_connect(client, opc_server_url);
|
||||||
|
|
||||||
|
if(retval != UA_STATUSCODE_GOOD)
|
||||||
|
{
|
||||||
|
ua_print("ua: [%s] connect failed %#x\n", __func__, retval);
|
||||||
|
UA_Client_delete(client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ua_print("ua: [%s] connect ok!\n", __func__);
|
||||||
|
ua_pr_info("--- add nodes ---\n", __func__);
|
||||||
|
ua_add_nodes(client);
|
||||||
|
/* Clean up */
|
||||||
|
UA_Client_disconnect(client);
|
||||||
|
UA_Client_delete(client); /* Disconnects the client internally */
|
||||||
|
}
|
||||||
|
|
||||||
|
void* UaAddNodesTest(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
if(argc == 2)
|
||||||
|
{
|
||||||
|
if(isdigit(argv[1][0]))
|
||||||
|
{
|
||||||
|
if(sscanf(argv[1], "%d.%d.%d.%d", &test_ua_ip[0], &test_ua_ip[1], &test_ua_ip[2], &test_ua_ip[3]) == EOF)
|
||||||
|
{
|
||||||
|
lw_pr_info("input wrong ip\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
lwip_config_tcp(lwip_ipaddr, lwip_netmask, test_ua_ip);
|
||||||
|
sys_thread_new("ua add nodes", UaAddNodesTask, NULL, UA_STACK_SIZE, UA_TASK_PRIO);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
||||||
|
UaAdd, UaAddNodesTest, UA Add Nodes);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,3 @@
|
||||||
|
SRC_FILES := plc_show_demo.c plc_control_demo.c
|
||||||
|
|
||||||
|
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -0,0 +1,221 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 AIIT XUOS Lab
|
||||||
|
* XiUOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file plc_control_demo.c
|
||||||
|
* @brief Demo for PLC control
|
||||||
|
* @version 1.0
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2022.2.22
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "transform.h"
|
||||||
|
#include "open62541.h"
|
||||||
|
#include "ua_api.h"
|
||||||
|
#include "sys_arch.h"
|
||||||
|
#include "plc_demo.h"
|
||||||
|
|
||||||
|
#define PLC_NS_FORMAT "n%d,%s"
|
||||||
|
|
||||||
|
struct PlcChannel plc_demo_ch;
|
||||||
|
struct PlcDriver plc_demo_drv;
|
||||||
|
struct PlcDevice plc_demo_dev;
|
||||||
|
|
||||||
|
PlcCtrlParamType plc_ctrl_param;
|
||||||
|
|
||||||
|
UA_NodeId test_nodeid = {4, UA_NODEIDTYPE_NUMERIC, 5};
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
void PlcDemoChannelDrvInit(void)
|
||||||
|
{
|
||||||
|
static uint8_t init_flag = 0;
|
||||||
|
if(init_flag)
|
||||||
|
return;
|
||||||
|
init_flag = 1;
|
||||||
|
|
||||||
|
lwip_config_tcp(lwip_ipaddr, lwip_netmask, test_ua_ip);
|
||||||
|
PlcChannelInit(&plc_demo_ch, PLC_CH_NAME);
|
||||||
|
if(PlcDriverInit(&plc_demo_drv, PLC_DRV_NAME) == EOK)
|
||||||
|
{
|
||||||
|
PlcDriverAttachToChannel(PLC_DRV_NAME, PLC_CH_NAME);
|
||||||
|
}
|
||||||
|
memset(&plc_demo_dev, 0, sizeof(plc_demo_dev));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PlcCtrlDemoInit(void)
|
||||||
|
{
|
||||||
|
static uint8_t init_flag = 0;
|
||||||
|
|
||||||
|
PlcDemoChannelDrvInit();
|
||||||
|
// register plc device
|
||||||
|
plc_demo_dev.state = CHDEV_INIT;
|
||||||
|
strcpy(plc_demo_dev.name, "UA Demo");
|
||||||
|
plc_demo_dev.info.product = "CPU 1215C";
|
||||||
|
plc_demo_dev.info.vendor = "SIEMENS";
|
||||||
|
plc_demo_dev.info.model = "S7-1200";
|
||||||
|
plc_demo_dev.info.id = 123;
|
||||||
|
plc_demo_dev.net = PLC_IND_ENET_OPCUA;
|
||||||
|
|
||||||
|
// register UA parameter
|
||||||
|
if(!plc_demo_dev.priv_data)
|
||||||
|
{
|
||||||
|
plc_demo_dev.priv_data = (UaParamType*)malloc(sizeof(UaParamType));
|
||||||
|
}
|
||||||
|
UaParamType* ua_ptr = plc_demo_dev.priv_data;
|
||||||
|
memset(ua_ptr, 0, sizeof(UaParamType));
|
||||||
|
strcpy(ua_ptr->ua_remote_ip, opc_server_url);
|
||||||
|
ua_ptr->act = UA_ACT_ATTR;
|
||||||
|
memcpy(&ua_ptr->ua_id, &test_nodeid, sizeof(test_nodeid));
|
||||||
|
|
||||||
|
if(init_flag)
|
||||||
|
return;
|
||||||
|
init_flag = 1;
|
||||||
|
|
||||||
|
if(PlcDevRegister(&plc_demo_dev, NULL, plc_demo_dev.name) != EOK)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
PlcDeviceAttachToChannel(plc_demo_dev.name, PLC_CH_NAME);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlcReadUATask(void* arg)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct PlcOps* ops = NULL;
|
||||||
|
char buf[PLC_BUF_SIZE];
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
PlcCtrlDemoInit();
|
||||||
|
ops = plc_demo_dev.ops;
|
||||||
|
ret = ops->open(&plc_demo_dev);
|
||||||
|
|
||||||
|
if(EOK != ret)
|
||||||
|
{
|
||||||
|
plc_print("plc: [%s] open failed %#x\n", __func__, ret);
|
||||||
|
// free(plc_demo_dev.priv_data);
|
||||||
|
// plc_demo_dev.priv_data = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ops->read(&plc_demo_dev, buf, PLC_BUF_SIZE);
|
||||||
|
|
||||||
|
if(EOK != ret)
|
||||||
|
{
|
||||||
|
plc_print("plc: [%s] read failed %x\n", __func__, ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
ops->close(&plc_demo_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlcReadTest(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
static char node_str[UA_NODE_LEN];
|
||||||
|
memset(node_str, 0, sizeof(node_str));
|
||||||
|
|
||||||
|
if(argc > 1)
|
||||||
|
{
|
||||||
|
plc_print("plc: arg %s\n", argv[1]);
|
||||||
|
|
||||||
|
if(sscanf(argv[1], PLC_NS_FORMAT, &test_nodeid.namespaceIndex, node_str) != EOF)
|
||||||
|
{
|
||||||
|
if(isdigit(node_str[0]))
|
||||||
|
{
|
||||||
|
test_nodeid.identifierType = UA_NODEIDTYPE_NUMERIC;
|
||||||
|
test_nodeid.identifier.numeric = atoi(node_str);
|
||||||
|
plc_print("ns %d num %d\n", test_nodeid.namespaceIndex, test_nodeid.identifier.numeric);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
test_nodeid.identifierType = UA_NODEIDTYPE_STRING;
|
||||||
|
test_nodeid.identifier.string.length = strlen(node_str);
|
||||||
|
test_nodeid.identifier.string.data = node_str;
|
||||||
|
plc_print("ns %d str %s\n", test_nodeid.namespaceIndex, test_nodeid.identifier.string.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sys_thread_new("plc read", PlcReadUATask, NULL, PLC_STACK_SIZE, PLC_TASK_PRIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
||||||
|
PlcRead, PlcReadTest, Read PLC);
|
||||||
|
|
||||||
|
void PlcWriteUATask(void* arg)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
struct PlcOps* ops = NULL;
|
||||||
|
char buf[PLC_BUF_SIZE];
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
|
||||||
|
PlcCtrlDemoInit();
|
||||||
|
ops = plc_demo_dev.ops;
|
||||||
|
ret = ops->open(&plc_demo_dev);
|
||||||
|
|
||||||
|
if(EOK != ret)
|
||||||
|
{
|
||||||
|
plc_print("plc: [%s] open failed %#x\n", __func__, ret);
|
||||||
|
// free(plc_demo_dev.priv_data);
|
||||||
|
// plc_demo_dev.priv_data = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ret = ops->write(&plc_demo_dev, arg, PLC_BUF_SIZE);
|
||||||
|
|
||||||
|
if(EOK != ret)
|
||||||
|
{
|
||||||
|
plc_print("plc: [%s] read failed\n", __func__);
|
||||||
|
}
|
||||||
|
|
||||||
|
ops->close(&plc_demo_dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlcWriteTest(int argc, char* argv[])
|
||||||
|
{
|
||||||
|
static char node_str[UA_NODE_LEN];
|
||||||
|
static char val_param[UA_NODE_LEN];
|
||||||
|
memset(node_str, 0, sizeof(node_str));
|
||||||
|
memset(val_param, 0, sizeof(val_param));
|
||||||
|
|
||||||
|
if(argc > 1)
|
||||||
|
{
|
||||||
|
plc_print("plc: arg %s\n", argv[1]);
|
||||||
|
|
||||||
|
if(sscanf(argv[1], PLC_NS_FORMAT, &test_nodeid.namespaceIndex, node_str) != EOF)
|
||||||
|
{
|
||||||
|
if(isdigit(node_str[0]))
|
||||||
|
{
|
||||||
|
test_nodeid.identifierType = UA_NODEIDTYPE_NUMERIC;
|
||||||
|
test_nodeid.identifier.numeric = atoi(node_str);
|
||||||
|
plc_print("ns %d num %d\n", test_nodeid.namespaceIndex, test_nodeid.identifier.numeric);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
test_nodeid.identifierType = UA_NODEIDTYPE_STRING;
|
||||||
|
test_nodeid.identifier.string.length = strlen(node_str);
|
||||||
|
test_nodeid.identifier.string.data = node_str;
|
||||||
|
plc_print("ns %d str %s\n", test_nodeid.namespaceIndex, test_nodeid.identifier.string.data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(argc > 2)
|
||||||
|
{
|
||||||
|
strcpy(val_param, argv[2]);
|
||||||
|
plc_print("write value %s\n", val_param);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sys_thread_new("plc write", PlcWriteUATask, val_param, PLC_STACK_SIZE, PLC_TASK_PRIO);
|
||||||
|
}
|
||||||
|
|
||||||
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
||||||
|
PlcWrite, PlcWriteTest, Read PLC);
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 AIIT XUOS Lab
|
||||||
|
* XiUOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file plc_show_demo.c
|
||||||
|
* @brief Demo for PLC information show
|
||||||
|
* @version 1.0
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2022.02.24
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PLC_DEMO_H_
|
||||||
|
#define __PLC_DEMO_H_
|
||||||
|
|
||||||
|
#include "plc_channel.h"
|
||||||
|
#include "plc_device.h"
|
||||||
|
|
||||||
|
#define PLC_CH_NAME "PLC"
|
||||||
|
#define PLC_DRV_NAME "OPCUA"
|
||||||
|
|
||||||
|
#define PLC_BUF_SIZE 128
|
||||||
|
|
||||||
|
#define PLC_STACK_SIZE 4096
|
||||||
|
#define PLC_TASK_PRIO 15
|
||||||
|
|
||||||
|
extern struct PlcChannel plc_demo_ch;
|
||||||
|
extern struct PlcDriver plc_demo_drv;
|
||||||
|
extern struct PlcDevice plc_demo_dev;
|
||||||
|
|
||||||
|
void PlcDemoChannelDrvInit(void);
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,257 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 AIIT XUOS Lab
|
||||||
|
* XiUOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file plc_show_demo.c
|
||||||
|
* @brief Demo for PLC information show
|
||||||
|
* @version 1.0
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2022.02.24
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "transform.h"
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
#include "open62541.h"
|
||||||
|
#include "ua_api.h"
|
||||||
|
#include "sys_arch.h"
|
||||||
|
#include "plc_demo.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define PLC_DEMO_NUM 5
|
||||||
|
|
||||||
|
struct PlcDevice plc_demo_array[PLC_DEMO_NUM];
|
||||||
|
|
||||||
|
typedef struct PlcShowParam
|
||||||
|
{
|
||||||
|
int id;
|
||||||
|
char* vector;
|
||||||
|
char* model;
|
||||||
|
char* product;
|
||||||
|
} PlcShowParamType;
|
||||||
|
|
||||||
|
PlcShowParamType plc_demo_param[PLC_NAME_SIZE] =
|
||||||
|
{
|
||||||
|
{1, "SIEMENS", "S7-1500", "CPU 1512SP-1PN"},
|
||||||
|
{2, "SIEMENS", "S7-1200", "CPU 1215C"},
|
||||||
|
{3, "SIEMSNS", "S7-200", "CPU SR60"},
|
||||||
|
{4, "B&R", "X20", "X20 CP1586"},
|
||||||
|
{5, "B&R", "X20", "X20 CP1381"}
|
||||||
|
};
|
||||||
|
|
||||||
|
static char* const channel_type_str[] =
|
||||||
|
{
|
||||||
|
"PLC_Channel",
|
||||||
|
"Unknown"
|
||||||
|
};
|
||||||
|
|
||||||
|
extern DoublelistType plcdev_list;
|
||||||
|
extern DoublelistType ch_linklist;
|
||||||
|
|
||||||
|
/**********************************************************************************************************************/
|
||||||
|
|
||||||
|
void PlcShowTitle(const char* item_array[])
|
||||||
|
{
|
||||||
|
int i = 0, max_len = 65;
|
||||||
|
KPrintf(" %-15s%-15s%-15s%-15s%-20s\n", item_array[0], item_array[1], item_array[2], item_array[3], item_array[4]);
|
||||||
|
|
||||||
|
while(i < max_len)
|
||||||
|
{
|
||||||
|
i++;
|
||||||
|
|
||||||
|
if(max_len == i)
|
||||||
|
{
|
||||||
|
KPrintf("-\n");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KPrintf("-");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static ChDrvType ShowChannelFindDriver(struct Channel* ch)
|
||||||
|
{
|
||||||
|
struct ChDrv* driver = NONE;
|
||||||
|
DoublelistType* node = NONE;
|
||||||
|
DoublelistType* head = &ch->ch_drvlink;
|
||||||
|
|
||||||
|
for(node = head->node_next; node != head; node = node->node_next)
|
||||||
|
{
|
||||||
|
driver = DOUBLE_LIST_ENTRY(node, struct ChDrv, driver_link);
|
||||||
|
return driver;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PlcShowDemoInit(void)
|
||||||
|
{
|
||||||
|
static uint8_t init_flag = 0;
|
||||||
|
int i;
|
||||||
|
PlcDemoChannelDrvInit();
|
||||||
|
|
||||||
|
for(i = 0; i < PLC_DEMO_NUM; i++)
|
||||||
|
{
|
||||||
|
// register plc device
|
||||||
|
plc_demo_array[i].state = CHDEV_INIT;
|
||||||
|
snprintf(plc_demo_array[i].name, PLC_NAME_SIZE, "PLC Demo %d", i);
|
||||||
|
plc_demo_array[i].info.vendor = plc_demo_param[i].vector;
|
||||||
|
plc_demo_array[i].info.model = plc_demo_param[i].model;
|
||||||
|
plc_demo_array[i].info.id = plc_demo_param[i].id;
|
||||||
|
plc_demo_array[i].info.product = plc_demo_param[i].product;
|
||||||
|
plc_demo_array[i].net = PLC_IND_ENET_OPCUA;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(init_flag)
|
||||||
|
return;
|
||||||
|
init_flag = 1;
|
||||||
|
|
||||||
|
for(i = 0; i < PLC_DEMO_NUM; i++)
|
||||||
|
{
|
||||||
|
if(PlcDevRegister(&plc_demo_array[i], NULL, plc_demo_array[i].name) == EOK)
|
||||||
|
{
|
||||||
|
PlcDeviceAttachToChannel(plc_demo_array[i].name, PLC_CH_NAME);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void PlcShowChannel(void)
|
||||||
|
{
|
||||||
|
ChannelType ch;
|
||||||
|
ChDrvType driver;
|
||||||
|
ChDevType device;
|
||||||
|
int dev_cnt;
|
||||||
|
DoublelistType* ch_node = NONE;
|
||||||
|
DoublelistType* ch_head = &ch_linklist;
|
||||||
|
const char* item_array[] = {"ch_type", "ch_name", "drv_name", "dev_name", "cnt"};
|
||||||
|
PlcShowDemoInit();
|
||||||
|
PlcShowTitle(item_array);
|
||||||
|
ch_node = ch_head->node_next;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ch = DOUBLE_LIST_ENTRY(ch_node, struct Channel, ch_link);
|
||||||
|
|
||||||
|
if((ch) && (ch->ch_type == CH_PLC_TYPE))
|
||||||
|
{
|
||||||
|
KPrintf("%s", " ");
|
||||||
|
KPrintf("%-15s%-15s",
|
||||||
|
channel_type_str[ch->ch_type],
|
||||||
|
ch->ch_name);
|
||||||
|
|
||||||
|
driver = ShowChannelFindDriver(ch);
|
||||||
|
|
||||||
|
if(driver)
|
||||||
|
{
|
||||||
|
KPrintf("%-15s", driver->drv_name);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KPrintf("%-15s", "nil");
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ch->haldev_cnt)
|
||||||
|
{
|
||||||
|
DoublelistType* dev_node = NONE;
|
||||||
|
DoublelistType* dev_head = &ch->ch_devlink;
|
||||||
|
dev_node = dev_head->node_next;
|
||||||
|
dev_cnt = 1;
|
||||||
|
|
||||||
|
while(dev_node != dev_head)
|
||||||
|
{
|
||||||
|
device = DOUBLE_LIST_ENTRY(dev_node, struct ChDev, dev_link);
|
||||||
|
|
||||||
|
if(1 == dev_cnt)
|
||||||
|
{
|
||||||
|
if(device)
|
||||||
|
{
|
||||||
|
KPrintf("%-16s%-4d\n", device->dev_name, dev_cnt);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KPrintf("%-16s%-4d\n", "nil", dev_cnt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KPrintf("%46s", " ");
|
||||||
|
|
||||||
|
if(device)
|
||||||
|
{
|
||||||
|
KPrintf("%-16s%-4d\n", device->dev_name, dev_cnt);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KPrintf("%-16s%-4d\n", "nil", dev_cnt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dev_cnt++;
|
||||||
|
dev_node = dev_node->node_next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KPrintf("\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ch_node = ch_node->node_next;
|
||||||
|
}
|
||||||
|
while(ch_node != ch_head);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
||||||
|
ShowChannel, PlcShowChannel, Show PLC information);
|
||||||
|
|
||||||
|
void PlcShowDev(void)
|
||||||
|
{
|
||||||
|
PlcDeviceType* plc_dev;
|
||||||
|
ChDrvType driver;
|
||||||
|
ChDevType device;
|
||||||
|
DoublelistType* plc_node = NONE;
|
||||||
|
DoublelistType* plc_head = &plcdev_list;
|
||||||
|
const char* item_array[] = {"device", "vendor", "model", "product", "id"};
|
||||||
|
PlcShowDemoInit();
|
||||||
|
PlcShowTitle(item_array);
|
||||||
|
plc_node = plc_head->node_next;
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
plc_dev = DOUBLE_LIST_ENTRY(plc_node, struct PlcDevice, link);
|
||||||
|
|
||||||
|
if(plc_dev)
|
||||||
|
{
|
||||||
|
KPrintf("%s", " ");
|
||||||
|
KPrintf("%-15s%-15s%-15s%-15s%-20d",
|
||||||
|
plc_dev->name,
|
||||||
|
plc_dev->info.vendor,
|
||||||
|
plc_dev->info.model,
|
||||||
|
plc_dev->info.product,
|
||||||
|
plc_dev->info.id);
|
||||||
|
KPrintf("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
plc_node = plc_node->node_next;
|
||||||
|
}
|
||||||
|
while(plc_node != plc_head);
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(3),
|
||||||
|
ShowPlc, PlcShowDev, Show PLC information);
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
menuconfig USING_EMBEDDED_DATABASE_APP
|
||||||
|
bool "embedded database app"
|
||||||
|
default n
|
||||||
|
if USING_EMBEDDED_DATABASE_APP
|
||||||
|
source "$APP_DIR/Applications/embedded_database_app/flashdb_app/Kconfig"
|
||||||
|
endif
|
|
@ -0,0 +1,14 @@
|
||||||
|
import os
|
||||||
|
Import('RTT_ROOT')
|
||||||
|
from building import *
|
||||||
|
|
||||||
|
cwd = GetCurrentDir()
|
||||||
|
objs = []
|
||||||
|
list = os.listdir(cwd)
|
||||||
|
|
||||||
|
for d in list:
|
||||||
|
path = os.path.join(cwd, d)
|
||||||
|
if os.path.isfile(os.path.join(path, 'SConscript')):
|
||||||
|
objs = objs + SConscript(os.path.join(path, 'SConscript'))
|
||||||
|
|
||||||
|
Return('objs')
|
|
@ -0,0 +1,5 @@
|
||||||
|
config EMBEDDED_DATABASE_FLASHDB_APP
|
||||||
|
bool "embedded database apps/flashdb(example)"
|
||||||
|
select USING_EMBEDDED_DATABASE
|
||||||
|
select USING_EMBEDDED_DATABASE_FLASHDB
|
||||||
|
default n
|
|
@ -0,0 +1,9 @@
|
||||||
|
from building import *
|
||||||
|
|
||||||
|
cwd = GetCurrentDir()
|
||||||
|
src = Glob('*.c') + Glob('*.cpp')
|
||||||
|
CPPPATH = [cwd]
|
||||||
|
|
||||||
|
group = DefineGroup('flashdb(example)', src, depend = ['EMBEDDED_DATABASE_FLASHDB_APP'], LOCAL_CPPPATH = CPPPATH)
|
||||||
|
|
||||||
|
Return('group')
|
|
@ -0,0 +1,129 @@
|
||||||
|
#include <transform.h>
|
||||||
|
#include <flashdb.h>
|
||||||
|
#define FDB_LOG_TAG "[flashdb_app]"
|
||||||
|
static pthread_mutex_t kv_locker, ts_locker;
|
||||||
|
static uint32_t boot_count = 0;
|
||||||
|
static time_t boot_time[10] = {0, 1, 2, 3};
|
||||||
|
/* default KV nodes */
|
||||||
|
static struct fdb_default_kv_node default_kv_table[] = {
|
||||||
|
{"username", "armink", 0}, /* string KV */
|
||||||
|
{"password", "123456", 0}, /* string KV */
|
||||||
|
{"boot_count", &boot_count, sizeof(boot_count)}, /* int type KV */
|
||||||
|
{"boot_time", &boot_time, sizeof(boot_time)}, /* int array type KV */
|
||||||
|
};
|
||||||
|
/* KVDB object */
|
||||||
|
static struct fdb_kvdb kvdb = { 0 };
|
||||||
|
/* TSDB object */
|
||||||
|
struct fdb_tsdb tsdb = { 0 };
|
||||||
|
/* counts for simulated timestamp */
|
||||||
|
static int counts = 0;
|
||||||
|
|
||||||
|
extern void kvdb_basic_sample(fdb_kvdb_t kvdb);
|
||||||
|
extern void kvdb_type_string_sample(fdb_kvdb_t kvdb);
|
||||||
|
extern void kvdb_type_blob_sample(fdb_kvdb_t kvdb);
|
||||||
|
extern void tsdb_sample(fdb_tsdb_t tsdb);
|
||||||
|
|
||||||
|
static void lock(fdb_db_t db)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock((pthread_mutex_t *)db->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void unlock(fdb_db_t db)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock((pthread_mutex_t *)db->user_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
static fdb_time_t get_time(void)
|
||||||
|
{
|
||||||
|
return time(NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
int flashdb_app(void)
|
||||||
|
{
|
||||||
|
fdb_err_t result;
|
||||||
|
bool file_mode = true;
|
||||||
|
uint32_t sec_size = 4096, db_size = sec_size * 4;
|
||||||
|
|
||||||
|
#ifdef FDB_USING_KVDB
|
||||||
|
{ /* KVDB Sample */
|
||||||
|
struct fdb_default_kv default_kv;
|
||||||
|
|
||||||
|
default_kv.kvs = default_kv_table;
|
||||||
|
default_kv.num = sizeof(default_kv_table) / sizeof(default_kv_table[0]);
|
||||||
|
/* set the lock and unlock function if you want */
|
||||||
|
pthread_mutex_init(&kv_locker, NULL);
|
||||||
|
fdb_kvdb_control(&kvdb, FDB_KVDB_CTRL_SET_LOCK, (void *)lock);
|
||||||
|
fdb_kvdb_control(&kvdb, FDB_KVDB_CTRL_SET_UNLOCK, (void *)unlock);
|
||||||
|
/* set the sector and database max size */
|
||||||
|
fdb_kvdb_control(&kvdb, FDB_KVDB_CTRL_SET_SEC_SIZE, &sec_size);
|
||||||
|
fdb_kvdb_control(&kvdb, FDB_KVDB_CTRL_SET_MAX_SIZE, &db_size);
|
||||||
|
/* enable file mode */
|
||||||
|
fdb_kvdb_control(&kvdb, FDB_KVDB_CTRL_SET_FILE_MODE, &file_mode);
|
||||||
|
/* create database directory */
|
||||||
|
mkdir("fdb_kvdb1", 0777);
|
||||||
|
/* Key-Value database initialization
|
||||||
|
*
|
||||||
|
* &kvdb: database object
|
||||||
|
* "env": database name
|
||||||
|
* "fdb_kvdb1": The flash partition name base on FAL. Please make sure it's in FAL partition table.
|
||||||
|
* Please change to YOUR partition name.
|
||||||
|
* &default_kv: The default KV nodes. It will auto add to KVDB when first initialize successfully.
|
||||||
|
* &kv_locker: The locker object.
|
||||||
|
*/
|
||||||
|
result = fdb_kvdb_init(&kvdb, "env", "fdb_kvdb1", &default_kv, &kv_locker);
|
||||||
|
|
||||||
|
if (result != FDB_NO_ERR) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* run basic KV samples */
|
||||||
|
kvdb_basic_sample(&kvdb);
|
||||||
|
/* run string KV samples */
|
||||||
|
kvdb_type_string_sample(&kvdb);
|
||||||
|
/* run blob KV samples */
|
||||||
|
kvdb_type_blob_sample(&kvdb);
|
||||||
|
}
|
||||||
|
#endif /* FDB_USING_KVDB */
|
||||||
|
|
||||||
|
#ifdef FDB_USING_TSDB
|
||||||
|
{ /* TSDB Sample */
|
||||||
|
/* set the lock and unlock function if you want */
|
||||||
|
pthread_mutex_init(&ts_locker, NULL);
|
||||||
|
fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_SET_LOCK, (void *)lock);
|
||||||
|
fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_SET_UNLOCK, (void *)unlock);
|
||||||
|
/* set the sector and database max size */
|
||||||
|
fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_SET_SEC_SIZE, &sec_size);
|
||||||
|
fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_SET_MAX_SIZE, &db_size);
|
||||||
|
/* enable file mode */
|
||||||
|
fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_SET_FILE_MODE, &file_mode);
|
||||||
|
/* create database directory */
|
||||||
|
mkdir("fdb_tsdb1", 0777);
|
||||||
|
/* Time series database initialization
|
||||||
|
*
|
||||||
|
* &tsdb: database object
|
||||||
|
* "log": database name
|
||||||
|
* "fdb_tsdb1": The flash partition name base on FAL. Please make sure it's in FAL partition table.
|
||||||
|
* Please change to YOUR partition name.
|
||||||
|
* get_time: The get current timestamp function.
|
||||||
|
* 128: maximum length of each log
|
||||||
|
* ts_locker: The locker object.
|
||||||
|
*/
|
||||||
|
result = fdb_tsdb_init(&tsdb, "log", "fdb_tsdb1", get_time, 128, &ts_locker);
|
||||||
|
/* read last saved time for simulated timestamp */
|
||||||
|
fdb_tsdb_control(&tsdb, FDB_TSDB_CTRL_GET_LAST_TIME, &counts);
|
||||||
|
|
||||||
|
if (result != FDB_NO_ERR) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* run TSDB sample */
|
||||||
|
tsdb_sample(&tsdb);
|
||||||
|
}
|
||||||
|
#endif /* FDB_USING_TSDB */
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __RT_THREAD_H__
|
||||||
|
MSH_CMD_EXPORT(flashdb_app, flashdb test);
|
||||||
|
#endif
|
|
@ -0,0 +1,50 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief basic KV samples.
|
||||||
|
*
|
||||||
|
* basic Key-Value Database KV feature samples
|
||||||
|
* get and show currnet boot counts
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <flashdb.h>
|
||||||
|
|
||||||
|
#ifdef FDB_USING_KVDB
|
||||||
|
|
||||||
|
#define FDB_LOG_TAG "[sample][kvdb][basic]"
|
||||||
|
|
||||||
|
void kvdb_basic_sample(fdb_kvdb_t kvdb)
|
||||||
|
{
|
||||||
|
struct fdb_blob blob;
|
||||||
|
int boot_count = 0;
|
||||||
|
|
||||||
|
FDB_INFO("==================== kvdb_basic_sample ====================\n");
|
||||||
|
|
||||||
|
{ /* GET the KV value */
|
||||||
|
/* get the "boot_count" KV value */
|
||||||
|
fdb_kv_get_blob(kvdb, "boot_count", fdb_blob_make(&blob, &boot_count, sizeof(boot_count)));
|
||||||
|
/* the blob.saved.len is more than 0 when get the value successful */
|
||||||
|
if (blob.saved.len > 0) {
|
||||||
|
FDB_INFO("get the 'boot_count' value is %d\n", boot_count);
|
||||||
|
} else {
|
||||||
|
FDB_INFO("get the 'boot_count' failed\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /* CHANGE the KV value */
|
||||||
|
/* increase the boot count */
|
||||||
|
boot_count ++;
|
||||||
|
/* change the "boot_count" KV's value */
|
||||||
|
fdb_kv_set_blob(kvdb, "boot_count", fdb_blob_make(&blob, &boot_count, sizeof(boot_count)));
|
||||||
|
FDB_INFO("set the 'boot_count' value to %d\n", boot_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
FDB_INFO("===========================================================\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* FDB_USING_KVDB */
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief blob KV samples.
|
||||||
|
*
|
||||||
|
* Key-Value Database blob type KV feature samples
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <flashdb.h>
|
||||||
|
|
||||||
|
#ifdef FDB_USING_KVDB
|
||||||
|
|
||||||
|
#define FDB_LOG_TAG "[sample][kvdb][blob]"
|
||||||
|
|
||||||
|
void kvdb_type_blob_sample(fdb_kvdb_t kvdb)
|
||||||
|
{
|
||||||
|
struct fdb_blob blob;
|
||||||
|
|
||||||
|
FDB_INFO("==================== kvdb_type_blob_sample ====================\n");
|
||||||
|
|
||||||
|
{ /* CREATE new Key-Value */
|
||||||
|
int temp_data = 36;
|
||||||
|
|
||||||
|
/* It will create new KV node when "temp" KV not in database.
|
||||||
|
* fdb_blob_make: It's a blob make function, and it will return the blob when make finish.
|
||||||
|
*/
|
||||||
|
fdb_kv_set_blob(kvdb, "temp", fdb_blob_make(&blob, &temp_data, sizeof(temp_data)));
|
||||||
|
FDB_INFO("create the 'temp' blob KV, value is: %d\n", temp_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /* GET the KV value */
|
||||||
|
int temp_data = 0;
|
||||||
|
|
||||||
|
/* get the "temp" KV value */
|
||||||
|
fdb_kv_get_blob(kvdb, "temp", fdb_blob_make(&blob, &temp_data, sizeof(temp_data)));
|
||||||
|
/* the blob.saved.len is more than 0 when get the value successful */
|
||||||
|
if (blob.saved.len > 0) {
|
||||||
|
FDB_INFO("get the 'temp' value is: %d\n", temp_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /* CHANGE the KV value */
|
||||||
|
int temp_data = 38;
|
||||||
|
|
||||||
|
/* change the "temp" KV's value to 38 */
|
||||||
|
fdb_kv_set_blob(kvdb, "temp", fdb_blob_make(&blob, &temp_data, sizeof(temp_data)));
|
||||||
|
FDB_INFO("set 'temp' value to %d\n", temp_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /* DELETE the KV by name */
|
||||||
|
fdb_kv_del(kvdb, "temp");
|
||||||
|
FDB_INFO("delete the 'temp' finish\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
FDB_INFO("===========================================================\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* FDB_USING_KVDB */
|
|
@ -0,0 +1,63 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief string KV samples.
|
||||||
|
*
|
||||||
|
* Key-Value Database string type KV feature samples source file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <flashdb.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef FDB_USING_KVDB
|
||||||
|
|
||||||
|
#define FDB_LOG_TAG "[sample][kvdb][string]"
|
||||||
|
|
||||||
|
void kvdb_type_string_sample(fdb_kvdb_t kvdb)
|
||||||
|
{
|
||||||
|
FDB_INFO("==================== kvdb_type_string_sample ====================\n");
|
||||||
|
|
||||||
|
{ /* CREATE new Key-Value */
|
||||||
|
char temp_data[10] = "36C";
|
||||||
|
|
||||||
|
/* It will create new KV node when "temp" KV not in database. */
|
||||||
|
fdb_kv_set(kvdb, "temp", temp_data);
|
||||||
|
FDB_INFO("create the 'temp' string KV, value is: %s\n", temp_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /* GET the KV value */
|
||||||
|
char *return_value, temp_data[10] = { 0 };
|
||||||
|
|
||||||
|
/* Get the "temp" KV value.
|
||||||
|
* NOTE: The return value saved in fdb_kv_get's buffer. Please copy away as soon as possible.
|
||||||
|
*/
|
||||||
|
return_value = fdb_kv_get(kvdb, "temp");
|
||||||
|
/* the return value is NULL when get the value failed */
|
||||||
|
if (return_value != NULL) {
|
||||||
|
strncpy(temp_data, return_value, sizeof(temp_data));
|
||||||
|
FDB_INFO("get the 'temp' value is: %s\n", temp_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /* CHANGE the KV value */
|
||||||
|
char temp_data[10] = "38C";
|
||||||
|
|
||||||
|
/* change the "temp" KV's value to "38.1" */
|
||||||
|
fdb_kv_set(kvdb, "temp", temp_data);
|
||||||
|
FDB_INFO("set 'temp' value to %s\n", temp_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /* DELETE the KV by name */
|
||||||
|
fdb_kv_del(kvdb, "temp");
|
||||||
|
FDB_INFO("delete the 'temp' finish\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
FDB_INFO("===========================================================\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* FDB_USING_KVDB */
|
|
@ -0,0 +1,120 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief TSDB samples.
|
||||||
|
*
|
||||||
|
* Time series log (like TSDB) feature samples source file.
|
||||||
|
*
|
||||||
|
* TSL is time series log, the TSDB saved many TSLs.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <flashdb.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef FDB_USING_TSDB
|
||||||
|
|
||||||
|
#define FDB_LOG_TAG "[sample][tsdb]"
|
||||||
|
|
||||||
|
struct env_status {
|
||||||
|
int temp;
|
||||||
|
int humi;
|
||||||
|
};
|
||||||
|
|
||||||
|
static bool query_cb(fdb_tsl_t tsl, void *arg);
|
||||||
|
static bool query_by_time_cb(fdb_tsl_t tsl, void *arg);
|
||||||
|
static bool set_status_cb(fdb_tsl_t tsl, void *arg);
|
||||||
|
|
||||||
|
void tsdb_sample(fdb_tsdb_t tsdb)
|
||||||
|
{
|
||||||
|
struct fdb_blob blob;
|
||||||
|
|
||||||
|
FDB_INFO("==================== tsdb_sample ====================\n");
|
||||||
|
|
||||||
|
{ /* APPEND new TSL (time series log) */
|
||||||
|
struct env_status status;
|
||||||
|
|
||||||
|
/* append new log to TSDB */
|
||||||
|
status.temp = 36;
|
||||||
|
status.humi = 85;
|
||||||
|
fdb_tsl_append(tsdb, fdb_blob_make(&blob, &status, sizeof(status)));
|
||||||
|
FDB_INFO("append the new status.temp (%d) and status.humi (%d)\n", status.temp, status.humi);
|
||||||
|
|
||||||
|
status.temp = 38;
|
||||||
|
status.humi = 90;
|
||||||
|
fdb_tsl_append(tsdb, fdb_blob_make(&blob, &status, sizeof(status)));
|
||||||
|
FDB_INFO("append the new status.temp (%d) and status.humi (%d)\n", status.temp, status.humi);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /* QUERY the TSDB */
|
||||||
|
/* query all TSL in TSDB by iterator */
|
||||||
|
fdb_tsl_iter(tsdb, query_cb, tsdb);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /* QUERY the TSDB by time */
|
||||||
|
/* prepare query time (from 1970-01-01 00:00:00 to 2020-05-05 00:00:00) */
|
||||||
|
struct tm tm_from = { .tm_year = 1970 - 1900, .tm_mon = 0, .tm_mday = 1, .tm_hour = 0, .tm_min = 0, .tm_sec = 0 };
|
||||||
|
struct tm tm_to = { .tm_year = 2020 - 1900, .tm_mon = 4, .tm_mday = 5, .tm_hour = 0, .tm_min = 0, .tm_sec = 0 };
|
||||||
|
time_t from_time = mktime(&tm_from), to_time = mktime(&tm_to);
|
||||||
|
size_t count;
|
||||||
|
/* query all TSL in TSDB by time */
|
||||||
|
fdb_tsl_iter_by_time(tsdb, from_time, to_time, query_by_time_cb, tsdb);
|
||||||
|
/* query all FDB_TSL_WRITE status TSL's count in TSDB by time */
|
||||||
|
count = fdb_tsl_query_count(tsdb, from_time, to_time, FDB_TSL_WRITE);
|
||||||
|
FDB_INFO("query count is: %zu\n", count);
|
||||||
|
}
|
||||||
|
|
||||||
|
{ /* SET the TSL status */
|
||||||
|
/* Change the TSL status by iterator or time iterator
|
||||||
|
* set_status_cb: the change operation will in this callback
|
||||||
|
*
|
||||||
|
* NOTE: The actions to modify the state must be in order.
|
||||||
|
* like: FDB_TSL_WRITE -> FDB_TSL_USER_STATUS1 -> FDB_TSL_DELETED -> FDB_TSL_USER_STATUS2
|
||||||
|
* The intermediate states can also be ignored.
|
||||||
|
* such as: FDB_TSL_WRITE -> FDB_TSL_DELETED
|
||||||
|
*/
|
||||||
|
fdb_tsl_iter(tsdb, set_status_cb, tsdb);
|
||||||
|
}
|
||||||
|
|
||||||
|
FDB_INFO("===========================================================\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool query_cb(fdb_tsl_t tsl, void *arg)
|
||||||
|
{
|
||||||
|
struct fdb_blob blob;
|
||||||
|
struct env_status status;
|
||||||
|
fdb_tsdb_t db = arg;
|
||||||
|
|
||||||
|
fdb_blob_read((fdb_db_t) db, fdb_tsl_to_blob(tsl, fdb_blob_make(&blob, &status, sizeof(status))));
|
||||||
|
FDB_INFO("[query_cb] queried a TSL: time: %ld, temp: %d, humi: %d\n", tsl->time, status.temp, status.humi);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool query_by_time_cb(fdb_tsl_t tsl, void *arg)
|
||||||
|
{
|
||||||
|
struct fdb_blob blob;
|
||||||
|
struct env_status status;
|
||||||
|
fdb_tsdb_t db = arg;
|
||||||
|
|
||||||
|
fdb_blob_read((fdb_db_t) db, fdb_tsl_to_blob(tsl, fdb_blob_make(&blob, &status, sizeof(status))));
|
||||||
|
FDB_INFO("[query_by_time_cb] queried a TSL: time: %ld, temp: %d, humi: %d\n", tsl->time, status.temp, status.humi);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool set_status_cb(fdb_tsl_t tsl, void *arg)
|
||||||
|
{
|
||||||
|
fdb_tsdb_t db = arg;
|
||||||
|
|
||||||
|
FDB_INFO("set the TSL (time %ld) status from %d to %d\n", tsl->time, tsl->status, FDB_TSL_USER_STATUS1);
|
||||||
|
fdb_tsl_set_status(db, tsl, FDB_TSL_USER_STATUS1);
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif /* FDB_USING_TSDB */
|
|
@ -36,6 +36,8 @@ extern int As830Ch4Init(void);
|
||||||
extern int Tb600bIaq10IaqInit(void);
|
extern int Tb600bIaq10IaqInit(void);
|
||||||
extern int Tb600bTvoc10TvocInit(void);
|
extern int Tb600bTvoc10TvocInit(void);
|
||||||
extern int Tb600bWqHcho1osInit(void);
|
extern int Tb600bWqHcho1osInit(void);
|
||||||
|
extern int QsFxWindDirectionInit(void);
|
||||||
|
extern int QsFsWindSpeedInit(void);
|
||||||
|
|
||||||
extern int lv_port_init(void);
|
extern int lv_port_init(void);
|
||||||
|
|
||||||
|
@ -104,6 +106,14 @@ static struct InitDesc sensor_desc[] =
|
||||||
{ "zg09_co2", Zg09Co2Init },
|
{ "zg09_co2", Zg09Co2Init },
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#ifdef SENSOR_QS_FX
|
||||||
|
{ "qs_fx_wind_direction", QsFxWindDirectionInit },
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef SENSOR_QS_FS
|
||||||
|
{ "qs_fs_wind_speed", QsFsWindSpeedInit },
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef SENSOR_AS830
|
#ifdef SENSOR_AS830
|
||||||
{ "ch4_as830", As830Ch4Init },
|
{ "ch4_as830", As830Ch4Init },
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -11,6 +11,11 @@ menuconfig USING_CMSIS_5_DEMOAPP
|
||||||
select IMAGE_PROCESSING_USING_TJPGD
|
select IMAGE_PROCESSING_USING_TJPGD
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
config USING_CMSIS_5_NN_DEMOAPP_VEG_CLASSIFY
|
||||||
|
bool "Using CMSIS-5 NN demo app vegetable classify"
|
||||||
|
select USING_IMAGE_PROCESSING
|
||||||
|
select IMAGE_PROCESSING_USING_TJPGD
|
||||||
|
default n
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,37 @@
|
||||||
|
# CMSIS-NN vegetable classify example
|
||||||
|
|
||||||
|
This example uses CMSIS-NN to classify vegetable in real time under certain circumstances .
|
||||||
|
|
||||||
|
## Requirements:
|
||||||
|
- CMSIS-NN in Framework/knowing/cmsis_5
|
||||||
|
- **ov2640 need to be configured** in menuconfig "More Drivers->ov2640 driver" as follows
|
||||||
|
- Output format (RGB565 mode)
|
||||||
|
- (256) X direction resolution of outputimage
|
||||||
|
- (256) Y direction resolution of outputimage
|
||||||
|
- (512) X direction WINDOWS SIZE
|
||||||
|
- (512) Y direction WINDOWS SIZE
|
||||||
|
|
||||||
|
## To run this demo:
|
||||||
|
- Set up and configure the corresponding hardware environment.
|
||||||
|
|
||||||
|
- Run demo by type the command
|
||||||
|
```
|
||||||
|
cmsisnn_vegetable_classify
|
||||||
|
|
||||||
|
## Results
|
||||||
|
|
||||||
|
- **tomato**
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- **potato**
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- **pepper**
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
- **mushroom**
|
||||||
|
|
||||||
|

|
|
@ -0,0 +1,18 @@
|
||||||
|
from building import *
|
||||||
|
import os
|
||||||
|
|
||||||
|
cwd = GetCurrentDir()
|
||||||
|
|
||||||
|
src = Split('''
|
||||||
|
model/nn_vegetable_classify.c
|
||||||
|
cmsisnn_vegetable_classify.c
|
||||||
|
''')
|
||||||
|
|
||||||
|
path = [
|
||||||
|
cwd + '/model',
|
||||||
|
cwd + '/demo'
|
||||||
|
]
|
||||||
|
|
||||||
|
group = DefineGroup('CMSISNN vegetable classify application', src, depend = ['USING_CMSIS_5_NN_DEMOAPP_VEG_CLASSIFY'], CPPPATH = path)
|
||||||
|
|
||||||
|
Return('group')
|
|
@ -0,0 +1,188 @@
|
||||||
|
#include <rtthread.h>
|
||||||
|
#include <rtdevice.h>
|
||||||
|
#include "stdio.h"
|
||||||
|
#include "string.h"
|
||||||
|
|
||||||
|
#ifdef OV2640_RGB565_MODE
|
||||||
|
#ifdef RT_USING_POSIX
|
||||||
|
#include <dfs_posix.h>
|
||||||
|
#include <dfs_poll.h>
|
||||||
|
#ifdef RT_USING_POSIX_TERMIOS
|
||||||
|
#include <posix_termios.h>
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <drv_ov2640.h>
|
||||||
|
#include <drv_lcd.h>
|
||||||
|
#include "nn_vegetable_classify.h"
|
||||||
|
#define JPEG_BUF_SIZE (2 * OV2640_X_RESOLUTION_IMAGE_OUTSIZE * OV2640_Y_RESOLUTION_IMAGE_OUTSIZE)
|
||||||
|
#define IOCTL_ERROR 1
|
||||||
|
|
||||||
|
static int fd = 0;
|
||||||
|
static int infer_times = 0;
|
||||||
|
static int photo_times = 0;
|
||||||
|
static int height = OV2640_X_RESOLUTION_IMAGE_OUTSIZE;
|
||||||
|
static int width = OV2640_Y_RESOLUTION_IMAGE_OUTSIZE;
|
||||||
|
static _ioctl_shoot_para shoot_para_t = {0};
|
||||||
|
const char *vegetable_label[] = {"mushroom", "pepper", "potato", "tomato"};
|
||||||
|
|
||||||
|
uint8_t *resized_buffer = NULL;
|
||||||
|
uint8_t *in_buffer = NULL;
|
||||||
|
|
||||||
|
int get_top_prediction_detection(q7_t *predictions)
|
||||||
|
{
|
||||||
|
int max_ind = 0;
|
||||||
|
int max_val = -128;
|
||||||
|
for (int i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
if (max_val < predictions[i])
|
||||||
|
{
|
||||||
|
max_val = predictions[i];
|
||||||
|
max_ind = i;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return max_ind;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cmsisnn_inference_vegetable_classify(uint8_t *input_data)
|
||||||
|
{
|
||||||
|
int8_t output_data[4];
|
||||||
|
char output[50] = {0};
|
||||||
|
char outputPrediction[50] = {0};
|
||||||
|
memset(output, 0, 50);
|
||||||
|
memset(outputPrediction, 0, 50);
|
||||||
|
|
||||||
|
run_nn_sn_classify((int8_t *)input_data, output_data);
|
||||||
|
arm_softmax_q7(output_data, 4, output_data);
|
||||||
|
|
||||||
|
infer_times++;
|
||||||
|
int top_ind = get_top_prediction_detection(output_data);
|
||||||
|
printf("times:%d Prediction:%s \r\n", infer_times, vegetable_label[top_ind]);
|
||||||
|
sprintf(outputPrediction, "times:%d Prediction:%s \r\n", infer_times, vegetable_label[top_ind]);
|
||||||
|
lcd_show_string(1, 280, 240, 16, 16, outputPrediction, RED);
|
||||||
|
return top_ind;
|
||||||
|
}
|
||||||
|
|
||||||
|
void resize_rgb888in_rgb565out(uint8_t *camera_image, uint16_t *resize_image)
|
||||||
|
{
|
||||||
|
uint8_t *psrc_temp = (uint8_t *)camera_image;
|
||||||
|
uint16_t *pdst_temp = (uint16_t *)resize_image;
|
||||||
|
for (int y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
*pdst_temp++ = (*psrc_temp++ & 0xF8) << 8 | (*psrc_temp++ & 0xFC) << 3 | *psrc_temp++ >> 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void resize_rgb565in_rgb888out(uint8_t *camera_image, uint8_t *resize_image)
|
||||||
|
{
|
||||||
|
uint8_t *psrc_temp = (uint8_t *)camera_image;
|
||||||
|
uint8_t *pdst_temp = (uint8_t *)resize_image;
|
||||||
|
for (int y = 0; y < height; y++)
|
||||||
|
{
|
||||||
|
for (int x = 0; x < width; x++)
|
||||||
|
{
|
||||||
|
uint8_t pixel_lo = *psrc_temp++;
|
||||||
|
uint8_t pixel_hi = *psrc_temp++;
|
||||||
|
*pdst_temp++ = (0xF8 & pixel_hi);
|
||||||
|
*pdst_temp++ = ((0x07 & pixel_hi) << 5) | ((0xE0 & pixel_lo) >> 3);
|
||||||
|
*pdst_temp++ = (0x1F & pixel_lo) << 3;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void lcd_show_ov2640_thread_detection(uint8_t *rgbbuffer)
|
||||||
|
{
|
||||||
|
int32_t ret = 0;
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
ret = ioctl(fd, IOCTRL_CAMERA_START_SHOT, &shoot_para_t);
|
||||||
|
if (ret == IOCTL_ERROR)
|
||||||
|
{
|
||||||
|
printf("ov2640 can't wait event flag");
|
||||||
|
free(rgbbuffer);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
lcd_fill_array(0, 0, OV2640_X_RESOLUTION_IMAGE_OUTSIZE, OV2640_Y_RESOLUTION_IMAGE_OUTSIZE, rgbbuffer);
|
||||||
|
|
||||||
|
if (photo_times % 20 == 0)
|
||||||
|
{
|
||||||
|
resize_rgb565in_rgb888out(rgbbuffer, resized_buffer);
|
||||||
|
int pixel = 0;
|
||||||
|
for (int i = 0; i < 3 * width; i += 3 * width / CONV1_IN_DIM)
|
||||||
|
{
|
||||||
|
for (int j = 0; j < 3 * height; j += 3 * height / CONV1_IN_DIM)
|
||||||
|
{
|
||||||
|
for (int k = 0; k < 3; k++, pixel++)
|
||||||
|
{
|
||||||
|
*(in_buffer + pixel) = *(resized_buffer + 256 * i + j + k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
cmsisnn_inference_vegetable_classify(in_buffer);
|
||||||
|
}
|
||||||
|
photo_times++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void cmsisnn_vegetable_classify()
|
||||||
|
{
|
||||||
|
fd = open("/dev/ov2640", O_RDONLY);
|
||||||
|
if (fd < 0)
|
||||||
|
{
|
||||||
|
printf("open ov2640 fail !!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
printf("memory_init \n\r");
|
||||||
|
uint8_t *JpegBuffer = malloc(JPEG_BUF_SIZE);
|
||||||
|
if (JpegBuffer == NULL)
|
||||||
|
{
|
||||||
|
printf("JpegBuffer senddata buf malloc error!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
resized_buffer = malloc(3 * width * height);
|
||||||
|
if (resized_buffer == NULL)
|
||||||
|
{
|
||||||
|
printf("Resized_buffer buf malloc error!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
in_buffer = malloc(CONV1_IN_CH * CONV1_IN_DIM * CONV1_IN_DIM);
|
||||||
|
if (in_buffer == NULL)
|
||||||
|
{
|
||||||
|
printf("In_buffer buf malloc error!\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
memory_init();
|
||||||
|
printf("memory_init success\n\r");
|
||||||
|
|
||||||
|
shoot_para_t.pdata = (uint32_t)JpegBuffer;
|
||||||
|
shoot_para_t.length = JPEG_BUF_SIZE / 2;
|
||||||
|
|
||||||
|
int result = 0;
|
||||||
|
pthread_t tid = 0;
|
||||||
|
pthread_attr_t attr;
|
||||||
|
struct sched_param prio;
|
||||||
|
prio.sched_priority = 8;
|
||||||
|
size_t stack_size = 1024 * 11;
|
||||||
|
pthread_attr_init(&attr);
|
||||||
|
pthread_attr_setschedparam(&attr, &prio);
|
||||||
|
pthread_attr_setstacksize(&attr, stack_size);
|
||||||
|
|
||||||
|
result = pthread_create(&tid, &attr, lcd_show_ov2640_thread_detection, JpegBuffer);
|
||||||
|
if (0 == result) {
|
||||||
|
printf("thread_detect_entry successfully!\n");
|
||||||
|
} else {
|
||||||
|
printf("thread_detect_entry failed! error code is %d.\n", result);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifdef __RT_THREAD_H__
|
||||||
|
MSH_CMD_EXPORT(cmsisnn_vegetable_classify, classify vegetable using cmsis-nn);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
Binary file not shown.
After Width: | Height: | Size: 144 KiB |
Binary file not shown.
After Width: | Height: | Size: 140 KiB |
Binary file not shown.
After Width: | Height: | Size: 126 KiB |
Binary file not shown.
After Width: | Height: | Size: 141 KiB |
|
@ -0,0 +1,108 @@
|
||||||
|
#include "nn_vegetable_classify.h"
|
||||||
|
|
||||||
|
static const q7_t conv1_w[CONV1_WT_SHAPE] = CONV1_WT;
|
||||||
|
static const q7_t conv1_b[CONV1_BIAS_SHAPE] = CONV1_BIAS;
|
||||||
|
static const q7_t conv2_w[CONV2_WT_SHAPE] = CONV2_WT;
|
||||||
|
static const q7_t conv2_b[CONV2_BIAS_SHAPE] = CONV2_BIAS;
|
||||||
|
// static const q7_t conv3_w[CONV3_WT_SHAPE] = CONV3_WT;
|
||||||
|
// static const q7_t conv3_b[CONV3_BIAS_SHAPE] = CONV3_BIAS;
|
||||||
|
static const q7_t interface_w[INTERFACE_WT_SHAPE] = INTERFACE_WT;
|
||||||
|
static const q7_t interface_b[INTERFACE_BIAS_SHAPE] = INTERFACE_BIAS;
|
||||||
|
static const q7_t linear_w[LINEAR_WT_SHAPE] = LINEAR_WT;
|
||||||
|
static const q7_t linear_b[LINEAR_BIAS_SHAPE] = LINEAR_BIAS;
|
||||||
|
|
||||||
|
q7_t *conv1_out = NULL;
|
||||||
|
q7_t *pool1_out = NULL;
|
||||||
|
q7_t *conv2_out = NULL;
|
||||||
|
q7_t *pool2_out = NULL;
|
||||||
|
// q7_t *conv3_out = NULL ;
|
||||||
|
q7_t *interface_out = NULL;
|
||||||
|
q7_t *linear_out = NULL;
|
||||||
|
q7_t *y_out = NULL;
|
||||||
|
q7_t *conv_buffer = NULL;
|
||||||
|
q7_t *fc_buffer = NULL;
|
||||||
|
|
||||||
|
void memory_init()
|
||||||
|
{
|
||||||
|
static int flag = 0;
|
||||||
|
if (flag == 0)
|
||||||
|
{
|
||||||
|
conv1_out = malloc(CONV1_OUT_CH * CONV1_OUT_DIM * CONV1_OUT_DIM);
|
||||||
|
if (conv1_out == NULL)
|
||||||
|
{
|
||||||
|
printf("conv1_out malloc failed...\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pool1_out = malloc(CONV1_OUT_CH * POOL1_OUT_DIM * POOL1_OUT_DIM);
|
||||||
|
if (pool1_out == NULL)
|
||||||
|
{
|
||||||
|
printf("pool1_out malloc failed...\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
conv2_out = malloc(CONV2_OUT_CH * CONV2_OUT_DIM * CONV2_OUT_DIM);
|
||||||
|
if (conv2_out == NULL)
|
||||||
|
{
|
||||||
|
printf("conv2_out malloc failed...\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
pool2_out = malloc(CONV2_OUT_CH * POOL2_OUT_DIM * POOL2_OUT_DIM);
|
||||||
|
if (pool2_out == NULL)
|
||||||
|
{
|
||||||
|
printf("pool2_out malloc failed...\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
interface_out = malloc(INTERFACE_OUT_DIM);
|
||||||
|
if (interface_out == NULL)
|
||||||
|
{
|
||||||
|
printf("interface_out malloc failed...\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
linear_out = malloc(LINEAR_OUT_DIM);
|
||||||
|
if (linear_out == NULL)
|
||||||
|
{
|
||||||
|
printf("linear_out malloc failed...\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
y_out = malloc(LINEAR_OUT_DIM);
|
||||||
|
if (y_out == NULL)
|
||||||
|
{
|
||||||
|
printf("y_out malloc failed...\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
conv_buffer = malloc(MAX_CONV_BUFFER_SIZE);
|
||||||
|
if (conv_buffer == NULL)
|
||||||
|
{
|
||||||
|
printf("conv_buffer malloc failed...\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
fc_buffer = malloc(MAX_FC_BUFFER);
|
||||||
|
if (fc_buffer == NULL)
|
||||||
|
{
|
||||||
|
printf("fc_buffer malloc failed...\n");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void run_nn_sn_classify(q7_t *input_data, q7_t *output_data)
|
||||||
|
{
|
||||||
|
for (int i = 0; i < CONV1_IN_CH * CONV1_IN_DIM * CONV1_IN_DIM; i++)
|
||||||
|
{
|
||||||
|
input_data[i] = input_data[i] - 127;
|
||||||
|
}
|
||||||
|
arm_convolve_HWC_q7_basic(input_data, CONV1_IN_DIM, CONV1_IN_CH, conv1_w, CONV1_OUT_CH, CONV1_KER_DIM, CONV1_PAD, CONV1_STRIDE, conv1_b, CONV1_BIAS_LSHIFT, CONV1_OUT_RSHIFT, conv1_out, CONV1_OUT_DIM, (q15_t *)conv_buffer, fc_buffer);
|
||||||
|
arm_maxpool_q7_HWC(conv1_out, POOL1_IN_DIM, POOL1_IN_CH, POOL1_KER_DIM, POOL1_PAD, POOL1_STRIDE, POOL1_OUT_DIM, NULL, pool1_out);
|
||||||
|
arm_relu_q7(pool1_out, POOL1_OUT_DIM * POOL1_OUT_DIM * CONV1_OUT_CH);
|
||||||
|
arm_convolve_HWC_q7_basic(pool1_out, CONV2_IN_DIM, CONV2_IN_CH, conv2_w, CONV2_OUT_CH, CONV2_KER_DIM, CONV2_PAD, CONV2_STRIDE, conv2_b, CONV2_BIAS_LSHIFT, CONV2_OUT_RSHIFT, conv2_out, CONV2_OUT_DIM, (q15_t *)conv_buffer, NULL);
|
||||||
|
arm_maxpool_q7_HWC(conv2_out, POOL2_IN_DIM, POOL2_IN_CH, POOL2_KER_DIM, POOL2_PAD, POOL2_STRIDE, POOL2_OUT_DIM, NULL, pool2_out);
|
||||||
|
arm_relu_q7(pool2_out, POOL2_OUT_DIM * POOL2_OUT_DIM * CONV2_OUT_CH);
|
||||||
|
// printf("1\n");
|
||||||
|
// arm_convolve_HWC_q7_basic(pool2_out, CONV3_IN_DIM, CONV3_IN_CH, conv3_w, CONV3_OUT_CH, CONV3_KER_DIM,
|
||||||
|
// CONV3_PAD, CONV3_STRIDE, conv3_b, CONV3_BIAS_LSHIFT, CONV3_OUT_RSHIFT, conv3_out,
|
||||||
|
// CONV3_OUT_DIM, (q15_t *) conv_buffer, NULL);
|
||||||
|
// arm_relu_q7(conv3_out, CONV3_OUT_DIM * CONV3_OUT_DIM * CONV3_OUT_CH);
|
||||||
|
// printf("2\n");
|
||||||
|
arm_fully_connected_q7_opt(pool2_out, interface_w, INTERFACE_IN_DIM, INTERFACE_OUT_DIM, INTERFACE_BIAS_LSHIFT, INTERFACE_OUT_RSHIFT, interface_b, interface_out, (q15_t *)fc_buffer);
|
||||||
|
arm_relu_q7(interface_out, INTERFACE_OUT_DIM);
|
||||||
|
arm_fully_connected_q7_opt(interface_out, linear_w, LINEAR_IN_DIM, LINEAR_OUT_DIM, LINEAR_BIAS_LSHIFT, LINEAR_OUT_RSHIFT, linear_b, output_data, (q15_t *)fc_buffer);
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
#ifndef __NN_H__
|
||||||
|
#define __NN_H__
|
||||||
|
|
||||||
|
#include <transform.h>
|
||||||
|
#include "arm_math.h"
|
||||||
|
#include "arm_nnfunctions.h"
|
||||||
|
#include "parameter_vegetable_classify.h"
|
||||||
|
#include "weights_vegetable_classify.h"
|
||||||
|
|
||||||
|
void run_nn_detection(q7_t* input_data, q7_t* output_data);
|
||||||
|
void memory_init();
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,56 @@
|
||||||
|
#define CONV1_IN_CH 3
|
||||||
|
#define CONV1_OUT_CH 32
|
||||||
|
#define CONV1_KER_DIM 3
|
||||||
|
#define CONV1_PAD 0
|
||||||
|
#define CONV1_STRIDE 1
|
||||||
|
#define CONV1_IN_DIM 32
|
||||||
|
#define CONV1_OUT_DIM 30
|
||||||
|
#define MAX_CONV_BUFFER_SIZE 3096
|
||||||
|
#define POOL1_IN_CH 32
|
||||||
|
#define POOL1_KER_DIM 2
|
||||||
|
#define POOL1_PAD 0
|
||||||
|
#define POOL1_STRIDE 2
|
||||||
|
#define POOL1_IN_DIM 30
|
||||||
|
#define POOL1_OUT_DIM 15
|
||||||
|
#define CONV2_IN_CH 32
|
||||||
|
#define CONV2_OUT_CH 32
|
||||||
|
#define CONV2_KER_DIM 3
|
||||||
|
#define CONV2_PAD 0
|
||||||
|
#define CONV2_STRIDE 1
|
||||||
|
#define CONV2_IN_DIM 15
|
||||||
|
#define CONV2_OUT_DIM 13
|
||||||
|
#define POOL2_IN_CH 32
|
||||||
|
#define POOL2_KER_DIM 2
|
||||||
|
#define POOL2_PAD 0
|
||||||
|
#define POOL2_STRIDE 2
|
||||||
|
#define POOL2_IN_DIM 13
|
||||||
|
#define POOL2_OUT_DIM 6
|
||||||
|
#define INTERFACE_OUT_DIM 32
|
||||||
|
#define INTERFACE_IN_DIM 1152
|
||||||
|
#define MAX_FC_BUFFER 3096
|
||||||
|
#define LINEAR_OUT_DIM 4
|
||||||
|
#define LINEAR_IN_DIM 32
|
||||||
|
#define CONV1_BIAS_LSHIFT 6
|
||||||
|
#define CONV1_OUT_RSHIFT 9
|
||||||
|
#define CONV1_WEIGHT_Q 8
|
||||||
|
#define CONV1_BIAS_Q 8
|
||||||
|
#define CONV1_INPUT_Q 6
|
||||||
|
#define CONV1_OUT_Q 5
|
||||||
|
#define CONV2_BIAS_LSHIFT 4
|
||||||
|
#define CONV2_OUT_RSHIFT 10
|
||||||
|
#define CONV2_WEIGHT_Q 9
|
||||||
|
#define CONV2_BIAS_Q 10
|
||||||
|
#define CONV2_INPUT_Q 5
|
||||||
|
#define CONV2_OUT_Q 4
|
||||||
|
#define INTERFACE_BIAS_LSHIFT 3
|
||||||
|
#define INTERFACE_OUT_RSHIFT 11
|
||||||
|
#define INTERFACE_WEIGHT_Q 9
|
||||||
|
#define INTERFACE_BIAS_Q 10
|
||||||
|
#define INTERFACE_INPUT_Q 4
|
||||||
|
#define INTERFACE_OUT_Q 2
|
||||||
|
#define LINEAR_BIAS_LSHIFT 0
|
||||||
|
#define LINEAR_OUT_RSHIFT 7
|
||||||
|
#define LINEAR_WEIGHT_Q 7
|
||||||
|
#define LINEAR_BIAS_Q 9
|
||||||
|
#define LINEAR_INPUT_Q 2
|
||||||
|
#define LINEAR_OUT_Q 2
|
File diff suppressed because one or more lines are too long
|
@ -1,4 +1,5 @@
|
||||||
config IMAGE_PROCESSING_TJPGDEC_APP
|
config IMAGE_PROCESSING_TJPGDEC_APP
|
||||||
bool "image processing apps/TJpgDec(example)"
|
bool "image processing apps/TJpgDec(example)"
|
||||||
|
select USING_IMAGE_PROCESSING
|
||||||
select IMAGE_PROCESSING_USING_TJPGD
|
select IMAGE_PROCESSING_USING_TJPGD
|
||||||
default n
|
default n
|
||||||
|
|
|
@ -53,6 +53,10 @@ menu "sensor app"
|
||||||
config APPLICATION_SENSOR_CO2_ZG09
|
config APPLICATION_SENSOR_CO2_ZG09
|
||||||
bool "Using sensor ZG09 apps"
|
bool "Using sensor ZG09 apps"
|
||||||
default n
|
default n
|
||||||
|
|
||||||
|
config APPLICATION_SENSOR_CO2_G8S
|
||||||
|
bool "Using sensor G8S apps"
|
||||||
|
default n
|
||||||
endif
|
endif
|
||||||
|
|
||||||
menuconfig APPLICATION_SENSOR_PM1_0
|
menuconfig APPLICATION_SENSOR_PM1_0
|
||||||
|
@ -123,6 +127,35 @@ menu "sensor app"
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
menuconfig APPLICATION_SENSOR_WINDDIRECTION
|
||||||
|
bool "Using sensor wind direction apps"
|
||||||
|
default n
|
||||||
|
|
||||||
|
if APPLICATION_SENSOR_WINDDIRECTION
|
||||||
|
config APPLICATION_SENSOR_WINDDIRECTION_QS_FX
|
||||||
|
bool "Using sensor QS-FX apps"
|
||||||
|
default n
|
||||||
|
endif
|
||||||
|
|
||||||
|
menuconfig APPLICATION_SENSOR_WINDSPEED
|
||||||
|
bool "Using sensor wind speed apps"
|
||||||
|
default n
|
||||||
|
|
||||||
|
if APPLICATION_SENSOR_WINDSPEED
|
||||||
|
config APPLICATION_SENSOR_WINDSPEED_QS_FS
|
||||||
|
bool "Using sensor QS-FS apps"
|
||||||
|
default n
|
||||||
|
endif
|
||||||
|
|
||||||
|
menuconfig APPLICATION_SENSOR_ALTITUDE
|
||||||
|
bool "Using sensor altitude apps"
|
||||||
|
default n
|
||||||
|
|
||||||
|
if APPLICATION_SENSOR_ALTITUDE
|
||||||
|
config APPLICATION_SENSOR_ALTITUDE_BMP180
|
||||||
|
bool "Using sensor BMP180 apps"
|
||||||
|
default n
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
|
|
@ -74,6 +74,10 @@ ifeq ($(CONFIG_ADD_XIZI_FETURES),y)
|
||||||
SRC_FILES += co2_zg09.c
|
SRC_FILES += co2_zg09.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_APPLICATION_SENSOR_CO2_G8S), y)
|
||||||
|
SRC_FILES += co2_g8s.c
|
||||||
|
endif
|
||||||
|
|
||||||
ifeq ($(CONFIG_APPLICATION_SENSOR_PM1_0_PS5308), y)
|
ifeq ($(CONFIG_APPLICATION_SENSOR_PM1_0_PS5308), y)
|
||||||
SRC_FILES += pm1_0_ps5308.c
|
SRC_FILES += pm1_0_ps5308.c
|
||||||
endif
|
endif
|
||||||
|
@ -98,6 +102,18 @@ ifeq ($(CONFIG_ADD_XIZI_FETURES),y)
|
||||||
SRC_FILES += temperature_hs300x.c
|
SRC_FILES += temperature_hs300x.c
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_APPLICATION_SENSOR_WINDDIRECTION_QS_FX), y)
|
||||||
|
SRC_FILES += winddirection_qs_fx.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_APPLICATION_SENSOR_WINDSPEED_QS_FS), y)
|
||||||
|
SRC_FILES += windspeed_qs_fs.c
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_APPLICATION_SENSOR_ALTITUDE_BMP180), y)
|
||||||
|
SRC_FILES += altitude_bmp180.c
|
||||||
|
endif
|
||||||
|
|
||||||
include $(KERNEL_ROOT)/compiler.mk
|
include $(KERNEL_ROOT)/compiler.mk
|
||||||
|
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -0,0 +1,39 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 AIIT XUOS Lab
|
||||||
|
* XiUOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file altitude_bmp180.c
|
||||||
|
* @brief BMP180 altitude example
|
||||||
|
* @version 1.1
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2021.12.23
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <user_api.h>
|
||||||
|
#include <sensor.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Read a altitude
|
||||||
|
* @return 0
|
||||||
|
*/
|
||||||
|
void AltitudeBmp180(void)
|
||||||
|
{
|
||||||
|
int32 altitude;
|
||||||
|
struct SensorQuantity *p_altitude = SensorQuantityFind(SENSOR_QUANTITY_BMP180_ALTITUDE, SENSOR_QUANTITY_ALTITUDE);
|
||||||
|
SensorQuantityOpen(p_altitude);
|
||||||
|
altitude = SensorQuantityRead(p_altitude);
|
||||||
|
|
||||||
|
printf("Altitude Pressure : %d Pa\n", altitude);
|
||||||
|
|
||||||
|
PrivTaskDelay(1000);
|
||||||
|
SensorQuantityClose(p_altitude);
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 AIIT XUOS Lab
|
||||||
|
* XiUOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file co2_g8s.c
|
||||||
|
* @brief G8S CO2 example
|
||||||
|
* @version 1.1
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2021.12.23
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <user_api.h>
|
||||||
|
#include <sensor.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Read a CO2
|
||||||
|
* @return 0
|
||||||
|
*/
|
||||||
|
void Co2G8s(void)
|
||||||
|
{
|
||||||
|
struct SensorQuantity *co2 = SensorQuantityFind(SENSOR_QUANTITY_G8S_CO2, SENSOR_QUANTITY_CO2);
|
||||||
|
SensorQuantityOpen(co2);
|
||||||
|
printf("CO2 : %d ppm\n", SensorQuantityRead(co2));
|
||||||
|
SensorQuantityClose(co2);
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 AIIT XUOS Lab
|
||||||
|
* XiOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file winddirection_qs_fx.c
|
||||||
|
* @brief qs-fx wind direction example
|
||||||
|
* @version 1.1
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2021.12.14
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <transform.h>
|
||||||
|
#include <sensor.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Read a wind direction
|
||||||
|
* @return 0
|
||||||
|
*/
|
||||||
|
void WindDirectionQsFx(void)
|
||||||
|
{
|
||||||
|
struct SensorQuantity *wind_direction = SensorQuantityFind(SENSOR_QUANTITY_QS_FX_WINDDIRECTION, SENSOR_QUANTITY_WINDDIRECTION);
|
||||||
|
SensorQuantityOpen(wind_direction);
|
||||||
|
PrivTaskDelay(2000);
|
||||||
|
uint16 result = SensorQuantityRead(wind_direction);
|
||||||
|
printf("wind direction : %d degree\n", result);
|
||||||
|
SensorQuantityClose(wind_direction);
|
||||||
|
}
|
||||||
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0)|SHELL_CMD_DISABLE_RETURN, WindDirectionQsFx, WindDirectionQsFx, WindDirectionQsFx function);
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 AIIT XUOS Lab
|
||||||
|
* XiOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file windspeed_qs_fs.c
|
||||||
|
* @brief qs-fx wind direction example
|
||||||
|
* @version 1.1
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2021.12.14
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <transform.h>
|
||||||
|
#include <sensor.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Read a wind speed
|
||||||
|
* @return 0
|
||||||
|
*/
|
||||||
|
void WindSpeedQsFs(void)
|
||||||
|
{
|
||||||
|
struct SensorQuantity *wind_speed = SensorQuantityFind(SENSOR_QUANTITY_QS_FS_WINDSPEED, SENSOR_QUANTITY_WINDSPEED);
|
||||||
|
SensorQuantityOpen(wind_speed);
|
||||||
|
PrivTaskDelay(2000);
|
||||||
|
uint16 result = SensorQuantityRead(wind_speed);
|
||||||
|
printf("wind speed : %d.%d m/s\n", result/10, result%10);
|
||||||
|
SensorQuantityClose(wind_speed);
|
||||||
|
}
|
||||||
|
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_PARAM_NUM(0)|SHELL_CMD_DISABLE_RETURN, WindSpeedQsFs, WindSpeedQsFs, WindSpeedQsFs function);
|
||||||
|
|
|
@ -3,6 +3,8 @@ config ADAPTER_ETHERCAT_HFA21
|
||||||
default "hfa21_ethercat"
|
default "hfa21_ethercat"
|
||||||
|
|
||||||
config ADAPTER_ETHERCAT_HFA21_ROLE
|
config ADAPTER_ETHERCAT_HFA21_ROLE
|
||||||
|
bool "support ethercat role configure"
|
||||||
|
default y
|
||||||
choice
|
choice
|
||||||
prompt "EtherCAT adapter select net role type "
|
prompt "EtherCAT adapter select net role type "
|
||||||
default AS_ETHERCAT_SLAVE_ROLE
|
default AS_ETHERCAT_SLAVE_ROLE
|
||||||
|
|
|
@ -1,3 +1,3 @@
|
||||||
SRC_FILES := ua_data.c open62541.c ua_client.c ua_server.c
|
SRC_FILES := ua_data.c open62541.c ua_client.c ua_server.c ua_api.c ua_test.c
|
||||||
|
|
||||||
include $(KERNEL_ROOT)/compiler.mk
|
include $(KERNEL_ROOT)/compiler.mk
|
||||||
|
|
|
@ -15,18 +15,6 @@
|
||||||
* A PARTICULAR PURPOSE.
|
* A PARTICULAR PURPOSE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
|
||||||
* Copyright (c) 2021 AIIT XUOS Lab
|
|
||||||
* XiUOS is licensed under Mulan PSL v2.
|
|
||||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
||||||
* You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
||||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file open62541.c
|
* @file open62541.c
|
||||||
* @brief Support OPCUA protocol
|
* @brief Support OPCUA protocol
|
||||||
|
@ -44256,7 +44244,7 @@ UA_Client_run_iterate(UA_Client *client, UA_UInt32 timeout) {
|
||||||
client->sessionState < UA_SESSIONSTATE_ACTIVATED) {
|
client->sessionState < UA_SESSIONSTATE_ACTIVATED) {
|
||||||
retval = connectIterate(client, timeout);
|
retval = connectIterate(client, timeout);
|
||||||
notifyClientState(client);
|
notifyClientState(client);
|
||||||
lw_print("lw: [%s] ret %d timeout %d state %d ch %d\n", __func__, retval, timeout,
|
ua_print("lw: [%s] ret %d timeout %d state %d ch %d\n", __func__, retval, timeout,
|
||||||
client->sessionState, client->channel.state);
|
client->sessionState, client->channel.state);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
@ -45299,7 +45287,7 @@ connectIterate(UA_Client *client, UA_UInt32 timeout) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
lw_print("lw: [%s] sess %d conn %d\n", __func__, client->sessionState, client->connectStatus);
|
ua_print("ua: [%s] sess %d conn %d\n", __func__, client->sessionState, client->connectStatus);
|
||||||
return client->connectStatus;
|
return client->connectStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,98 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 AIIT XUOS Lab
|
||||||
|
* XiUOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ua_api.c
|
||||||
|
* @brief Demo for OpcUa function
|
||||||
|
* @version 1.0
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2021.11.11
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "open62541.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "ua_api.h"
|
||||||
|
|
||||||
|
int ua_open(void *dev)
|
||||||
|
{
|
||||||
|
UaParamType *param = (UaParamType *)dev;
|
||||||
|
|
||||||
|
param->client = UA_Client_new();
|
||||||
|
|
||||||
|
ua_pr_info("ua: [%s] start ...\n", __func__);
|
||||||
|
|
||||||
|
if (param->client == NULL)
|
||||||
|
{
|
||||||
|
ua_print("ua: [%s] tcp client null\n", __func__);
|
||||||
|
return EEMPTY;
|
||||||
|
}
|
||||||
|
|
||||||
|
UA_ClientConfig *config = UA_Client_getConfig(param->client);
|
||||||
|
UA_ClientConfig_setDefault(config);
|
||||||
|
|
||||||
|
ua_pr_info("ua: [%s] %d %s\n", __func__, strlen(param->ua_remote_ip), param->ua_remote_ip);
|
||||||
|
|
||||||
|
UA_StatusCode retval = UA_Client_connect(param->client, param->ua_remote_ip);
|
||||||
|
if(retval != UA_STATUSCODE_GOOD) {
|
||||||
|
ua_pr_info("ua: [%s] deleted ret %x!\n", __func__, retval);
|
||||||
|
return (int)retval;
|
||||||
|
}
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ua_close(void *dev)
|
||||||
|
{
|
||||||
|
UaParamType *param = (UaParamType *)dev;
|
||||||
|
UA_Client_disconnect(param->client);
|
||||||
|
UA_Client_delete(param->client); /* Disconnects the client internally */
|
||||||
|
}
|
||||||
|
|
||||||
|
int ua_read(void *dev, void *buf, size_t len)
|
||||||
|
{
|
||||||
|
UaParamType *param = (UaParamType *)dev;
|
||||||
|
switch(param->act)
|
||||||
|
{
|
||||||
|
case UA_ACT_ATTR:
|
||||||
|
ua_read_nodeid_value(param->client, param->ua_id, buf);
|
||||||
|
break;
|
||||||
|
case UA_ACT_OBJ:
|
||||||
|
ua_test_browser_objects(param->client);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ua_write(void *dev, const void *buf, size_t len)
|
||||||
|
{
|
||||||
|
UaParamType *param = (UaParamType *)dev;
|
||||||
|
|
||||||
|
switch(param->act)
|
||||||
|
{
|
||||||
|
case UA_ACT_ATTR:
|
||||||
|
ua_write_nodeid_value(param->client, param->ua_id, (char *)buf);
|
||||||
|
break;
|
||||||
|
case UA_ACT_OBJ:
|
||||||
|
ua_test_browser_objects(param->client);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ua_ioctl(void *dev, int cmd, void *arg)
|
||||||
|
{
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
|
@ -9,23 +9,64 @@
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ua_api.h
|
||||||
|
* @brief API for OpcUa function
|
||||||
|
* @version 1.0
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2021.11.11
|
||||||
|
*/
|
||||||
|
|
||||||
#ifndef __UA_API_H__
|
#ifndef __UA_API_H__
|
||||||
#define __UA_API_H__
|
#define __UA_API_H__
|
||||||
|
|
||||||
#include "open62541.h"
|
#include "open62541.h"
|
||||||
|
|
||||||
#define OPC_SERVER "opc.tcp://192.168.250.5:4840"
|
#define UA_DEV_IP_LEN 48
|
||||||
|
#define UA_NODE_LEN 32
|
||||||
|
|
||||||
#define ua_print //printf
|
enum UaAction_e
|
||||||
#define ua_trace() //printf("ua: [%s] line %d checked!\n", __func__, __LINE__)
|
{
|
||||||
|
UA_ACT_ATTR,
|
||||||
|
UA_ACT_OBJ,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct UaParam
|
||||||
|
{
|
||||||
|
enum UaAction_e act;
|
||||||
|
UA_NodeId ua_id;
|
||||||
|
char ua_remote_ip[UA_DEV_IP_LEN];
|
||||||
|
char ua_node[UA_NODE_LEN];
|
||||||
|
UA_Client *client;
|
||||||
|
}UaParamType;
|
||||||
|
|
||||||
|
#define ua_print //KPrintf
|
||||||
|
#define ua_trace() //KPrintf("ua: [%s] line %d checked!\n", __func__, __LINE__)
|
||||||
#define ua_pr_info KPrintf
|
#define ua_pr_info KPrintf
|
||||||
#define ua_debug
|
#define ua_debug //KPrintf
|
||||||
|
|
||||||
|
extern const char *opc_server_url;
|
||||||
|
extern char test_ua_ip[];
|
||||||
|
|
||||||
int ua_server_connect(void);
|
int ua_server_connect(void);
|
||||||
int ua_get_server_info(UA_Client *client);
|
|
||||||
void ua_browser_objects(UA_Client *client);
|
|
||||||
void ua_browser_nodes(UA_Client *client);
|
void ua_browser_nodes(UA_Client *client);
|
||||||
|
void ua_browser_id(UA_Client *client, UA_NodeId id);
|
||||||
void ua_read_time(UA_Client *client);
|
void ua_read_time(UA_Client *client);
|
||||||
int16 ua_test(void);
|
void ua_add_nodes(UA_Client *client);
|
||||||
|
|
||||||
|
int ua_open(void *dev); // open and connect PLC device
|
||||||
|
void ua_close(void* dev); // close and disconnect PLC device
|
||||||
|
int ua_read(void* dev, void *buf, size_t len); // read data from PLC
|
||||||
|
int ua_write(void* dev, const void *buf, size_t len); // write data from PLC
|
||||||
|
int ua_ioctl(void* dev, int cmd, void *arg); // send control command to PLC
|
||||||
|
|
||||||
|
char *ua_get_nodeid_str(UA_NodeId *node_id);
|
||||||
|
void ua_read_nodeid_value(UA_Client *client, UA_NodeId id, UA_Int32 *value);
|
||||||
|
void ua_write_nodeid_value(UA_Client *client, UA_NodeId id, char* value);
|
||||||
|
void ua_test_attr(UA_Client *client);
|
||||||
|
UA_StatusCode ua_read_array_value(UA_Client *client, int array_size, UA_ReadValueId *array);
|
||||||
|
void ua_test_browser_objects(UA_Client *client);
|
||||||
|
int ua_test_interact_server(UA_Client *client);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -10,10 +10,22 @@
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "open62541.h"
|
/**
|
||||||
|
* @file ua_client.c
|
||||||
|
* @brief Client for OpcUa function
|
||||||
|
* @version 1.0
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2021.11.11
|
||||||
|
*/
|
||||||
|
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include "open62541.h"
|
||||||
#include "ua_api.h"
|
#include "ua_api.h"
|
||||||
|
|
||||||
|
#define UA_RESPONSE_TIMEOUT 10000
|
||||||
|
|
||||||
|
const char *opc_server_url = {"opc.tcp://192.168.250.2:4840"};
|
||||||
|
|
||||||
#ifdef UA_ENABLE_SUBSCRIPTIONS
|
#ifdef UA_ENABLE_SUBSCRIPTIONS
|
||||||
static void handler_TheAnswerChanged(UA_Client* client, UA_UInt32 subId, void* subContext,
|
static void handler_TheAnswerChanged(UA_Client* client, UA_UInt32 subId, void* subContext,
|
||||||
UA_UInt32 monId, void* monContext, UA_DataValue* value)
|
UA_UInt32 monId, void* monContext, UA_DataValue* value)
|
||||||
|
@ -34,7 +46,6 @@ static UA_StatusCode nodeIter(UA_NodeId childId, UA_Boolean isInverse, UA_NodeId
|
||||||
parent->namespaceIndex, parent->identifier.numeric,
|
parent->namespaceIndex, parent->identifier.numeric,
|
||||||
referenceTypeId.identifier.numeric, childId.namespaceIndex,
|
referenceTypeId.identifier.numeric, childId.namespaceIndex,
|
||||||
childId.identifier.numeric);
|
childId.identifier.numeric);
|
||||||
|
|
||||||
return UA_STATUSCODE_GOOD;
|
return UA_STATUSCODE_GOOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,48 +54,120 @@ int ua_get_points(UA_Client *client)
|
||||||
/* Listing endpoints */
|
/* Listing endpoints */
|
||||||
UA_EndpointDescription* endpointArray = NULL;
|
UA_EndpointDescription* endpointArray = NULL;
|
||||||
size_t endpointArraySize = 0;
|
size_t endpointArraySize = 0;
|
||||||
UA_StatusCode retval = UA_Client_getEndpoints(client, OPC_SERVER,
|
UA_StatusCode ret = UA_Client_getEndpoints(client, opc_server_url,
|
||||||
&endpointArraySize, &endpointArray);
|
&endpointArraySize, &endpointArray);
|
||||||
if(retval != UA_STATUSCODE_GOOD)
|
|
||||||
|
if(ret != UA_STATUSCODE_GOOD)
|
||||||
{
|
{
|
||||||
UA_Array_delete(endpointArray, endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
|
UA_Array_delete(endpointArray, endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ua_print("%i endpoints found\n", (int)endpointArraySize);
|
ua_print("%i endpoints found\n", (int)endpointArraySize);
|
||||||
|
|
||||||
for(size_t i=0; i<endpointArraySize; i++)
|
for(size_t i=0; i<endpointArraySize; i++)
|
||||||
{
|
{
|
||||||
ua_print("URL of endpoint %i is %.*s\n", (int)i,
|
ua_print("URL of endpoint %i is %.*s\n", (int)i,
|
||||||
(int)endpointArray[i].endpointUrl.length,
|
(int)endpointArray[i].endpointUrl.length,
|
||||||
endpointArray[i].endpointUrl.data);
|
endpointArray[i].endpointUrl.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
UA_Array_delete(endpointArray,endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
|
UA_Array_delete(endpointArray,endpointArraySize, &UA_TYPES[UA_TYPES_ENDPOINTDESCRIPTION]);
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ua_browser_objects(UA_Client *client)
|
void ua_print_value(UA_Variant* val)
|
||||||
{
|
{
|
||||||
/* Browse some objects */
|
if(val->type == &UA_TYPES[UA_TYPES_LOCALIZEDTEXT])
|
||||||
ua_pr_info("Browsing nodes in objects folder:\n");
|
{
|
||||||
|
UA_LocalizedText* ptr = (UA_LocalizedText*)val->data;
|
||||||
|
ua_pr_info("%.*s (Text)\n", ptr->text.length, ptr->text.data);
|
||||||
|
}
|
||||||
|
else if(val->type == &UA_TYPES[UA_TYPES_UINT32])
|
||||||
|
{
|
||||||
|
UA_UInt32* ptr = (UA_UInt32*)val->data;
|
||||||
|
ua_pr_info("%d (UInt32)\n", *ptr);
|
||||||
|
}
|
||||||
|
else if(val->type == &UA_TYPES[UA_TYPES_BOOLEAN])
|
||||||
|
{
|
||||||
|
UA_Boolean* ptr = (UA_Boolean*)val->data;
|
||||||
|
ua_pr_info("%i (BOOL)\n", *ptr);
|
||||||
|
}
|
||||||
|
else if(val->type == &UA_TYPES[UA_TYPES_INT32])
|
||||||
|
{
|
||||||
|
UA_Int32* ptr = (UA_Int32*)val->data;
|
||||||
|
ua_pr_info("%d (Int32)\n", *ptr);
|
||||||
|
}
|
||||||
|
else if(val->type == &UA_TYPES[UA_TYPES_INT16])
|
||||||
|
{
|
||||||
|
UA_Int16* ptr = (UA_Int16*)val->data;
|
||||||
|
ua_pr_info("%d (Int16)\n", *ptr);
|
||||||
|
}
|
||||||
|
else if(val->type == &UA_TYPES[UA_TYPES_STRING])
|
||||||
|
{
|
||||||
|
UA_String* ptr = (UA_String*)val->data;
|
||||||
|
ua_pr_info("%*.s (String)\n", ptr->length, ptr->data);
|
||||||
|
}
|
||||||
|
else if(val->type == &UA_TYPES[UA_TYPES_DATETIME])
|
||||||
|
{
|
||||||
|
UA_DateTime* ptr = (UA_DateTime*)val->data;
|
||||||
|
UA_DateTimeStruct dts = UA_DateTime_toStruct(*ptr);
|
||||||
|
ua_pr_info("%d-%d-%d %d:%d:%d.%03d (Time)\n",
|
||||||
|
dts.day, dts.month, dts.year, dts.hour, dts.min, dts.sec, dts.milliSec);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UA_BrowseRequest bReq;
|
char *ua_get_nodeid_str(UA_NodeId *node_id)
|
||||||
UA_BrowseRequest_init(&bReq);
|
{
|
||||||
|
static char nodeid_str[UA_NODE_LEN] = {0};
|
||||||
|
|
||||||
bReq.requestedMaxReferencesPerNode = 0;
|
switch(node_id->identifierType)
|
||||||
bReq.nodesToBrowse = UA_BrowseDescription_new();
|
{
|
||||||
bReq.nodesToBrowseSize = 1;
|
case UA_NODEIDTYPE_NUMERIC:
|
||||||
bReq.nodesToBrowse[0].nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER); /* browse objects folder */
|
snprintf(nodeid_str, UA_NODE_LEN, "n%d,%d", node_id->namespaceIndex, node_id->identifier.numeric);
|
||||||
bReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; /* return everything */
|
break;
|
||||||
|
case UA_NODEIDTYPE_STRING:
|
||||||
|
snprintf(nodeid_str, UA_NODE_LEN, "n%d,%.*s", node_id->namespaceIndex, node_id->identifier.string.length,
|
||||||
|
node_id->identifier.string.data);
|
||||||
|
break;
|
||||||
|
case UA_NODEIDTYPE_BYTESTRING:
|
||||||
|
snprintf(nodeid_str, UA_NODE_LEN, "n%d,%s", node_id->namespaceIndex, node_id->identifier.byteString.data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return nodeid_str;
|
||||||
|
}
|
||||||
|
|
||||||
UA_BrowseResponse bResp = UA_Client_Service_browse(client, bReq);
|
void ua_print_nodeid(UA_NodeId *node_id)
|
||||||
|
{
|
||||||
|
switch(node_id->identifierType)
|
||||||
|
{
|
||||||
|
case UA_NODEIDTYPE_NUMERIC:
|
||||||
|
ua_pr_info(" NodeID n%d,%d ", node_id->namespaceIndex, node_id->identifier.numeric);
|
||||||
|
break;
|
||||||
|
case UA_NODEIDTYPE_STRING:
|
||||||
|
ua_pr_info(" NodeID n%d,%.*s ", node_id->namespaceIndex, node_id->identifier.string.length,
|
||||||
|
node_id->identifier.string.data);
|
||||||
|
break;
|
||||||
|
case UA_NODEIDTYPE_BYTESTRING:
|
||||||
|
ua_pr_info(" NodeID n%d,%s ", node_id->namespaceIndex, node_id->identifier.byteString.data);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ua_print_object(UA_BrowseResponse* res)
|
||||||
|
{
|
||||||
ua_pr_info("%-9s %-16s %-16s %-16s\n", "NAMESPACE", "NODEID", "BROWSE NAME", "DISPLAY NAME");
|
ua_pr_info("%-9s %-16s %-16s %-16s\n", "NAMESPACE", "NODEID", "BROWSE NAME", "DISPLAY NAME");
|
||||||
|
|
||||||
for(size_t i = 0; i < bResp.resultsSize; ++i)
|
for(size_t i = 0; i < res->resultsSize; ++i)
|
||||||
{
|
{
|
||||||
for(size_t j = 0; j < bResp.results[i].referencesSize; ++j)
|
for(size_t j = 0; j < res->results[i].referencesSize; ++j)
|
||||||
{
|
{
|
||||||
UA_ReferenceDescription *ref = &(bResp.results[i].references[j]);
|
UA_ReferenceDescription* ref = &(res->results[i].references[j]);
|
||||||
|
|
||||||
if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC)
|
if(ref->nodeId.nodeId.identifierType == UA_NODEIDTYPE_NUMERIC)
|
||||||
{
|
{
|
||||||
ua_pr_info("%-9d %-16d %-16.*s %-16.*s\n", ref->nodeId.nodeId.namespaceIndex,
|
ua_pr_info("%-9d %-16d %-16.*s %-16.*s\n", ref->nodeId.nodeId.namespaceIndex,
|
||||||
|
@ -100,92 +183,191 @@ void ua_browser_objects(UA_Client *client)
|
||||||
(int)ref->browseName.name.length, ref->browseName.name.data,
|
(int)ref->browseName.name.length, ref->browseName.name.data,
|
||||||
(int)ref->displayName.text.length, ref->displayName.text.data);
|
(int)ref->displayName.text.length, ref->displayName.text.data);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* TODO: distinguish further types */
|
/* TODO: distinguish further types */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ua_pr_info("\n");
|
ua_pr_info("\n");
|
||||||
UA_BrowseRequest_clear(&bReq);
|
}
|
||||||
UA_BrowseResponse_clear(&bResp);
|
|
||||||
|
UA_StatusCode ua_read_array_value(UA_Client* client, int array_size, UA_ReadValueId* array)
|
||||||
|
{
|
||||||
|
UA_ReadRequest request;
|
||||||
|
UA_ReadRequest_init(&request);
|
||||||
|
request.nodesToRead = array;
|
||||||
|
request.nodesToReadSize = array_size;
|
||||||
|
UA_ReadResponse response = UA_Client_Service_read(client, request);
|
||||||
|
|
||||||
|
if((response.responseHeader.serviceResult != UA_STATUSCODE_GOOD)
|
||||||
|
|| (response.resultsSize != array_size))
|
||||||
|
{
|
||||||
|
UA_ReadResponse_clear(&response);
|
||||||
|
ua_pr_info("ua: [%s] read failed 0x%x\n", __func__,
|
||||||
|
response.responseHeader.serviceResult);
|
||||||
|
return UA_STATUSCODE_BADUNEXPECTEDERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
UA_StatusCode* arr_ret = malloc(array_size * sizeof(UA_StatusCode));
|
||||||
|
|
||||||
|
for(int i = 0; i < array_size; ++i)
|
||||||
|
{
|
||||||
|
if((response.results[i].status == UA_STATUSCODE_GOOD)
|
||||||
|
&& (response.results[i].hasValue))
|
||||||
|
{
|
||||||
|
ua_pr_info("node %s: ", ua_get_nodeid_str(&array[i].nodeId));
|
||||||
|
ua_print_value(&response.results[i].value);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ua_pr_info("\n");
|
||||||
|
|
||||||
|
free(arr_ret);
|
||||||
|
UA_ReadResponse_clear(&response);
|
||||||
|
return UA_STATUSCODE_GOOD;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ua_browser_id(UA_Client* client, UA_NodeId id)
|
||||||
|
{
|
||||||
|
/* Browse some objects */
|
||||||
|
ua_pr_info("Browsing nodes in objects folder:\n");
|
||||||
|
UA_BrowseRequest bReq;
|
||||||
|
UA_BrowseRequest_init(&bReq);
|
||||||
|
bReq.requestedMaxReferencesPerNode = 0;
|
||||||
|
bReq.nodesToBrowse = UA_BrowseDescription_new();
|
||||||
|
bReq.nodesToBrowseSize = 1;
|
||||||
|
bReq.nodesToBrowse[0].nodeId = id; /* browse objects folder */
|
||||||
|
bReq.nodesToBrowse[0].resultMask = UA_BROWSERESULTMASK_ALL; /* return everything */
|
||||||
|
UA_BrowseResponse res = UA_Client_Service_browse(client, bReq);
|
||||||
|
ua_print_object(&res);
|
||||||
|
UA_BrowseResponse_clear(&res);
|
||||||
|
// UA_BrowseRequest_clear(&bReq);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ua_browser_nodes(UA_Client* client)
|
void ua_browser_nodes(UA_Client* client)
|
||||||
{
|
{
|
||||||
/* Same thing, this time using the node iterator... */
|
|
||||||
UA_NodeId* parent = UA_NodeId_new();
|
UA_NodeId* parent = UA_NodeId_new();
|
||||||
*parent = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
|
*parent = UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER);
|
||||||
UA_Client_forEachChildNodeCall(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
|
UA_Client_forEachChildNodeCall(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER), nodeIter, (void*) parent);
|
||||||
nodeIter, (void *) parent);
|
|
||||||
UA_NodeId_delete(parent);
|
UA_NodeId_delete(parent);
|
||||||
}
|
}
|
||||||
|
|
||||||
UA_UInt32 ua_start_sub(UA_Client *client)
|
UA_UInt32 ua_start_sub(UA_Client* client, UA_NodeId node_id)
|
||||||
{
|
{
|
||||||
/* Create a subscription */
|
/* Create a subscription */
|
||||||
UA_CreateSubscriptionRequest request = UA_CreateSubscriptionRequest_default();
|
UA_CreateSubscriptionRequest request = UA_CreateSubscriptionRequest_default();
|
||||||
UA_CreateSubscriptionResponse response = UA_Client_Subscriptions_create(client, request,
|
UA_CreateSubscriptionResponse response = UA_Client_Subscriptions_create(client, request,
|
||||||
NULL, NULL, NULL);
|
NULL, NULL, NULL);
|
||||||
|
|
||||||
UA_UInt32 subId = response.subscriptionId;
|
UA_UInt32 subId = response.subscriptionId;
|
||||||
|
|
||||||
if(response.responseHeader.serviceResult == UA_STATUSCODE_GOOD)
|
if(response.responseHeader.serviceResult == UA_STATUSCODE_GOOD)
|
||||||
|
{
|
||||||
ua_print("Create subscription succeeded, id %u\n", subId);
|
ua_print("Create subscription succeeded, id %u\n", subId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ua_print("Create subscription failed, id %u\n", response.responseHeader.serviceResult);
|
||||||
|
return response.responseHeader.serviceResult;
|
||||||
|
}
|
||||||
|
|
||||||
UA_MonitoredItemCreateRequest monRequest =
|
UA_MonitoredItemCreateRequest monRequest =
|
||||||
UA_MonitoredItemCreateRequest_default(UA_NODEID_STRING(1, "the.answer"));
|
UA_MonitoredItemCreateRequest_default(node_id);
|
||||||
|
|
||||||
UA_MonitoredItemCreateResult monResponse =
|
UA_MonitoredItemCreateResult monResponse =
|
||||||
UA_Client_MonitoredItems_createDataChange(client, response.subscriptionId,
|
UA_Client_MonitoredItems_createDataChange(client, response.subscriptionId,
|
||||||
UA_TIMESTAMPSTORETURN_BOTH,
|
UA_TIMESTAMPSTORETURN_BOTH,
|
||||||
monRequest, NULL, handler_TheAnswerChanged, NULL);
|
monRequest, NULL, handler_TheAnswerChanged, NULL);
|
||||||
if(monResponse.statusCode == UA_STATUSCODE_GOOD)
|
|
||||||
ua_print("Monitoring 'the.answer', id %u\n", monResponse.monitoredItemId);
|
|
||||||
|
|
||||||
|
if(monResponse.statusCode == UA_STATUSCODE_GOOD)
|
||||||
|
{
|
||||||
|
ua_print("Monitoring 'the.answer', id %u\n", monResponse.monitoredItemId);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
ua_print("%s return 0x%x\n", __func__, monResponse.statusCode);
|
||||||
|
}
|
||||||
|
|
||||||
/* The first publish request should return the initial value of the variable */
|
/* The first publish request should return the initial value of the variable */
|
||||||
UA_Client_run_iterate(client, 1000);
|
UA_Client_run_iterate(client, UA_RESPONSE_TIMEOUT);
|
||||||
return subId;
|
return subId;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ua_read_attr(UA_Client *client)
|
void ua_write_nodeid_value(UA_Client* client, UA_NodeId id, char* value)
|
||||||
{
|
{
|
||||||
/* Read attribute */
|
UA_Boolean bool_val;
|
||||||
UA_Int32 value = 0;
|
uint32_t integer_val;
|
||||||
ua_print("\nReading the value of node (1, \"the.answer\"):\n");
|
|
||||||
UA_Variant *val = UA_Variant_new();
|
|
||||||
UA_StatusCode retval = UA_Client_readValueAttribute(client, UA_NODEID_STRING(1, "the.answer"), val);
|
|
||||||
if(retval == UA_STATUSCODE_GOOD && UA_Variant_isScalar(val) &&
|
|
||||||
val->type == &UA_TYPES[UA_TYPES_INT32]) {
|
|
||||||
value = *(UA_Int32*)val->data;
|
|
||||||
ua_print("the value is: %i\n", value);
|
|
||||||
}
|
|
||||||
UA_Variant_delete(val);
|
|
||||||
|
|
||||||
/* Write node attribute */
|
|
||||||
value++;
|
|
||||||
ua_print("\nWriting a value of node (1, \"the.answer\"):\n");
|
|
||||||
UA_WriteRequest wReq;
|
UA_WriteRequest wReq;
|
||||||
UA_WriteRequest_init(&wReq);
|
UA_WriteRequest_init(&wReq);
|
||||||
|
|
||||||
wReq.nodesToWrite = UA_WriteValue_new();
|
wReq.nodesToWrite = UA_WriteValue_new();
|
||||||
wReq.nodesToWriteSize = 1;
|
wReq.nodesToWriteSize = 1;
|
||||||
wReq.nodesToWrite[0].nodeId = UA_NODEID_STRING_ALLOC(1, "the.answer");
|
|
||||||
|
if(strncmp(value, "1b", 2) == 0)
|
||||||
|
{
|
||||||
|
wReq.nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
|
||||||
|
bool_val = 1;
|
||||||
|
wReq.nodesToWrite[0].value.value.data = &bool_val;
|
||||||
|
}
|
||||||
|
else if(strncmp(value, "0b", 2) == 0)
|
||||||
|
{
|
||||||
|
wReq.nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_BOOLEAN];
|
||||||
|
bool_val = 0;
|
||||||
|
wReq.nodesToWrite[0].value.value.data = &bool_val;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
wReq.nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_INT16];
|
||||||
|
sscanf(value, "%d", &integer_val);
|
||||||
|
wReq.nodesToWrite[0].value.value.data = &integer_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
wReq.nodesToWrite[0].nodeId = id;
|
||||||
wReq.nodesToWrite[0].attributeId = UA_ATTRIBUTEID_VALUE;
|
wReq.nodesToWrite[0].attributeId = UA_ATTRIBUTEID_VALUE;
|
||||||
wReq.nodesToWrite[0].value.hasValue = true;
|
wReq.nodesToWrite[0].value.hasValue = true;
|
||||||
wReq.nodesToWrite[0].value.value.type = &UA_TYPES[UA_TYPES_INT32];
|
|
||||||
wReq.nodesToWrite[0].value.value.storageType = UA_VARIANT_DATA_NODELETE; /* do not free the integer on deletion */
|
wReq.nodesToWrite[0].value.value.storageType = UA_VARIANT_DATA_NODELETE; /* do not free the integer on deletion */
|
||||||
wReq.nodesToWrite[0].value.value.data = &value;
|
|
||||||
UA_WriteResponse wResp = UA_Client_Service_write(client, wReq);
|
UA_WriteResponse wResp = UA_Client_Service_write(client, wReq);
|
||||||
|
|
||||||
if(wResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD)
|
if(wResp.responseHeader.serviceResult == UA_STATUSCODE_GOOD)
|
||||||
ua_print("the new value is: %i\n", value);
|
{
|
||||||
|
ua_pr_info("write new value is: %s\n", value);
|
||||||
|
}
|
||||||
|
|
||||||
UA_WriteRequest_clear(&wReq);
|
UA_WriteRequest_clear(&wReq);
|
||||||
UA_WriteResponse_clear(&wResp);
|
UA_WriteResponse_clear(&wResp);
|
||||||
|
|
||||||
/* Write node attribute (using the highlevel API) */
|
// /* Write node attribute (using the highlevel API) */
|
||||||
value++;
|
// value++;
|
||||||
UA_Variant *myVariant = UA_Variant_new();
|
// UA_Variant *myVariant = UA_Variant_new();
|
||||||
UA_Variant_setScalarCopy(myVariant, &value, &UA_TYPES[UA_TYPES_INT32]);
|
// UA_Variant_setScalarCopy(myVariant, &value, &UA_TYPES[UA_TYPES_INT32]);
|
||||||
UA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, "the.answer"), myVariant);
|
// UA_Client_writeValueAttribute(client, UA_NODEID_STRING(1, UA_NODE_STR), myVariant);
|
||||||
UA_Variant_delete(myVariant);
|
// UA_Variant_delete(myVariant);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Read attribute */
|
||||||
|
void ua_read_nodeid_value(UA_Client* client, UA_NodeId id, UA_Int32 *value)
|
||||||
|
{
|
||||||
|
UA_Variant* val = UA_Variant_new();
|
||||||
|
UA_StatusCode ret = UA_Client_readValueAttribute(client, id, val);
|
||||||
|
|
||||||
|
if(ret == UA_STATUSCODE_GOOD)
|
||||||
|
{
|
||||||
|
ua_print_value(val);
|
||||||
|
if(UA_Variant_isScalar(val))
|
||||||
|
{
|
||||||
|
if(val->type == &UA_TYPES[UA_TYPES_BOOLEAN])
|
||||||
|
{
|
||||||
|
*value = *(UA_Boolean *)val->data;
|
||||||
|
}
|
||||||
|
else if(val->type == &UA_TYPES[UA_TYPES_INT32])
|
||||||
|
{
|
||||||
|
*value = *(UA_Int32 *)val->data;
|
||||||
|
}
|
||||||
|
else if(val->type == &UA_TYPES[UA_TYPES_INT16])
|
||||||
|
{
|
||||||
|
*value = *(UA_Int16 *)val->data;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UA_Variant_delete(val);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ua_call_remote(UA_Client* client)
|
void ua_call_remote(UA_Client* client)
|
||||||
|
@ -197,9 +379,10 @@ void ua_call_remote(UA_Client *client)
|
||||||
UA_Variant_setScalarCopy(&input, &argString, &UA_TYPES[UA_TYPES_STRING]);
|
UA_Variant_setScalarCopy(&input, &argString, &UA_TYPES[UA_TYPES_STRING]);
|
||||||
size_t outputSize;
|
size_t outputSize;
|
||||||
UA_Variant* output;
|
UA_Variant* output;
|
||||||
UA_StatusCode retval = UA_Client_call(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
|
UA_StatusCode ret = UA_Client_call(client, UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
|
||||||
UA_NODEID_NUMERIC(1, 62541), 1, &input, &outputSize, &output);
|
UA_NODEID_NUMERIC(1, 62541), 1, &input, &outputSize, &output);
|
||||||
if(retval == UA_STATUSCODE_GOOD)
|
|
||||||
|
if(ret == UA_STATUSCODE_GOOD)
|
||||||
{
|
{
|
||||||
ua_print("Method call was successful, and %lu returned values available.\n",
|
ua_print("Method call was successful, and %lu returned values available.\n",
|
||||||
(unsigned long)outputSize);
|
(unsigned long)outputSize);
|
||||||
|
@ -207,8 +390,9 @@ void ua_call_remote(UA_Client *client)
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ua_print("Method call was unsuccessful, and %x returned values available.\n", retval);
|
ua_print("Method call was unsuccessful, and %x returned values available.\n", ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
UA_Variant_clear(&input);
|
UA_Variant_clear(&input);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -222,43 +406,52 @@ void ua_add_nodes(UA_Client *client)
|
||||||
ref_attr.displayName = UA_LOCALIZEDTEXT("en-US", "NewReference");
|
ref_attr.displayName = UA_LOCALIZEDTEXT("en-US", "NewReference");
|
||||||
ref_attr.description = UA_LOCALIZEDTEXT("en-US", "References something that might or might not exist");
|
ref_attr.description = UA_LOCALIZEDTEXT("en-US", "References something that might or might not exist");
|
||||||
ref_attr.inverseName = UA_LOCALIZEDTEXT("en-US", "IsNewlyReferencedBy");
|
ref_attr.inverseName = UA_LOCALIZEDTEXT("en-US", "IsNewlyReferencedBy");
|
||||||
UA_StatusCode retval = UA_Client_addReferenceTypeNode(client,
|
UA_StatusCode ret = UA_Client_addReferenceTypeNode(client,
|
||||||
UA_NODEID_NUMERIC(1, 12133),
|
UA_NODEID_NUMERIC(1, 12133),
|
||||||
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
|
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
|
||||||
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
|
||||||
UA_QUALIFIEDNAME(1, "NewReference"),
|
UA_QUALIFIEDNAME(1, "NewReference"),
|
||||||
ref_attr, &ref_id);
|
ref_attr, &ref_id);
|
||||||
if(retval == UA_STATUSCODE_GOOD )
|
|
||||||
|
if(ret == UA_STATUSCODE_GOOD)
|
||||||
|
{
|
||||||
ua_print("Created 'NewReference' with numeric NodeID %u\n", ref_id.identifier.numeric);
|
ua_print("Created 'NewReference' with numeric NodeID %u\n", ref_id.identifier.numeric);
|
||||||
|
}
|
||||||
|
|
||||||
/* New ObjectType */
|
/* New ObjectType */
|
||||||
UA_NodeId objt_id;
|
UA_NodeId objt_id;
|
||||||
UA_ObjectTypeAttributes objt_attr = UA_ObjectTypeAttributes_default;
|
UA_ObjectTypeAttributes objt_attr = UA_ObjectTypeAttributes_default;
|
||||||
objt_attr.displayName = UA_LOCALIZEDTEXT("en-US", "TheNewObjectType");
|
objt_attr.displayName = UA_LOCALIZEDTEXT("en-US", "TheNewObjectType");
|
||||||
objt_attr.description = UA_LOCALIZEDTEXT("en-US", "Put innovative description here");
|
objt_attr.description = UA_LOCALIZEDTEXT("en-US", "Put innovative description here");
|
||||||
retval = UA_Client_addObjectTypeNode(client,
|
ret = UA_Client_addObjectTypeNode(client,
|
||||||
UA_NODEID_NUMERIC(1, 12134),
|
UA_NODEID_NUMERIC(1, 12134),
|
||||||
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
|
UA_NODEID_NUMERIC(0, UA_NS0ID_BASEOBJECTTYPE),
|
||||||
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
|
UA_NODEID_NUMERIC(0, UA_NS0ID_HASSUBTYPE),
|
||||||
UA_QUALIFIEDNAME(1, "NewObjectType"),
|
UA_QUALIFIEDNAME(1, "NewObjectType"),
|
||||||
objt_attr, &objt_id);
|
objt_attr, &objt_id);
|
||||||
if(retval == UA_STATUSCODE_GOOD)
|
|
||||||
|
if(ret == UA_STATUSCODE_GOOD)
|
||||||
|
{
|
||||||
ua_print("Created 'NewObjectType' with numeric NodeID %u\n", objt_id.identifier.numeric);
|
ua_print("Created 'NewObjectType' with numeric NodeID %u\n", objt_id.identifier.numeric);
|
||||||
|
}
|
||||||
|
|
||||||
/* New Object */
|
/* New Object */
|
||||||
UA_NodeId obj_id;
|
UA_NodeId obj_id;
|
||||||
UA_ObjectAttributes obj_attr = UA_ObjectAttributes_default;
|
UA_ObjectAttributes obj_attr = UA_ObjectAttributes_default;
|
||||||
obj_attr.displayName = UA_LOCALIZEDTEXT("en-US", "TheNewGreatNode");
|
obj_attr.displayName = UA_LOCALIZEDTEXT("en-US", "TheNewGreatNode");
|
||||||
obj_attr.description = UA_LOCALIZEDTEXT("de-DE", "Hier koennte Ihre Webung stehen!");
|
obj_attr.description = UA_LOCALIZEDTEXT("de-DE", "Hier koennte Ihre Webung stehen!");
|
||||||
retval = UA_Client_addObjectNode(client,
|
ret = UA_Client_addObjectNode(client,
|
||||||
UA_NODEID_NUMERIC(1, 0),
|
UA_NODEID_NUMERIC(1, 0),
|
||||||
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
|
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
|
||||||
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
|
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
|
||||||
UA_QUALIFIEDNAME(1, "TheGreatNode"),
|
UA_QUALIFIEDNAME(1, "TheGreatNode"),
|
||||||
UA_NODEID_NUMERIC(1, 12134),
|
UA_NODEID_NUMERIC(1, 12134),
|
||||||
obj_attr, &obj_id);
|
obj_attr, &obj_id);
|
||||||
if(retval == UA_STATUSCODE_GOOD )
|
|
||||||
|
if(ret == UA_STATUSCODE_GOOD)
|
||||||
|
{
|
||||||
ua_print("Created 'NewObject' with numeric NodeID %u\n", obj_id.identifier.numeric);
|
ua_print("Created 'NewObject' with numeric NodeID %u\n", obj_id.identifier.numeric);
|
||||||
|
}
|
||||||
|
|
||||||
/* New Integer Variable */
|
/* New Integer Variable */
|
||||||
UA_NodeId var_id;
|
UA_NodeId var_id;
|
||||||
|
@ -270,68 +463,36 @@ void ua_add_nodes(UA_Client *client)
|
||||||
/* This does not copy the value */
|
/* This does not copy the value */
|
||||||
UA_Variant_setScalar(&var_attr.value, &int_value, &UA_TYPES[UA_TYPES_INT32]);
|
UA_Variant_setScalar(&var_attr.value, &int_value, &UA_TYPES[UA_TYPES_INT32]);
|
||||||
var_attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
|
var_attr.dataType = UA_TYPES[UA_TYPES_INT32].typeId;
|
||||||
retval = UA_Client_addVariableNode(client,
|
ret = UA_Client_addVariableNode(client,
|
||||||
UA_NODEID_NUMERIC(1, 0), // Assign new/random NodeID
|
UA_NODEID_NUMERIC(1, 0), // Assign new/random NodeID
|
||||||
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
|
UA_NODEID_NUMERIC(0, UA_NS0ID_OBJECTSFOLDER),
|
||||||
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
|
UA_NODEID_NUMERIC(0, UA_NS0ID_ORGANIZES),
|
||||||
UA_QUALIFIEDNAME(0, "VariableNode"),
|
UA_QUALIFIEDNAME(0, "VariableNode"),
|
||||||
UA_NODEID_NULL, // no variable type
|
UA_NODEID_NULL, // no variable type
|
||||||
var_attr, &var_id);
|
var_attr, &var_id);
|
||||||
if(retval == UA_STATUSCODE_GOOD )
|
|
||||||
ua_print("Created 'NewVariable' with numeric NodeID %u\n", var_id.identifier.numeric);
|
|
||||||
|
|
||||||
}
|
if(ret == UA_STATUSCODE_GOOD)
|
||||||
|
|
||||||
int ua_get_server_info(UA_Client *client)
|
|
||||||
{
|
{
|
||||||
ua_browser_objects(client);
|
ua_print("Created 'NewVariable' with numeric NodeID %u\n", var_id.identifier.numeric);
|
||||||
|
}
|
||||||
/* Same thing, this time using the node iterator... */
|
|
||||||
ua_browser_nodes(client);
|
|
||||||
|
|
||||||
#ifdef UA_ENABLE_SUBSCRIPTIONS
|
|
||||||
UA_Int32 subId = ua_start_sub(client);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
ua_read_attr(client);
|
|
||||||
|
|
||||||
#ifdef UA_ENABLE_SUBSCRIPTIONS
|
|
||||||
/* Take another look at the.answer */
|
|
||||||
UA_Client_run_iterate(client, 100);
|
|
||||||
/* Delete the subscription */
|
|
||||||
if(UA_Client_Subscriptions_deleteSingle(client, subId) == UA_STATUSCODE_GOOD)
|
|
||||||
ua_print("Subscription removed\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef UA_ENABLE_METHODCALLS
|
|
||||||
ua_call_remote(client);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef UA_ENABLE_NODEMANAGEMENT
|
|
||||||
ua_add_nodes(client);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ua_read_time(UA_Client* client)
|
void ua_read_time(UA_Client* client)
|
||||||
{
|
{
|
||||||
/* Read the value attribute of the node. UA_Client_readValueAttribute is a
|
UA_Variant value;
|
||||||
* wrapper for the raw read service available as UA_Client_Service_read. */
|
|
||||||
UA_Variant value; /* Variants can hold scalar values and arrays of any type */
|
|
||||||
UA_Variant_init(&value);
|
UA_Variant_init(&value);
|
||||||
|
|
||||||
/* NodeId of the variable holding the current time */
|
|
||||||
const UA_NodeId nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
|
const UA_NodeId nodeId = UA_NODEID_NUMERIC(0, UA_NS0ID_SERVER_SERVERSTATUS_CURRENTTIME);
|
||||||
UA_StatusCode retval = UA_Client_readValueAttribute(client, nodeId, &value);
|
UA_StatusCode ret = UA_Client_readValueAttribute(client, nodeId, &value);
|
||||||
|
|
||||||
if(retval == UA_STATUSCODE_GOOD && UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_DATETIME]))
|
if(ret == UA_STATUSCODE_GOOD && UA_Variant_hasScalarType(&value, &UA_TYPES[UA_TYPES_DATETIME]))
|
||||||
{
|
{
|
||||||
UA_DateTime raw_date = *(UA_DateTime*) value.data;
|
UA_DateTime raw_date = *(UA_DateTime*) value.data;
|
||||||
UA_DateTimeStruct dts = UA_DateTime_toStruct(raw_date);
|
UA_DateTimeStruct dts = UA_DateTime_toStruct(raw_date);
|
||||||
UA_LOG_INFO(UA_Log_Stdout, UA_LOGCATEGORY_USERLAND, "date is: %u-%u-%u %u:%u:%u.%03u\n",
|
ua_pr_info("date is: %d-%d-%d %d:%d:%d.%03d\n",
|
||||||
dts.day, dts.month, dts.year, dts.hour, dts.min, dts.sec, dts.milliSec);
|
dts.day, dts.month, dts.year, dts.hour, dts.min, dts.sec, dts.milliSec);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
UA_Variant_clear(&value);
|
UA_Variant_clear(&value);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,17 +10,85 @@
|
||||||
* See the Mulan PSL v2 for more details.
|
* See the Mulan PSL v2 for more details.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file ua_test.c
|
||||||
|
* @brief Test for OpcUa function
|
||||||
|
* @version 1.0
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2021.11.11
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "open62541.h"
|
||||||
|
#include "ua_api.h"
|
||||||
|
|
||||||
|
//for target NODEID
|
||||||
|
#define UA_TEST_BROWSER_NODEID UA_NODEID_STRING(3, "ServerInterfaces")
|
||||||
|
#define UA_TEST_BROWSER_NODEID1 UA_NODEID_NUMERIC(4, 1)
|
||||||
|
#define UA_TEST_WRITE_NODEID UA_NODEID_NUMERIC(4, 5)
|
||||||
|
|
||||||
|
|
||||||
|
static UA_StatusCode ua_test_read_array(UA_Client *client)
|
||||||
|
{
|
||||||
|
const int item_size = 4;
|
||||||
|
UA_ReadValueId test_item[item_size];
|
||||||
|
|
||||||
|
for (int i = 0; i < item_size; i++)
|
||||||
|
{
|
||||||
|
UA_ReadValueId_init(&test_item[i]);
|
||||||
|
test_item[i].attributeId = UA_ATTRIBUTEID_VALUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
test_item[0].nodeId = UA_NODEID_NUMERIC(4, 2);
|
||||||
|
test_item[1].nodeId = UA_NODEID_NUMERIC(4, 3);
|
||||||
|
test_item[2].nodeId = UA_NODEID_NUMERIC(4, 4);
|
||||||
|
test_item[3].nodeId = UA_NODEID_NUMERIC(4, 5);
|
||||||
|
|
||||||
|
return ua_read_array_value(client, item_size, test_item);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ua_test_browser_objects(UA_Client *client)
|
||||||
|
{
|
||||||
|
UA_NodeId test_id;
|
||||||
|
ua_browser_id(client, UA_TEST_BROWSER_NODEID);
|
||||||
|
ua_browser_id(client, UA_TEST_BROWSER_NODEID1);
|
||||||
|
test_id = UA_TEST_BROWSER_NODEID1;
|
||||||
|
ua_pr_info("Show values in %s:\n", ua_get_nodeid_str(&test_id));
|
||||||
|
ua_test_read_array(client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ua_test_write_attr(UA_Client *client)
|
||||||
|
{
|
||||||
|
UA_Int32 value;
|
||||||
|
char val_str[UA_NODE_LEN];
|
||||||
|
UA_NodeId id = UA_TEST_WRITE_NODEID;
|
||||||
|
|
||||||
|
ua_pr_info("--- Test write %s ---\n", ua_get_nodeid_str(&id));
|
||||||
|
ua_read_nodeid_value(client, id, &value);
|
||||||
|
ua_write_nodeid_value(client, id, itoa(value + 1, val_str, 10));
|
||||||
|
ua_read_nodeid_value(client, id, &value);
|
||||||
|
ua_pr_info("\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
int ua_test_interact_server(UA_Client *client)
|
||||||
|
{
|
||||||
|
ua_read_time(client);
|
||||||
|
ua_test_browser_objects(client);
|
||||||
|
ua_test_write_attr(client);
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
int16 ua_test(void)
|
int16 ua_test(void)
|
||||||
{
|
{
|
||||||
UA_Client *client = UA_Client_new();
|
UA_Client *client = UA_Client_new();
|
||||||
UA_StatusCode retval = UA_Client_connect(client, OPC_SERVER);
|
UA_StatusCode retval = UA_Client_connect(client, opc_server_url);
|
||||||
if(retval != UA_STATUSCODE_GOOD) {
|
if(retval != UA_STATUSCODE_GOOD) {
|
||||||
UA_Client_delete(client);
|
UA_Client_delete(client);
|
||||||
return (int)retval;
|
return (int)retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
ua_read_time(client);
|
ua_read_time(client);
|
||||||
ua_run_test(client);
|
|
||||||
|
|
||||||
/* Clean up */
|
/* Clean up */
|
||||||
UA_Client_disconnect(client);
|
UA_Client_disconnect(client);
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
SRC_FILES := plc.c
|
SRC_FILES := plc_device.c plc_channel.c plc_driver.c
|
||||||
|
|
||||||
include $(KERNEL_ROOT)/compiler.mk
|
include $(KERNEL_ROOT)/compiler.mk
|
||||||
|
|
||||||
|
|
|
@ -1,58 +0,0 @@
|
||||||
/*
|
|
||||||
* Copyright (c) 2021 AIIT XUOS Lab
|
|
||||||
* XiUOS is licensed under Mulan PSL v2.
|
|
||||||
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
|
||||||
* You may obtain a copy of Mulan PSL v2 at:
|
|
||||||
* http://license.coscl.org.cn/MulanPSL2
|
|
||||||
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
|
||||||
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
|
||||||
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
|
||||||
* See the Mulan PSL v2 for more details.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @file plc.c
|
|
||||||
* @brief plc relative activities
|
|
||||||
* @version 1.0
|
|
||||||
* @author AIIT XUOS Lab
|
|
||||||
* @date 2021.12.15
|
|
||||||
*/
|
|
||||||
#ifdef USING_CONTROL_PLC_OPCUA
|
|
||||||
#include "../interoperability/opcua/open62541.h"
|
|
||||||
#endif
|
|
||||||
#include "plc.h"
|
|
||||||
|
|
||||||
|
|
||||||
struct PlcDevice plc_device;
|
|
||||||
|
|
||||||
// open and connect PLC device
|
|
||||||
void plc_open(struct PlcDevice *pdev)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// close and disconnect PLC device
|
|
||||||
void plc_close(struct PlcDevice *pdev)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// read data from PLC
|
|
||||||
void plc_read(struct PlcDevice *pdev, void *buf, size_t len)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// write data from PLC
|
|
||||||
void plc_write(struct PlcDevice *pdev, const void *buf, size_t len)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
// send control command to PLC
|
|
||||||
void plc_ioctl(struct PlcDevice *pdev, int cmd, void *arg)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void plc_init(struct PlcDevice *plc_dev)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,538 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 AIIT XUOS Lab
|
||||||
|
* XiUOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file plc_ch.c
|
||||||
|
* @brief Support channel driver framework provide ch API version 1.0
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2021-04-24
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "string.h"
|
||||||
|
#include "plc_channel.h"
|
||||||
|
#include "plc_device.h"
|
||||||
|
#include "transform.h"
|
||||||
|
|
||||||
|
DoublelistType ch_linklist;
|
||||||
|
|
||||||
|
/*Create the ch linklist*/
|
||||||
|
static void ChannelLinkInit(struct Channel *ch)
|
||||||
|
{
|
||||||
|
static uint8 ch_link_flag = RET_FALSE;
|
||||||
|
|
||||||
|
if(!ch_link_flag) {
|
||||||
|
AppInitDoubleList(&ch_linklist);
|
||||||
|
ch_link_flag = RET_TRUE;
|
||||||
|
ch->ch_link_flag = RET_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Create the driver of the ch linklist*/
|
||||||
|
if(!ch->ch_drvlink_flag) {
|
||||||
|
AppInitDoubleList(&ch->ch_drvlink);
|
||||||
|
ch->ch_drvlink_flag = RET_TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*Create the hardware device of the ch linklist*/
|
||||||
|
if(!ch->ch_devlink_flag) {
|
||||||
|
AppInitDoubleList(&ch->ch_devlink);
|
||||||
|
ch->ch_devlink_flag = RET_TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int ChannelMatchDrvDev(struct ChDrv *driver, struct ChDev *device)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(driver);
|
||||||
|
CHECK_CH_PARAM(device);
|
||||||
|
|
||||||
|
if(!strncmp(driver->owner_ch->ch_name, device->owner_ch->ch_name, NAME_NUM_MAX)) {
|
||||||
|
KPrintf("ChannelMatchDrvDev match successfully, ch name %s\n", driver->owner_ch->ch_name);
|
||||||
|
|
||||||
|
driver->private_data = device->private_data;//driver get the device param
|
||||||
|
device->owner_ch->owner_driver = driver;
|
||||||
|
driver->owner_ch->owner_haldev = device;
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to obtain ch for a certain dev if necessary, then configure and init its drv
|
||||||
|
* @param ch - ch pointer
|
||||||
|
* @param dev - dev pointer
|
||||||
|
* @param drv_name - drv name
|
||||||
|
* @param config - ChConfigInfo pointer
|
||||||
|
* @return successful:EOK,failed:ERROR
|
||||||
|
*/
|
||||||
|
int DeviceObtainChannel(struct Channel *ch, struct ChDev *dev, const char *drv_name, struct ChConfigInfo *cfg)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(ch);
|
||||||
|
CHECK_CH_PARAM(dev);
|
||||||
|
|
||||||
|
int32 ret = EOK;
|
||||||
|
|
||||||
|
ret = PrivMutexObtain(&ch->ch_lock);
|
||||||
|
if(EOK != ret) {
|
||||||
|
KPrintf("DevObtainChannel ch_lock error %d!\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ch->owner_haldev != dev) {
|
||||||
|
struct ChDrv *drv = ChannelFindDriver(ch, drv_name);
|
||||||
|
|
||||||
|
cfg->configure_cmd = OPE_CFG;
|
||||||
|
drv->configure(drv, cfg);
|
||||||
|
|
||||||
|
cfg->configure_cmd = OPE_INT;
|
||||||
|
drv->configure(drv, cfg);
|
||||||
|
|
||||||
|
ch->owner_haldev = dev;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to register ch pointer with linklist
|
||||||
|
* @param ch - ch pointer
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
int ChannelRegister(struct Channel *ch)
|
||||||
|
{
|
||||||
|
int ret = EOK;
|
||||||
|
CHECK_CH_PARAM(ch);
|
||||||
|
|
||||||
|
ch->match = ChannelMatchDrvDev;
|
||||||
|
|
||||||
|
ChannelLinkInit(ch);
|
||||||
|
|
||||||
|
PrivMutexCreate(&ch->ch_lock, NULL);
|
||||||
|
|
||||||
|
AppDoubleListInsertNodeAfter(&ch_linklist, &(ch->ch_link));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to release ch pointer in linklist
|
||||||
|
* @param ch - ch pointer
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
int ChannelRelease(struct Channel *ch)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(ch);
|
||||||
|
|
||||||
|
PrivMutexAbandon(&ch->ch_lock);
|
||||||
|
|
||||||
|
ch->ch_cnt = 0;
|
||||||
|
ch->driver_cnt = 0;
|
||||||
|
ch->haldev_cnt = 0;
|
||||||
|
|
||||||
|
ch->ch_link_flag = RET_FALSE;
|
||||||
|
ch->ch_drvlink_flag = RET_FALSE;
|
||||||
|
ch->ch_devlink_flag = RET_FALSE;
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to unregister ch pointer and delete its linklist node
|
||||||
|
* @param ch - ch pointer
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
int ChannelUnregister(struct Channel *ch)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(ch);
|
||||||
|
|
||||||
|
ch->ch_cnt--;
|
||||||
|
|
||||||
|
AppDoubleListRmNode(&(ch->ch_link));
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to register driver pointer to ch pointer
|
||||||
|
* @param ch - ch pointer
|
||||||
|
* @param driver - driver pointer
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
int DriverRegisterToChannel(struct Channel *ch, struct ChDrv *driver)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(ch);
|
||||||
|
CHECK_CH_PARAM(driver);
|
||||||
|
|
||||||
|
driver->owner_ch = ch;
|
||||||
|
ch->driver_cnt++;
|
||||||
|
|
||||||
|
AppDoubleListInsertNodeAfter(&ch->ch_drvlink, &(driver->driver_link));
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to register dev pointer to ch pointer
|
||||||
|
* @param ch - ch pointer
|
||||||
|
* @param device - device pointer
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
int DeviceRegisterToChannel(struct Channel *ch, struct ChDev *device)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(ch);
|
||||||
|
CHECK_CH_PARAM(device);
|
||||||
|
|
||||||
|
device->owner_ch = ch;
|
||||||
|
ch->haldev_cnt++;
|
||||||
|
|
||||||
|
AppDoubleListInsertNodeAfter(&ch->ch_devlink, &(device->dev_link));
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to delete driver pointer from ch pointer
|
||||||
|
* @param ch - ch pointer
|
||||||
|
* @param driver - driver pointer
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
int DriverDeleteFromChannel(struct Channel *ch, struct ChDrv *driver)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(ch);
|
||||||
|
CHECK_CH_PARAM(driver);
|
||||||
|
|
||||||
|
ch->driver_cnt--;
|
||||||
|
|
||||||
|
AppDoubleListRmNode(&(driver->driver_link));
|
||||||
|
|
||||||
|
free(driver);
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to delete dev pointer from ch pointer
|
||||||
|
* @param ch - ch pointer
|
||||||
|
* @param device - device pointer
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
int DeviceDeleteFromChannel(struct Channel *ch, struct ChDev *device)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(ch);
|
||||||
|
CHECK_CH_PARAM(device);
|
||||||
|
|
||||||
|
ch->haldev_cnt--;
|
||||||
|
|
||||||
|
AppDoubleListRmNode(&(device->dev_link));
|
||||||
|
|
||||||
|
free(device);
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to find ch pointer by ch name
|
||||||
|
* @param ch_name - ch name
|
||||||
|
* @return successful:ch pointer,failed:NONE
|
||||||
|
*/
|
||||||
|
ChannelType ChannelFind(const char *ch_name)
|
||||||
|
{
|
||||||
|
struct Channel *ch = NONE;
|
||||||
|
|
||||||
|
DoublelistType *node = NONE;
|
||||||
|
DoublelistType *head = &ch_linklist;
|
||||||
|
|
||||||
|
for (node = head->node_next; node != head; node = node->node_next)
|
||||||
|
{
|
||||||
|
ch = DOUBLE_LIST_ENTRY(node, struct Channel, ch_link);
|
||||||
|
if(!strcmp(ch->ch_name, ch_name)) {
|
||||||
|
return ch;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KPrintf("ChannelFind cannot find the %s ch.return NULL\n", ch_name);
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to find driver pointer of certain ch by driver name
|
||||||
|
* @param ch - ch pointer
|
||||||
|
* @param driver_name - driver name
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
ChDrvType ChannelFindDriver(struct Channel *ch, const char *driver_name)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(ch);
|
||||||
|
struct ChDrv *driver = NONE;
|
||||||
|
|
||||||
|
DoublelistType *node = NONE;
|
||||||
|
DoublelistType *head = &ch->ch_drvlink;
|
||||||
|
|
||||||
|
for (node = head->node_next; node != head; node = node->node_next)
|
||||||
|
{
|
||||||
|
driver = DOUBLE_LIST_ENTRY(node, struct ChDrv, driver_link);
|
||||||
|
if(!strcmp(driver->drv_name, driver_name)) {
|
||||||
|
return driver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KPrintf("ChannelFindDriver cannot find the %s driver.return NULL\n", driver_name);
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to find device pointer of certain ch by device name
|
||||||
|
* @param ch - ch pointer
|
||||||
|
* @param device_name - device name
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
ChDevType ChannelFindDevice(struct Channel *ch, const char *device_name)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(ch);
|
||||||
|
struct ChDev *device = NONE;
|
||||||
|
|
||||||
|
DoublelistType *node = NONE;
|
||||||
|
DoublelistType *head = &ch->ch_devlink;
|
||||||
|
|
||||||
|
for (node = head->node_next; node != head; node = node->node_next)
|
||||||
|
{
|
||||||
|
device = DOUBLE_LIST_ENTRY(node, struct ChDev, dev_link);
|
||||||
|
|
||||||
|
if(!strcmp(device->dev_name, device_name)) {
|
||||||
|
return device;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KPrintf("ChannelFindDevice cannot find the %s device.return NULL\n", device_name);
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to set dev receive function callback
|
||||||
|
* @param dev - dev pointer
|
||||||
|
* @param dev_recv_callback - callback function
|
||||||
|
* @return successful:EOK,failed:ERROR
|
||||||
|
*/
|
||||||
|
uint32 ChannelDevRecvCallback(struct ChDev *dev, int (*dev_recv_callback) (void *dev, x_size_t length))
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(dev );
|
||||||
|
|
||||||
|
dev->dev_recv_callback = dev_recv_callback;
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to open dev
|
||||||
|
* @param dev - dev pointer
|
||||||
|
* @return successful:EOK,failed:ERROR
|
||||||
|
*/
|
||||||
|
uint32 ChannelDevOpen(struct ChDev *dev)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(dev);
|
||||||
|
|
||||||
|
int ret = EOK;
|
||||||
|
|
||||||
|
if (dev->dev_done->open) {
|
||||||
|
ret = dev->dev_done->open(dev);
|
||||||
|
if(ret) {
|
||||||
|
KPrintf("ChannelDevOpen error ret %u\n", ret);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to close dev
|
||||||
|
* @param dev - dev pointer
|
||||||
|
* @return successful:EOK,failed:ERROR
|
||||||
|
*/
|
||||||
|
uint32 ChannelDevClose(struct ChDev *dev)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(dev);
|
||||||
|
|
||||||
|
int ret = EOK;
|
||||||
|
|
||||||
|
if (dev->dev_done->close) {
|
||||||
|
ret = dev->dev_done->close(dev);
|
||||||
|
if(ret) {
|
||||||
|
KPrintf("ChannelDevClose error ret %u\n", ret);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to write data to dev
|
||||||
|
* @param dev - dev pointer
|
||||||
|
* @param write_param - ChWriteParam
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
uint32 ChannelDevWriteData(struct ChDev *dev, struct ChWriteParam *write_param)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(dev);
|
||||||
|
|
||||||
|
if (dev->dev_done->write) {
|
||||||
|
return dev->dev_done->write(dev, write_param);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to read data from dev
|
||||||
|
* @param dev - dev pointer
|
||||||
|
* @param read_param - ChReadParam
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
uint32 ChannelDevReadData(struct ChDev *dev, struct ChReadParam *read_param)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(dev);
|
||||||
|
|
||||||
|
if (dev->dev_done->read) {
|
||||||
|
return dev->dev_done->read(dev, read_param);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @Description: support to configure drv, include OPE_CFG and OPE_INT
|
||||||
|
* @param drv - drv pointer
|
||||||
|
* @param config - ChConfigInfo
|
||||||
|
* @return successful:EOK,failed:NONE
|
||||||
|
*/
|
||||||
|
uint32 ChannelDrvConfigure(struct ChDrv *drv, struct ChConfigInfo *config)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(drv);
|
||||||
|
CHECK_CH_PARAM(config);
|
||||||
|
|
||||||
|
int ret = EOK;
|
||||||
|
|
||||||
|
if (drv->configure) {
|
||||||
|
ret = drv->configure(drv, config);
|
||||||
|
if(ret) {
|
||||||
|
KPrintf("ChannelDrvCfg error, ret %u\n", ret);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PlcChannelInit(struct PlcChannel* plc_ch, const char* ch_name)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(plc_ch);
|
||||||
|
CHECK_CH_PARAM(ch_name);
|
||||||
|
int ret = EOK;
|
||||||
|
|
||||||
|
if(CHANNEL_INSTALL != plc_ch->ch.ch_state)
|
||||||
|
{
|
||||||
|
strncpy(plc_ch->ch.ch_name, ch_name, NAME_NUM_MAX);
|
||||||
|
plc_ch->ch.ch_type = CH_PLC_TYPE;
|
||||||
|
plc_ch->ch.ch_state = CHANNEL_INSTALL;
|
||||||
|
plc_ch->ch.private_data = plc_ch->private_data;
|
||||||
|
ret = ChannelRegister(&plc_ch->ch);
|
||||||
|
|
||||||
|
if(EOK != ret)
|
||||||
|
{
|
||||||
|
KPrintf("PlcChannelInit ChannelRegister error %u\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KPrintf("PlcChannelInit ChannelRegister channel has been register state %u\n",
|
||||||
|
plc_ch->ch.ch_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PlcDriverInit(struct PlcDriver* plc_driver, const char* driver_name)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(plc_driver);
|
||||||
|
CHECK_CH_PARAM(driver_name);
|
||||||
|
int ret = EOK;
|
||||||
|
|
||||||
|
if(CHDRV_INSTALL != plc_driver->driver.driver_state)
|
||||||
|
{
|
||||||
|
plc_driver->driver.driver_type = CHDRV_PLC_TYPE;
|
||||||
|
plc_driver->driver.driver_state = CHDRV_INSTALL;
|
||||||
|
strncpy(plc_driver->driver.drv_name, driver_name, NAME_NUM_MAX);
|
||||||
|
plc_driver->driver.configure = plc_driver->configure;
|
||||||
|
ret = PlcDriverRegister(&plc_driver->driver);
|
||||||
|
|
||||||
|
if(EOK != ret)
|
||||||
|
{
|
||||||
|
KPrintf("PlcDriverInit DriverRegister error %u\n", ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
KPrintf("PlcDriverInit Driver %s has been register state %u\n",
|
||||||
|
driver_name, plc_driver->driver.driver_state);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PlcReleaseChannel(struct PlcChannel* plc_ch)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(plc_ch);
|
||||||
|
return ChannelRelease(&plc_ch->ch);
|
||||||
|
}
|
||||||
|
|
||||||
|
int PlcDriverAttachToChannel(const char* drv_name, const char* ch_name)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(drv_name);
|
||||||
|
CHECK_CH_PARAM(ch_name);
|
||||||
|
int ret = EOK;
|
||||||
|
struct Channel* ch;
|
||||||
|
struct ChDrv* driver;
|
||||||
|
ch = ChannelFind(ch_name);
|
||||||
|
|
||||||
|
if(NONE == ch)
|
||||||
|
{
|
||||||
|
KPrintf("PlcDriverAttachToChannel find plc channel error!name %s\n", ch_name);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CH_PLC_TYPE == ch->ch_type)
|
||||||
|
{
|
||||||
|
driver = PlcDriverFind(drv_name, CHDRV_PLC_TYPE);
|
||||||
|
|
||||||
|
if(NONE == driver)
|
||||||
|
{
|
||||||
|
KPrintf("PlcDriverAttachToChannel find plc driver error!name %s\n", drv_name);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(CHDRV_PLC_TYPE == driver->driver_type)
|
||||||
|
{
|
||||||
|
ret = DriverRegisterToChannel(ch, driver);
|
||||||
|
|
||||||
|
if(EOK != ret)
|
||||||
|
{
|
||||||
|
KPrintf("PlcDriverAttachToChannel DriverRegisterToBus error %u\n", ret);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,278 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2022 AIIT XUOS Lab
|
||||||
|
* XiUOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file plc_channel.h
|
||||||
|
* @brief define ch driver framework function and common API
|
||||||
|
* @version 1.0
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2022-03-01
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef __PLC_CHANNEL_H_
|
||||||
|
#define __PLC_CHANNEL_H_
|
||||||
|
|
||||||
|
#include "list.h"
|
||||||
|
|
||||||
|
#define x_OffPos uint32
|
||||||
|
#define x_size_t size_t
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define OPE_INT 0x0000
|
||||||
|
#define OPE_CFG 0x0001
|
||||||
|
|
||||||
|
#define OPER_WDT_SET_TIMEOUT 0x0002
|
||||||
|
#define OPER_WDT_KEEPALIVE 0x0003
|
||||||
|
|
||||||
|
#define CHECK_CH_PARAM(param) \
|
||||||
|
do \
|
||||||
|
{ \
|
||||||
|
if(param == NONE) { \
|
||||||
|
KPrintf("PARAM CHECK FAILED ...%s %d %s is NULL.\n",__FUNCTION__,__LINE__,#param); \
|
||||||
|
while(RET_TRUE); \
|
||||||
|
} \
|
||||||
|
}while (0)
|
||||||
|
|
||||||
|
typedef struct Channel *ChannelType;
|
||||||
|
typedef struct ChDev *ChDevType;
|
||||||
|
typedef struct ChDrv *ChDrvType;
|
||||||
|
|
||||||
|
/* need to add new ch type in ../tool/shell/letter-shell/cmd.c, ensure ShowBus cmd supported*/
|
||||||
|
enum ChType_e
|
||||||
|
{
|
||||||
|
CH_PLC_TYPE,
|
||||||
|
CH_END_TYPE,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ChState_e
|
||||||
|
{
|
||||||
|
CHANNEL_INIT = 0,
|
||||||
|
CHANNEL_INSTALL,
|
||||||
|
CHANNEL_UNINSTALL,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ChDevType_e
|
||||||
|
{
|
||||||
|
CHDEV_PLC_TYPE,
|
||||||
|
CHDEV_END_TYPE,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ChDevState_e
|
||||||
|
{
|
||||||
|
CHDEV_INIT = 0,
|
||||||
|
CHDEV_INSTALL,
|
||||||
|
CHDEV_UNINSTALL,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ChDrvType_e
|
||||||
|
{
|
||||||
|
CHDRV_PLC_TYPE,
|
||||||
|
CHDRV_END_TYPE,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum ChDrvState_e
|
||||||
|
{
|
||||||
|
CHDRV_INIT = 0,
|
||||||
|
CHDRV_INSTALL,
|
||||||
|
CHDRV_UNINSTALL,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChConfigInfo
|
||||||
|
{
|
||||||
|
int configure_cmd;
|
||||||
|
void *private_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChReadParam
|
||||||
|
{
|
||||||
|
x_OffPos pos;
|
||||||
|
void* buffer;
|
||||||
|
x_size_t size;
|
||||||
|
x_size_t read_length;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChWriteParam
|
||||||
|
{
|
||||||
|
x_OffPos pos;
|
||||||
|
const void* buffer;
|
||||||
|
x_size_t size;
|
||||||
|
};
|
||||||
|
|
||||||
|
//struct ChHalDevBlockParam
|
||||||
|
//{
|
||||||
|
// uint32 cmd;
|
||||||
|
////tst by wly
|
||||||
|
//// struct DeviceBlockArrange dev_block;
|
||||||
|
//// struct DeviceBlockAddr *dev_addr;
|
||||||
|
//};
|
||||||
|
|
||||||
|
struct ChHalDevDone
|
||||||
|
{
|
||||||
|
uint32 (*open) (void *dev);
|
||||||
|
uint32 (*close) (void *dev);
|
||||||
|
uint32 (*write) (void *dev, struct ChWriteParam *write_param);
|
||||||
|
uint32 (*read) (void *dev, struct ChReadParam *read_param);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChDev
|
||||||
|
{
|
||||||
|
int8 dev_name[NAME_NUM_MAX];
|
||||||
|
enum ChDevType_e dev_type;
|
||||||
|
enum ChDevState_e dev_state;
|
||||||
|
|
||||||
|
const struct ChHalDevDone *dev_done;
|
||||||
|
|
||||||
|
int (*dev_recv_callback) (void *dev, x_size_t length);
|
||||||
|
// int (*dev_block_control) (struct ChDev *dev, struct ChHalDevBlockParam *block_param);
|
||||||
|
|
||||||
|
struct Channel *owner_ch;
|
||||||
|
void *private_data;
|
||||||
|
|
||||||
|
int32 dev_sem;
|
||||||
|
|
||||||
|
DoublelistType dev_link;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ChDrv
|
||||||
|
{
|
||||||
|
int8 drv_name[NAME_NUM_MAX];
|
||||||
|
enum ChDrvType_e driver_type;
|
||||||
|
enum ChDrvState_e driver_state;
|
||||||
|
|
||||||
|
uint32 (*configure)(void *drv, struct ChConfigInfo *config);
|
||||||
|
|
||||||
|
struct Channel *owner_ch;
|
||||||
|
void *private_data;
|
||||||
|
|
||||||
|
DoublelistType driver_link;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Channel
|
||||||
|
{
|
||||||
|
int8 ch_name[NAME_NUM_MAX];
|
||||||
|
enum ChType_e ch_type;
|
||||||
|
enum ChState_e ch_state;
|
||||||
|
|
||||||
|
int32 (*match)(struct ChDrv *driver, struct ChDev *device);
|
||||||
|
|
||||||
|
int ch_lock;
|
||||||
|
|
||||||
|
struct ChDev *owner_haldev;
|
||||||
|
struct ChDrv *owner_driver;
|
||||||
|
|
||||||
|
void *private_data;
|
||||||
|
|
||||||
|
/*manage the drv of the channel*/
|
||||||
|
uint8 driver_cnt;
|
||||||
|
uint8 ch_drvlink_flag;
|
||||||
|
DoublelistType ch_drvlink;
|
||||||
|
|
||||||
|
/*manage the dev of the channel*/
|
||||||
|
uint8 haldev_cnt;
|
||||||
|
uint8 ch_devlink_flag;
|
||||||
|
DoublelistType ch_devlink;
|
||||||
|
|
||||||
|
uint8 ch_cnt;
|
||||||
|
uint8 ch_link_flag;
|
||||||
|
DoublelistType ch_link;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*Register the BUS,manage with the double linklist*/
|
||||||
|
int ChannelRegister(struct Channel *ch);
|
||||||
|
|
||||||
|
/*Release the BUS framework*/
|
||||||
|
int ChannelRelease(struct Channel *ch);
|
||||||
|
|
||||||
|
/*Unregister a certain kind of BUS*/
|
||||||
|
int ChannelUnregister(struct Channel *ch);
|
||||||
|
|
||||||
|
/*Register the driver to the channel*/
|
||||||
|
int DriverRegisterToChannel(struct Channel *ch, struct ChDrv *driver);
|
||||||
|
|
||||||
|
/*Register the device to the channel*/
|
||||||
|
int DeviceRegisterToChannel(struct Channel *ch, struct ChDev *device);
|
||||||
|
|
||||||
|
/*Delete the driver from the channel*/
|
||||||
|
int DriverDeleteFromChannel(struct Channel *ch, struct ChDrv *driver);
|
||||||
|
|
||||||
|
/*Delete the device from the channel*/
|
||||||
|
int DeviceDeleteFromChannel(struct Channel *ch, struct ChDev *device);
|
||||||
|
|
||||||
|
/*Find the ch with ch name*/
|
||||||
|
ChannelType ChannelFind(const char *ch_name);
|
||||||
|
|
||||||
|
/*Find the driver of cetain channel*/
|
||||||
|
ChDrvType ChannelFindDriver(struct Channel *ch, const char *driver_name);
|
||||||
|
|
||||||
|
/*Find the device of certain channel*/
|
||||||
|
ChDevType ChannelFindDevice(struct Channel *ch, const char *device_name);
|
||||||
|
|
||||||
|
/*Dev receive data callback function*/
|
||||||
|
uint32 ChannelDevRecvCallback(struct ChDev *dev, int (*dev_recv_callback) (void *dev, x_size_t length));
|
||||||
|
|
||||||
|
/*Open the device of the channel*/
|
||||||
|
uint32 ChannelDevOpen(struct ChDev *dev);
|
||||||
|
|
||||||
|
/*Close the device of the channel*/
|
||||||
|
uint32 ChannelDevClose(struct ChDev *dev);
|
||||||
|
|
||||||
|
/*Write data to the device*/
|
||||||
|
uint32 ChannelDevWriteData(struct ChDev *dev, struct ChWriteParam *write_param);
|
||||||
|
|
||||||
|
/*Read data from the device*/
|
||||||
|
uint32 ChannelDevReadData(struct ChDev *dev, struct ChReadParam *read_param);
|
||||||
|
|
||||||
|
/*Configure the driver of the channel*/
|
||||||
|
uint32 ChannelDrvConfigure(struct ChDrv *drv, struct ChConfigInfo *config);
|
||||||
|
|
||||||
|
/*Obtain the ch using a certain dev*/
|
||||||
|
int DeviceObtainChannel(struct Channel *ch, struct ChDev *dev, const char *drv_name, struct ChConfigInfo *config);
|
||||||
|
|
||||||
|
|
||||||
|
struct PlcDriver
|
||||||
|
{
|
||||||
|
struct ChDrv driver;
|
||||||
|
uint32 (*configure) (void *drv, struct ChConfigInfo *cfg);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct PlcChannel
|
||||||
|
{
|
||||||
|
struct Channel ch;
|
||||||
|
void *private_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/*Register the plc bus*/
|
||||||
|
int PlcChannelInit(struct PlcChannel *plc_ch, const char *ch_name);
|
||||||
|
|
||||||
|
/*Register the plc driver*/
|
||||||
|
int PlcDriverInit(struct PlcDriver *plc_driver, const char *driver_name);
|
||||||
|
|
||||||
|
/*Release the plc device*/
|
||||||
|
int PlcReleaseChannel(struct PlcChannel *plc_ch);
|
||||||
|
|
||||||
|
/*Register the plc driver to the plc bus*/
|
||||||
|
int PlcDriverAttachToChannel(const char *drv_name, const char *ch_name);
|
||||||
|
|
||||||
|
/*Register the driver, manage with the double linklist*/
|
||||||
|
int PlcDriverRegister(struct ChDrv *driver);
|
||||||
|
|
||||||
|
/*Find the register driver*/
|
||||||
|
ChDrvType PlcDriverFind(const char *drv_name, enum ChDrvType_e drv_type);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,189 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2021 AIIT XUOS Lab
|
||||||
|
* XiUOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file plc.c
|
||||||
|
* @brief plc relative activities
|
||||||
|
* @version 1.0
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2021.12.15
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "ua_api.h"
|
||||||
|
#include "plc_channel.h"
|
||||||
|
#include "plc_device.h"
|
||||||
|
|
||||||
|
DoublelistType plcdev_list;
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/*Create the plc device linklist*/
|
||||||
|
static void PlcDeviceLinkInit()
|
||||||
|
{
|
||||||
|
AppInitDoubleList(&plcdev_list);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int PlcDeviceOpen(void *dev)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(dev);
|
||||||
|
|
||||||
|
struct PlcDevice *plc_dev = (struct PlcDevice *)dev;
|
||||||
|
|
||||||
|
if(plc_dev->net == PLC_IND_ENET_OPCUA)
|
||||||
|
{
|
||||||
|
return ua_open(plc_dev->priv_data);
|
||||||
|
}
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void PlcDeviceClose(void *dev)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(dev);
|
||||||
|
|
||||||
|
struct PlcDevice *plc_dev = (struct PlcDevice *)dev;
|
||||||
|
|
||||||
|
if(plc_dev->net == PLC_IND_ENET_OPCUA)
|
||||||
|
{
|
||||||
|
ua_close(plc_dev->priv_data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int PlcDeviceWrite(void *dev, const void *buf, size_t len)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(dev);
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
struct PlcDevice *plc_dev = (struct PlcDevice *)dev;
|
||||||
|
|
||||||
|
if(plc_dev->net == PLC_IND_ENET_OPCUA)
|
||||||
|
{
|
||||||
|
ret = ua_write(plc_dev->priv_data, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int PlcDeviceRead(void *dev, void *buf, size_t len)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(dev);
|
||||||
|
CHECK_CH_PARAM(buf);
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
struct PlcDevice *plc_dev = (struct PlcDevice *)dev;
|
||||||
|
|
||||||
|
if(plc_dev->net == PLC_IND_ENET_OPCUA)
|
||||||
|
{
|
||||||
|
ret = ua_read(plc_dev->priv_data, buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct PlcOps plc_done =
|
||||||
|
{
|
||||||
|
.open = PlcDeviceOpen,
|
||||||
|
.close = PlcDeviceClose,
|
||||||
|
.write = PlcDeviceWrite,
|
||||||
|
.read = PlcDeviceRead,
|
||||||
|
};
|
||||||
|
|
||||||
|
/* find PLC device with device name */
|
||||||
|
struct ChDev *PlcDevFind(const char *dev_name)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(dev_name);
|
||||||
|
|
||||||
|
struct PlcDevice *device = NONE;
|
||||||
|
struct ChDev *haldev = NONE;
|
||||||
|
|
||||||
|
DoublelistType *node = NONE;
|
||||||
|
DoublelistType *head = &plcdev_list;
|
||||||
|
|
||||||
|
for (node = head->node_next; node != head; node = node->node_next) {
|
||||||
|
device = DOUBLE_LIST_ENTRY(node, struct PlcDevice, link);
|
||||||
|
if (!strcmp(device->name, dev_name)) {
|
||||||
|
haldev = &device->haldev;
|
||||||
|
return haldev;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
plc_print("plc: [%s] cannot find the %s device\n", __func__, dev_name);
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PlcDevRegister(struct PlcDevice *plc_device, void *plc_param, const char *device_name)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(plc_device);
|
||||||
|
CHECK_CH_PARAM(device_name);
|
||||||
|
|
||||||
|
int ret = EOK;
|
||||||
|
static uint8_t dev_link_flag = 0;
|
||||||
|
|
||||||
|
if (!dev_link_flag) {
|
||||||
|
PlcDeviceLinkInit();
|
||||||
|
dev_link_flag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CHDEV_INSTALL != plc_device->state) {
|
||||||
|
strncpy(plc_device->haldev.dev_name, device_name, NAME_NUM_MAX);
|
||||||
|
plc_device->haldev.dev_type = CHDEV_PLC_TYPE;
|
||||||
|
plc_device->haldev.dev_state = CHDEV_INSTALL;
|
||||||
|
|
||||||
|
strncpy(plc_device->name, device_name, strlen(device_name));
|
||||||
|
plc_device->ops = &plc_done;
|
||||||
|
|
||||||
|
AppDoubleListInsertNodeAfter(&plcdev_list, &(plc_device->link));
|
||||||
|
plc_device->state = CHDEV_INSTALL;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
KPrintf("PlcDevRegister device %s has been register state%u\n", device_name, plc_device->state);
|
||||||
|
ret = ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PlcDeviceAttachToChannel(const char *dev_name, const char *ch_name)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(dev_name);
|
||||||
|
CHECK_CH_PARAM(ch_name);
|
||||||
|
|
||||||
|
int ret = EOK;
|
||||||
|
|
||||||
|
struct Channel *ch;
|
||||||
|
struct ChDev *device;
|
||||||
|
|
||||||
|
ch = ChannelFind(ch_name);
|
||||||
|
if (NONE == ch) {
|
||||||
|
KPrintf("PlcDeviceAttachToChannel find plc ch error!name %s\n", ch_name);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CH_PLC_TYPE == ch->ch_type) {
|
||||||
|
device = PlcDevFind(dev_name);
|
||||||
|
if (NONE == device) {
|
||||||
|
KPrintf("PlcDeviceAttachToChannel find plc device %s error!\n", dev_name);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (CHDEV_PLC_TYPE == device->dev_type) {
|
||||||
|
ret = DeviceRegisterToChannel(ch, device);
|
||||||
|
if (EOK != ret) {
|
||||||
|
KPrintf("PlcDeviceAttachToChannel DeviceRegisterToChannel error %u\n", ret);
|
||||||
|
return ERROR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return EOK;
|
||||||
|
}
|
||||||
|
|
|
@ -11,28 +11,38 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @file plc.h
|
* @file plc_dev.h
|
||||||
* @brief plc relative definition and structure
|
* @brief plc relative definition and structure
|
||||||
* @version 1.0
|
* @version 1.0
|
||||||
* @author AIIT XUOS Lab
|
* @author AIIT XUOS Lab
|
||||||
* @date 2021.12.15
|
* @date 2022-01-24
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "xs_klist.h"
|
#ifndef __PLC_DEV_H_
|
||||||
|
#define __PLC_DEV_H_
|
||||||
|
|
||||||
|
#include "list.h"
|
||||||
|
#include "plc_channel.h"
|
||||||
|
|
||||||
|
#undef open
|
||||||
|
#undef close
|
||||||
|
#undef read
|
||||||
|
#undef write
|
||||||
|
|
||||||
#define IP_ADDR_SIZE 32
|
#define IP_ADDR_SIZE 32
|
||||||
#define PLC_NAME_SIZE 32
|
#define PLC_NAME_SIZE 32
|
||||||
|
|
||||||
// PLC device information
|
// PLC device information
|
||||||
struct PlcInfo {
|
typedef struct PlcInfo {
|
||||||
uint32_t ability; // PLC ability
|
uint32_t ability; // PLC ability
|
||||||
uint32_t id; // PLC Device ID
|
uint32_t id; // PLC Device ID
|
||||||
uint32_t soft_version; // software version
|
uint32_t soft_version; // software version
|
||||||
uint32_t hard_version; // hardware version
|
uint32_t hard_version; // hardware version
|
||||||
uint32_t date; // manufact date
|
uint32_t date; // manufact date
|
||||||
const char *vendor; // vendor
|
const char *vendor; // vendor
|
||||||
const char *model; // product model
|
const char *model; // model
|
||||||
};
|
const char *product; // product
|
||||||
|
}PlcInfoType;
|
||||||
|
|
||||||
enum PlcSerialType {
|
enum PlcSerialType {
|
||||||
PLC_SERIAL_232,
|
PLC_SERIAL_232,
|
||||||
|
@ -55,13 +65,13 @@ union PlcCfg {
|
||||||
struct PlcDevice;
|
struct PlcDevice;
|
||||||
|
|
||||||
// operation API
|
// operation API
|
||||||
struct PlcOps {
|
typedef struct PlcOps {
|
||||||
int (*open)(struct PlcDevice *pdev); // open and connect PLC device
|
int (*open)(void *dev); // open and connect PLC device
|
||||||
void (*close)(struct PlcDevice*pdev); // close and disconnect PLC device
|
void (*close)(void* dev); // close and disconnect PLC device
|
||||||
int (*read)(struct PlcDevice* pdev, void *buf, size_t len); // read data from PLC
|
int (*read)(void* dev, void *buf, size_t len); // read data from PLC
|
||||||
int (*write)(struct PlcDevice* pdev, const void *buf, size_t len); // write data from PLC
|
int (*write)(void* dev, const void *buf, size_t len); // write data from PLC
|
||||||
int (*ioctl)(struct PlcDevice* pdev, int cmd, void *arg); // send control command to PLC
|
int (*ioctl)(void* dev, int cmd, void *arg); // send control command to PLC
|
||||||
};
|
}PlcOpsType;
|
||||||
|
|
||||||
enum PlcCtlType {
|
enum PlcCtlType {
|
||||||
PLC_CTRL_TYPE_HSC,
|
PLC_CTRL_TYPE_HSC,
|
||||||
|
@ -69,12 +79,10 @@ enum PlcCtlType {
|
||||||
PLC_CTRL_TYPE_PHASING
|
PLC_CTRL_TYPE_PHASING
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
#define PLC_ABILITY_HSC ((uint32_t)(1 << PLC_CTRL_TYPE_HSC))
|
#define PLC_ABILITY_HSC ((uint32_t)(1 << PLC_CTRL_TYPE_HSC))
|
||||||
#define PLC_ABILITY_PID ((uint32_t)(1 << PLC_CTRL_TYPE_PID))
|
#define PLC_ABILITY_PID ((uint32_t)(1 << PLC_CTRL_TYPE_PID))
|
||||||
#define PLC_ABILITY_PHASING ((uint32_t)(1 << PLC_CTRL_TYPE_PHASING))
|
#define PLC_ABILITY_PHASING ((uint32_t)(1 << PLC_CTRL_TYPE_PHASING))
|
||||||
|
|
||||||
|
|
||||||
enum PlcIndHybridNet
|
enum PlcIndHybridNet
|
||||||
{
|
{
|
||||||
// PLC Field Bus
|
// PLC Field Bus
|
||||||
|
@ -103,22 +111,43 @@ enum PlcTransType
|
||||||
};
|
};
|
||||||
|
|
||||||
//communication interface
|
//communication interface
|
||||||
struct PlcInterface
|
typedef struct PlcInterface
|
||||||
{
|
{
|
||||||
enum PlcIndHybridNet net;
|
|
||||||
enum PlcTransType trans;
|
|
||||||
char ip_addr[IP_ADDR_SIZE];
|
char ip_addr[IP_ADDR_SIZE];
|
||||||
char attrib;
|
char attrib;
|
||||||
};
|
}PlcInterfaceType;
|
||||||
|
|
||||||
// identify PLC device
|
// identify PLC device
|
||||||
struct PlcDevice {
|
typedef struct PlcDevice {
|
||||||
const char name[PLC_NAME_SIZE]; /* name of the device */
|
struct ChDev haldev; /* hardware device driver for channel */
|
||||||
|
enum ChDevState_e state;
|
||||||
|
|
||||||
|
char name[PLC_NAME_SIZE]; /* name of the device */
|
||||||
enum PlcCtlType type; /* PLC Control Type */
|
enum PlcCtlType type; /* PLC Control Type */
|
||||||
|
enum PlcIndHybridNet net;
|
||||||
|
enum PlcTransType trans;
|
||||||
|
|
||||||
struct PlcInfo info;/* Plc info, such as vendor name and model name */
|
struct PlcInfo info;/* Plc info, such as vendor name and model name */
|
||||||
union PlcCfg cfg;
|
union PlcCfg cfg;
|
||||||
struct PlcOps ops; /* filesystem-like APIs for data transferring */
|
struct PlcOps *ops; /* filesystem-like APIs for data transferring */
|
||||||
struct PlcInterface interface; /* protocols used for transferring data from program to plc */
|
struct PlcInterface interface; /* protocols used for transferring data from program to plc */
|
||||||
DoubleLinklistType link;/* link list node */
|
|
||||||
};
|
|
||||||
|
|
||||||
|
void *priv_data; /* private data for different PLC*/
|
||||||
|
DoublelistType link;/* link list node */
|
||||||
|
}PlcDeviceType;
|
||||||
|
|
||||||
|
typedef struct PlcCtrlParam {
|
||||||
|
void *node_id; // for node ID
|
||||||
|
int value;
|
||||||
|
}PlcCtrlParamType;
|
||||||
|
|
||||||
|
#define plc_print KPrintf
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
int PlcDevRegister(struct PlcDevice *plc_device, void *plc_param, const char *device_name);
|
||||||
|
int PlcDeviceAttachToChannel(const char *dev_name, const char *ch_name);
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,71 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 AIIT XUOS Lab
|
||||||
|
* XiUOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file drv_plc.c
|
||||||
|
* @brief register plc drv function using bus driver framework
|
||||||
|
* @version 1.0
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2022-01-24
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "transform.h"
|
||||||
|
#include "plc_channel.h"
|
||||||
|
#include "plc_device.h"
|
||||||
|
|
||||||
|
static DoublelistType plcdrv_linklist;
|
||||||
|
|
||||||
|
/******************************************************************************/
|
||||||
|
|
||||||
|
/*Create the driver linklist*/
|
||||||
|
static void PlcDrvLinkInit()
|
||||||
|
{
|
||||||
|
AppInitDoubleList(&plcdrv_linklist);
|
||||||
|
}
|
||||||
|
|
||||||
|
ChDrvType PlcDriverFind(const char *drv_name, enum ChDrvType_e drv_type)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(drv_name);
|
||||||
|
|
||||||
|
struct ChDrv *driver = NONE;
|
||||||
|
|
||||||
|
DoublelistType *node = NONE;
|
||||||
|
DoublelistType *head = &plcdrv_linklist;
|
||||||
|
|
||||||
|
for (node = head->node_next; node != head; node = node->node_next) {
|
||||||
|
driver = DOUBLE_LIST_ENTRY(node, struct ChDrv, driver_link);
|
||||||
|
if ((!strcmp(driver->drv_name, drv_name)) && (drv_type == driver->driver_type)) {
|
||||||
|
return driver;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
KPrintf("PlcDriverFind cannot find the %s driver.return NULL\n", drv_name);
|
||||||
|
return NONE;
|
||||||
|
}
|
||||||
|
|
||||||
|
int PlcDriverRegister(struct ChDrv *driver)
|
||||||
|
{
|
||||||
|
CHECK_CH_PARAM(driver);
|
||||||
|
|
||||||
|
int ret = EOK;
|
||||||
|
static uint8_t driver_link_flag = 0;
|
||||||
|
|
||||||
|
if (!driver_link_flag) {
|
||||||
|
PlcDrvLinkInit();
|
||||||
|
driver_link_flag = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
AppDoubleListInsertNodeAfter(&plcdrv_linklist, &(driver->driver_link));
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
SRC_DIR :=
|
SRC_FILES := control.c
|
||||||
|
|
||||||
include $(KERNEL_ROOT)/compiler.mk
|
include $(KERNEL_ROOT)/compiler.mk
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
{
|
||||||
|
"siemens plc":
|
||||||
|
{
|
||||||
|
"device type": "PLC",
|
||||||
|
"control type": "HSC",
|
||||||
|
"info":
|
||||||
|
{
|
||||||
|
"plc ability" : 1,
|
||||||
|
"plc device id": 1,
|
||||||
|
"soft version" : 1,
|
||||||
|
"hardware version": 1,
|
||||||
|
"date": "2022-1-28",
|
||||||
|
"vendor": "siemens",
|
||||||
|
"model":"S300"
|
||||||
|
},
|
||||||
|
|
||||||
|
"serial config":
|
||||||
|
{
|
||||||
|
"serial type":"485",
|
||||||
|
"station id" : "station1",
|
||||||
|
"serial port" : 1
|
||||||
|
},
|
||||||
|
|
||||||
|
"network config":
|
||||||
|
{
|
||||||
|
"ip addr" : "192.168.250.5",
|
||||||
|
"ip port" : 4840
|
||||||
|
},
|
||||||
|
|
||||||
|
"interface":
|
||||||
|
{
|
||||||
|
"inhybridnet":"OPCUA",
|
||||||
|
"transport":"TCP",
|
||||||
|
"ip address": "192.168.250.5",
|
||||||
|
"attribute" : "1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,4 +1,8 @@
|
||||||
|
|
||||||
|
#include "cJSON.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void control_init(void)
|
void control_init(void)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
@ -6,6 +10,12 @@ void control_init(void)
|
||||||
|
|
||||||
void control_read_file()
|
void control_read_file()
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -83,8 +83,7 @@ ifeq ($(CONFIG_USING_TENSORFLOWLITEMICRO),y)
|
||||||
-Isource/third_party/ruy
|
-Isource/third_party/ruy
|
||||||
DEFINES += -DTF_LITE_USE_GLOBAL_CMATH_FUNCTIONS \
|
DEFINES += -DTF_LITE_USE_GLOBAL_CMATH_FUNCTIONS \
|
||||||
-DTF_LITE_USE_GLOBAL_MAX \
|
-DTF_LITE_USE_GLOBAL_MAX \
|
||||||
-DTF_LITE_USE_GLOBAL_MIN \
|
-DTF_LITE_USE_GLOBAL_MIN
|
||||||
-DTF_LITE_STATIC_MEMORY
|
|
||||||
endif
|
endif
|
||||||
|
|
||||||
include $(KERNEL_ROOT)/compiler.mk
|
include $(KERNEL_ROOT)/compiler.mk
|
||||||
|
|
|
@ -23,8 +23,8 @@ $(patsubst %.cc,%.o,$(patsubst %.c,%.o,$(SRCS)))
|
||||||
|
|
||||||
LIBRARY_OBJS := $(filter-out tensorflow/lite/micro/examples/%, $(OBJS))
|
LIBRARY_OBJS := $(filter-out tensorflow/lite/micro/examples/%, $(OBJS))
|
||||||
|
|
||||||
CXXFLAGS += -std=c++11 -fno-rtti -fno-exceptions -fno-threadsafe-statics -fno-unwind-tables -ffunction-sections -fdata-sections -fmessage-length=0 -DTF_LITE_STATIC_MEMORY -DTF_LITE_DISABLE_X86_NEON -O3 -Werror -Wsign-compare -Wdouble-promotion -Wshadow -Wunused-variable -Wmissing-field-initializers -Wunused-function -Wswitch -Wvla -Wall -Wextra -Wstrict-aliasing -Wno-unused-parameter -DCMSIS_NN -DTF_LITE_USE_CTIME -I. -I./third_party/gemmlowp -I./third_party/flatbuffers/include -I./third_party/ruy
|
CXXFLAGS += -std=c++11 -fno-rtti -fno-exceptions -fno-threadsafe-statics -fno-unwind-tables -ffunction-sections -fdata-sections -fmessage-length=0 -DTF_LITE_DISABLE_X86_NEON -O3 -Werror -Wsign-compare -Wdouble-promotion -Wshadow -Wunused-variable -Wmissing-field-initializers -Wunused-function -Wswitch -Wvla -Wall -Wextra -Wstrict-aliasing -Wno-unused-parameter -DCMSIS_NN -DTF_LITE_USE_CTIME -I. -I./third_party/gemmlowp -I./third_party/flatbuffers/include -I./third_party/ruy
|
||||||
CCFLAGS += -std=c11 -fno-unwind-tables -ffunction-sections -fdata-sections -fmessage-length=0 -DTF_LITE_STATIC_MEMORY -DTF_LITE_DISABLE_X86_NEON -O3 -Werror -Wsign-compare -Wdouble-promotion -Wshadow -Wunused-variable -Wmissing-field-initializers -Wunused-function -Wswitch -Wvla -Wall -Wextra -Wstrict-aliasing -Wno-unused-parameter -DCMSIS_NN -DTF_LITE_USE_CTIME -I. -I./third_party/gemmlowp -I./third_party/flatbuffers/include -I./third_party/ruy
|
CCFLAGS += -std=c11 -fno-unwind-tables -ffunction-sections -fdata-sections -fmessage-length=0 -DTF_LITE_DISABLE_X86_NEON -O3 -Werror -Wsign-compare -Wdouble-promotion -Wshadow -Wunused-variable -Wmissing-field-initializers -Wunused-function -Wswitch -Wvla -Wall -Wextra -Wstrict-aliasing -Wno-unused-parameter -DCMSIS_NN -DTF_LITE_USE_CTIME -I. -I./third_party/gemmlowp -I./third_party/flatbuffers/include -I./third_party/ruy
|
||||||
|
|
||||||
LDFLAGS += -lm
|
LDFLAGS += -lm
|
||||||
|
|
||||||
|
|
|
@ -66,4 +66,25 @@ if SUPPORT_SENSOR_FRAMEWORK
|
||||||
if SENSOR_HUMIDITY
|
if SENSOR_HUMIDITY
|
||||||
source "$APP_DIR/Framework/sensor/humidity/Kconfig"
|
source "$APP_DIR/Framework/sensor/humidity/Kconfig"
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
menuconfig SENSOR_WINDSPEED
|
||||||
|
bool "Using wind speed sensor device"
|
||||||
|
default n
|
||||||
|
if SENSOR_WINDSPEED
|
||||||
|
source "$APP_DIR/Framework/sensor/windspeed/Kconfig"
|
||||||
|
endif
|
||||||
|
|
||||||
|
menuconfig SENSOR_WINDDIRECTION
|
||||||
|
bool "Using wind direction sensor device"
|
||||||
|
default n
|
||||||
|
if SENSOR_WINDDIRECTION
|
||||||
|
source "$APP_DIR/Framework/sensor/winddirection/Kconfig"
|
||||||
|
endif
|
||||||
|
|
||||||
|
menuconfig SENSOR_ALTITUDE
|
||||||
|
bool "Using altitude sensor device"
|
||||||
|
default n
|
||||||
|
if SENSOR_ALTITUDE
|
||||||
|
source "$APP_DIR/Framework/sensor/altitude/Kconfig"
|
||||||
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -45,5 +45,17 @@ ifeq ($(CONFIG_ADD_XIZI_FETURES),y)
|
||||||
SRC_DIR += humidity
|
SRC_DIR += humidity
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_SENSOR_WINDSPEED),y)
|
||||||
|
SRC_DIR += windspeed
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_SENSOR_WINDDIRECTION),y)
|
||||||
|
SRC_DIR += winddirection
|
||||||
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_SENSOR_ALTITUDE),y)
|
||||||
|
SRC_DIR += altitude
|
||||||
|
endif
|
||||||
|
|
||||||
include $(KERNEL_ROOT)/compiler.mk
|
include $(KERNEL_ROOT)/compiler.mk
|
||||||
endif
|
endif
|
||||||
|
|
|
@ -0,0 +1,32 @@
|
||||||
|
|
||||||
|
config SENSOR_BMP180
|
||||||
|
bool "Using BMP180"
|
||||||
|
default n
|
||||||
|
|
||||||
|
if SENSOR_BMP180
|
||||||
|
config SENSOR_DEVICE_BMP180
|
||||||
|
string "BMP180 sensor name"
|
||||||
|
default "bmp180"
|
||||||
|
|
||||||
|
config SENSOR_QUANTITY_BMP180_ALTITUDE
|
||||||
|
string "BMP180 quantity name"
|
||||||
|
default "altitude_1"
|
||||||
|
|
||||||
|
if ADD_XIZI_FETURES
|
||||||
|
config SENSOR_DEVICE_BMP180_DEV
|
||||||
|
string "BMP180 device name"
|
||||||
|
default "/dev/i2c1_dev0"
|
||||||
|
|
||||||
|
config SENSOR_DEVICE_BMP180_I2C_ADDR
|
||||||
|
hex "BMP180 device i2c address"
|
||||||
|
default 0x77
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ADD_NUTTX_FETURES
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ADD_RTTHREAD_FETURES
|
||||||
|
|
||||||
|
endif
|
||||||
|
endif
|
|
@ -0,0 +1,5 @@
|
||||||
|
ifeq ($(CONFIG_SENSOR_BMP180),y)
|
||||||
|
SRC_DIR += bmp180
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -0,0 +1,14 @@
|
||||||
|
import os
|
||||||
|
Import('RTT_ROOT')
|
||||||
|
from building import *
|
||||||
|
|
||||||
|
cwd = GetCurrentDir()
|
||||||
|
objs = []
|
||||||
|
list = os.listdir(cwd)
|
||||||
|
|
||||||
|
for d in list:
|
||||||
|
path = os.path.join(cwd, d)
|
||||||
|
if os.path.isfile(os.path.join(path, 'SConscript')):
|
||||||
|
objs = objs + SConscript(os.path.join(path, 'SConscript'))
|
||||||
|
|
||||||
|
Return('objs')
|
|
@ -0,0 +1,3 @@
|
||||||
|
SRC_FILES := bmp180.c
|
||||||
|
|
||||||
|
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -0,0 +1,10 @@
|
||||||
|
from building import *
|
||||||
|
import os
|
||||||
|
|
||||||
|
cwd = GetCurrentDir()
|
||||||
|
src = []
|
||||||
|
if GetDepend(['SENSOR_BMP180']):
|
||||||
|
src += ['bmp180.c']
|
||||||
|
group = DefineGroup('sensor altitude bmp180', src, depend = [], CPPPATH = [cwd])
|
||||||
|
|
||||||
|
Return('group')
|
|
@ -0,0 +1,322 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 AIIT XUOS Lab
|
||||||
|
* XiUOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file bmp180.c
|
||||||
|
* @brief BMP180 altitude driver base sensor
|
||||||
|
* @version 1.1
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2021.12.20
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sensor.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
static struct SensorDevice bmp180;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
int8_t ac_data[3];
|
||||||
|
uint8_t unsigned_ac_data[3];
|
||||||
|
int8_t b_data[2];
|
||||||
|
int8_t m_data[3];
|
||||||
|
}Bmp180RegData;
|
||||||
|
|
||||||
|
static Bmp180RegData bmp180_reg_data;
|
||||||
|
|
||||||
|
const static unsigned char OSS = 0; // Oversampling Setting
|
||||||
|
static long CalTemp_data = 0;
|
||||||
|
|
||||||
|
static struct SensorProductInfo info =
|
||||||
|
{
|
||||||
|
(SENSOR_ABILITY_ALTITUDE),
|
||||||
|
"BOSCH",
|
||||||
|
"BMP180",
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Open BMP180 sensor device
|
||||||
|
* @param sdev - sensor device pointer
|
||||||
|
* @return success : 0 error : -1
|
||||||
|
*/
|
||||||
|
static int SensorDeviceOpen(struct SensorDevice *sdev)
|
||||||
|
{
|
||||||
|
int result;
|
||||||
|
uint16_t i2c_dev_addr = SENSOR_DEVICE_BMP180_I2C_ADDR;
|
||||||
|
|
||||||
|
sdev->fd = PrivOpen(SENSOR_DEVICE_BMP180_DEV, O_RDWR);
|
||||||
|
if (sdev->fd < 0) {
|
||||||
|
printf("open %s error\n", SENSOR_DEVICE_BMP180_DEV);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct PrivIoctlCfg ioctl_cfg;
|
||||||
|
ioctl_cfg.ioctl_driver_type = I2C_TYPE;
|
||||||
|
ioctl_cfg.args = &i2c_dev_addr;
|
||||||
|
result = PrivIoctl(sdev->fd, OPE_INT, &ioctl_cfg);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Write sensor device
|
||||||
|
* @param sdev - sensor device pointer
|
||||||
|
* @param len - the length of the read data
|
||||||
|
* @return success: 0 , failure: -1
|
||||||
|
*/
|
||||||
|
static int SensorDeviceWrite(struct SensorDevice *sdev, const void *buf, size_t len)
|
||||||
|
{
|
||||||
|
if (PrivWrite(sdev->fd, buf, len) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Read sensor device
|
||||||
|
* @param sdev - sensor device pointer
|
||||||
|
* @param len - the length of the read data
|
||||||
|
* @return success: 0 , failure: -1
|
||||||
|
*/
|
||||||
|
static int SensorDeviceRead(struct SensorDevice *sdev, size_t len)
|
||||||
|
{
|
||||||
|
//Read i2c device data from i2c device address
|
||||||
|
if (PrivRead(sdev->fd, sdev->buffer, len) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct SensorDone done =
|
||||||
|
{
|
||||||
|
SensorDeviceOpen,
|
||||||
|
NULL,
|
||||||
|
SensorDeviceRead,
|
||||||
|
SensorDeviceWrite,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Init BMP180 sensor and register
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
static void SensorDeviceBmp180Init(void)
|
||||||
|
{
|
||||||
|
bmp180.name = SENSOR_DEVICE_BMP180;
|
||||||
|
bmp180.info = &info;
|
||||||
|
bmp180.done = &done;
|
||||||
|
bmp180.status = SENSOR_DEVICE_PASSIVE;
|
||||||
|
|
||||||
|
SensorDeviceRegister(&bmp180);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct SensorQuantity bmp180_altitude;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Stores all of the bmp180's calibration values into global variables
|
||||||
|
* @return uint16_t reg data
|
||||||
|
*/
|
||||||
|
static uint16_t SensorDeviceBmp180ReadRegs(struct SensorDevice *sdev, char reg_addr)
|
||||||
|
{
|
||||||
|
uint8_t reg_data[2] = {0};
|
||||||
|
|
||||||
|
if (SensorDeviceWrite(sdev, ®_addr, 1) < 0) {
|
||||||
|
printf("SensorDeviceBmp180ReadRegs write reg 0x%x error. return 0x0\n", reg_addr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (SensorDeviceRead(sdev, 2) < 0) {
|
||||||
|
printf("SensorDeviceBmp180ReadRegs error. return 0x0\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
reg_data[0] = sdev->buffer[0];
|
||||||
|
reg_data[1] = sdev->buffer[1];
|
||||||
|
|
||||||
|
return (uint16_t)(reg_data[0] << 8 | reg_data[1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Read the uncompensated temperature value(ut)
|
||||||
|
* @return uint16_t 0xF6 reg data
|
||||||
|
*/
|
||||||
|
static uint16_t SensorDeviceBmp180ReadUT(struct SensorDevice *sdev)
|
||||||
|
{
|
||||||
|
uint8_t data[2];
|
||||||
|
data[0] = 0xF4;
|
||||||
|
data[1] = 0x2E;
|
||||||
|
|
||||||
|
if (SensorDeviceWrite(sdev, data, 2) < 0) {
|
||||||
|
printf("SensorDeviceBmp180ReadUT write reg 0xF4 error. return 0x0\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SensorDeviceBmp180ReadRegs(sdev, 0xF6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Read the uncompensated pressure value(up)
|
||||||
|
* @return uint16_t 0xF6 reg data
|
||||||
|
*/
|
||||||
|
static uint16_t SensorDeviceBmp180ReadUP(struct SensorDevice *sdev)
|
||||||
|
{
|
||||||
|
uint8_t data[2];
|
||||||
|
data[0] = 0xF4;
|
||||||
|
data[1] = 0x34 + (OSS << 6);
|
||||||
|
|
||||||
|
if (SensorDeviceWrite(sdev, data, 2) < 0) {
|
||||||
|
printf("SensorDeviceBmp180ReadUP write reg 0xF4 error. return 0x0\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return SensorDeviceBmp180ReadRegs(sdev, 0xF6);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Calculate temperature
|
||||||
|
* @return uint16_t reg data
|
||||||
|
*/
|
||||||
|
static float SensorDeviceBmp180CalTemp(struct SensorDevice *sdev, uint16_t ut, Bmp180RegData *bmp180_reg_data)
|
||||||
|
{
|
||||||
|
long x1, x2;
|
||||||
|
x1 = (((long)ut - (long)bmp180_reg_data->unsigned_ac_data[2]) * (long)bmp180_reg_data->unsigned_ac_data[1]) >> 15;
|
||||||
|
x2 = ((long)bmp180_reg_data->m_data[1] << 11) / (x1 + bmp180_reg_data->m_data[2]);
|
||||||
|
CalTemp_data = x1 + x2;
|
||||||
|
float temp = ((CalTemp_data + 8) >> 4);
|
||||||
|
temp = temp / 10;
|
||||||
|
return temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Calculate pressure
|
||||||
|
* @return float pressure
|
||||||
|
*/
|
||||||
|
static float SensorDeviceBmp180CalPressure(struct SensorDevice *sdev, uint16_t up, Bmp180RegData *bmp180_reg_data)
|
||||||
|
{
|
||||||
|
long x1, x2, x3, y1, y2, pressure;
|
||||||
|
unsigned long z1, z2;
|
||||||
|
|
||||||
|
y2 = CalTemp_data - 4000;
|
||||||
|
// Calculate y1 data
|
||||||
|
x1 = (bmp180_reg_data->b_data[1] * (y2 * y2) >> 12) >> 11;
|
||||||
|
x2 = (bmp180_reg_data->ac_data[1] * y2)>>11;
|
||||||
|
x3 = x1 + x2;
|
||||||
|
y1 = (((((long)bmp180_reg_data->ac_data[0]) * 4 + x3) << OSS) + 2) >> 2;
|
||||||
|
|
||||||
|
// Calculate B4
|
||||||
|
x1 = (bmp180_reg_data->ac_data[2] * y2) >> 13;
|
||||||
|
x2 = (bmp180_reg_data->b_data[0] * ((y2 * y2) >> 12)) >> 16;
|
||||||
|
x3 = ((x1 + x2) + 2) >> 2;
|
||||||
|
z1 = (bmp180_reg_data->unsigned_ac_data[0] * (unsigned long)(x3 + 32768)) >> 15;
|
||||||
|
|
||||||
|
z2 = ((unsigned long)(up - y1) * (50000 >> OSS));
|
||||||
|
if (z2 < 0x80000000)
|
||||||
|
pressure = (z2 << 1) / z1;
|
||||||
|
else
|
||||||
|
pressure = (z2 / z1) << 1;
|
||||||
|
|
||||||
|
x1 = (pressure >> 8) * (pressure >> 8);
|
||||||
|
x1 = (x1 * 3038) >> 16;
|
||||||
|
x2 = (-7357 * pressure) >> 16;
|
||||||
|
pressure += (x1 + x2 + 3791) >> 4;
|
||||||
|
|
||||||
|
return pressure;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Calculate altitude
|
||||||
|
* @return float Altitude
|
||||||
|
*/
|
||||||
|
static float SensorDeviceBmp180CalAltitude(float pressure)
|
||||||
|
{
|
||||||
|
float A = pressure / 101325;
|
||||||
|
float B = 1 / 5.25588;
|
||||||
|
float altitude = pow(A, B);
|
||||||
|
altitude = 1 - altitude;
|
||||||
|
altitude = altitude / 0.0000225577;
|
||||||
|
|
||||||
|
return altitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Analysis BMP180 temperature result
|
||||||
|
* @param quant - sensor quantity pointer
|
||||||
|
* @return quantity value
|
||||||
|
*/
|
||||||
|
static int32_t ReadAltitude(struct SensorQuantity *quant)
|
||||||
|
{
|
||||||
|
if (!quant)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
memset(&bmp180_reg_data, 0 , sizeof(Bmp180RegData));
|
||||||
|
|
||||||
|
uint16_t ut, up = 0;
|
||||||
|
float bmp180_temperature, bmp180_pressure, bmp180_aititude;
|
||||||
|
if (quant->sdev->done->read != NULL) {
|
||||||
|
if (quant->sdev->status == SENSOR_DEVICE_PASSIVE) {
|
||||||
|
|
||||||
|
bmp180_reg_data.ac_data[0] = SensorDeviceBmp180ReadRegs(quant->sdev, 0xAA);
|
||||||
|
bmp180_reg_data.ac_data[1] = SensorDeviceBmp180ReadRegs(quant->sdev, 0xAC);
|
||||||
|
bmp180_reg_data.ac_data[2] = SensorDeviceBmp180ReadRegs(quant->sdev, 0xAE);
|
||||||
|
bmp180_reg_data.unsigned_ac_data[0] = SensorDeviceBmp180ReadRegs(quant->sdev, 0xB0);
|
||||||
|
bmp180_reg_data.unsigned_ac_data[1] = SensorDeviceBmp180ReadRegs(quant->sdev, 0xB2);
|
||||||
|
bmp180_reg_data.unsigned_ac_data[2] = SensorDeviceBmp180ReadRegs(quant->sdev, 0xB4);
|
||||||
|
bmp180_reg_data.b_data[0] = SensorDeviceBmp180ReadRegs(quant->sdev, 0xB6);
|
||||||
|
bmp180_reg_data.b_data[1] = SensorDeviceBmp180ReadRegs(quant->sdev, 0xB8);
|
||||||
|
bmp180_reg_data.m_data[0] = SensorDeviceBmp180ReadRegs(quant->sdev, 0xBA);
|
||||||
|
bmp180_reg_data.m_data[1] = SensorDeviceBmp180ReadRegs(quant->sdev, 0xBC);
|
||||||
|
bmp180_reg_data.m_data[2] = SensorDeviceBmp180ReadRegs(quant->sdev, 0xBE);
|
||||||
|
|
||||||
|
ut = SensorDeviceBmp180ReadUT(quant->sdev);
|
||||||
|
up = SensorDeviceBmp180ReadUP(quant->sdev);
|
||||||
|
|
||||||
|
bmp180_temperature = SensorDeviceBmp180CalTemp(quant->sdev, ut, &bmp180_reg_data);
|
||||||
|
bmp180_pressure = SensorDeviceBmp180CalPressure(quant->sdev, up, &bmp180_reg_data);
|
||||||
|
bmp180_aititude = SensorDeviceBmp180CalAltitude(bmp180_pressure);
|
||||||
|
|
||||||
|
return (int32_t)bmp180_pressure;
|
||||||
|
}
|
||||||
|
if (quant->sdev->status == SENSOR_DEVICE_ACTIVE) {
|
||||||
|
printf("Please set passive mode.\n");
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
printf("%s don't have read done.\n", quant->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Init BMP180 temperature quantity and register
|
||||||
|
* @return 0
|
||||||
|
*/
|
||||||
|
int Bmp180AltitudeInit(void)
|
||||||
|
{
|
||||||
|
SensorDeviceBmp180Init();
|
||||||
|
|
||||||
|
bmp180_altitude.name = SENSOR_QUANTITY_BMP180_ALTITUDE;
|
||||||
|
bmp180_altitude.type = SENSOR_QUANTITY_ALTITUDE;
|
||||||
|
bmp180_altitude.value.decimal_places = 1;
|
||||||
|
bmp180_altitude.value.max_std = 1000;
|
||||||
|
bmp180_altitude.value.min_std = 0;
|
||||||
|
bmp180_altitude.value.last_value = SENSOR_QUANTITY_VALUE_ERROR;
|
||||||
|
bmp180_altitude.value.max_value = SENSOR_QUANTITY_VALUE_ERROR;
|
||||||
|
bmp180_altitude.value.min_value = SENSOR_QUANTITY_VALUE_ERROR;
|
||||||
|
bmp180_altitude.sdev = &bmp180;
|
||||||
|
bmp180_altitude.ReadValue = ReadAltitude;
|
||||||
|
|
||||||
|
SensorQuantityRegister(&bmp180_altitude);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -46,3 +46,46 @@ config SENSOR_ZG09
|
||||||
|
|
||||||
endif
|
endif
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
config SENSOR_G8S
|
||||||
|
bool "Using g8-s"
|
||||||
|
default n
|
||||||
|
|
||||||
|
if SENSOR_G8S
|
||||||
|
config SENSOR_DEVICE_G8S
|
||||||
|
string "g8-s sensor name"
|
||||||
|
default "g8-s"
|
||||||
|
|
||||||
|
config SENSOR_QUANTITY_G8S_CO2
|
||||||
|
string "g8-s quantity name"
|
||||||
|
default "co2_2"
|
||||||
|
|
||||||
|
if ADD_XIZI_FETURES
|
||||||
|
config SENSOR_G8S_DRIVER_EXTUART
|
||||||
|
bool "Using extra uart to support g8-s"
|
||||||
|
default n
|
||||||
|
|
||||||
|
config SENSOR_DEVICE_G8S_DEV
|
||||||
|
string "g8-s device uart path"
|
||||||
|
default "/dev/uart2_dev2"
|
||||||
|
depends on !SENSOR_G8S_DRIVER_EXTUART
|
||||||
|
|
||||||
|
if SENSOR_G8S_DRIVER_EXTUART
|
||||||
|
config SENSOR_DEVICE_G8S_DEV
|
||||||
|
string "g8-s device extra uart path"
|
||||||
|
default "/dev/extuart_dev4"
|
||||||
|
|
||||||
|
config SENSOR_DEVICE_G8S_DEV_EXT_PORT
|
||||||
|
int "if g8-s device using extuart, choose port"
|
||||||
|
default "4"
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ADD_NUTTX_FETURES
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ADD_RTTHREAD_FETURES
|
||||||
|
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
|
@ -2,4 +2,8 @@ ifeq ($(CONFIG_SENSOR_ZG09),y)
|
||||||
SRC_DIR += zg09
|
SRC_DIR += zg09
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
ifeq ($(CONFIG_SENSOR_G8S),y)
|
||||||
|
SRC_DIR += g8s
|
||||||
|
endif
|
||||||
|
|
||||||
include $(KERNEL_ROOT)/compiler.mk
|
include $(KERNEL_ROOT)/compiler.mk
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
import os
|
||||||
|
Import('RTT_ROOT')
|
||||||
|
from building import *
|
||||||
|
|
||||||
|
cwd = GetCurrentDir()
|
||||||
|
objs = []
|
||||||
|
list = os.listdir(cwd)
|
||||||
|
|
||||||
|
for d in list:
|
||||||
|
path = os.path.join(cwd, d)
|
||||||
|
if os.path.isfile(os.path.join(path, 'SConscript')):
|
||||||
|
objs = objs + SConscript(os.path.join(path, 'SConscript'))
|
||||||
|
|
||||||
|
Return('objs')
|
|
@ -0,0 +1,3 @@
|
||||||
|
SRC_FILES := g8s.c
|
||||||
|
|
||||||
|
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -0,0 +1,10 @@
|
||||||
|
from building import *
|
||||||
|
import os
|
||||||
|
|
||||||
|
cwd = GetCurrentDir()
|
||||||
|
src = []
|
||||||
|
if GetDepend(['SENSOR_G8S']):
|
||||||
|
src += ['g8s.c']
|
||||||
|
group = DefineGroup('sensor co2 g8s', src, depend = [], CPPPATH = [cwd])
|
||||||
|
|
||||||
|
Return('group')
|
|
@ -0,0 +1,187 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 AIIT XUOS Lab
|
||||||
|
* XiUOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file g8s.c
|
||||||
|
* @brief G8S CO2 driver base sensor
|
||||||
|
* @version 1.1
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2021.12.23
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sensor.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
static uint8_t g8s_read_instruction[8] = {0x52, 0x36, 0x09, 0x37, 0x38, 0x0D, 0x0A};
|
||||||
|
|
||||||
|
static struct SensorDevice g8s;
|
||||||
|
|
||||||
|
static struct SensorProductInfo info =
|
||||||
|
{
|
||||||
|
SENSOR_ABILITY_CO2,
|
||||||
|
"senTec",
|
||||||
|
"G8S",
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Open G8S sensor device
|
||||||
|
* @param sdev - sensor device pointer
|
||||||
|
* @return success: 1 , failure: other
|
||||||
|
*/
|
||||||
|
static int SensorDeviceOpen(struct SensorDevice *sdev)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
sdev->fd = PrivOpen(SENSOR_DEVICE_G8S_DEV, O_RDWR);
|
||||||
|
if (sdev->fd < 0) {
|
||||||
|
printf("open %s error\n", SENSOR_DEVICE_G8S_DEV);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SerialDataCfg cfg;
|
||||||
|
cfg.serial_baud_rate = BAUD_RATE_9600;
|
||||||
|
cfg.serial_data_bits = DATA_BITS_8;
|
||||||
|
cfg.serial_stop_bits = STOP_BITS_1;
|
||||||
|
cfg.serial_buffer_size = 128;
|
||||||
|
cfg.serial_parity_mode = PARITY_NONE;
|
||||||
|
cfg.serial_bit_order = 0;
|
||||||
|
cfg.serial_invert_mode = 0;
|
||||||
|
#ifdef SENSOR_G8S_DRIVER_EXTUART
|
||||||
|
cfg.ext_uart_no = SENSOR_DEVICE_G8S_DEV_EXT_PORT;
|
||||||
|
cfg.port_configure = PORT_CFG_INIT;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct PrivIoctlCfg ioctl_cfg;
|
||||||
|
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
|
||||||
|
ioctl_cfg.args = &cfg;
|
||||||
|
result = PrivIoctl(sdev->fd, OPE_INT, &ioctl_cfg);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Read sensor device
|
||||||
|
* @param sdev - sensor device pointer
|
||||||
|
* @param len - the length of the read data
|
||||||
|
* @return get data length
|
||||||
|
*/
|
||||||
|
static int SensorDeviceRead(struct SensorDevice *sdev, size_t len)
|
||||||
|
{
|
||||||
|
uint8_t tmp = 0;
|
||||||
|
|
||||||
|
PrivWrite(sdev->fd, g8s_read_instruction, sizeof(g8s_read_instruction));
|
||||||
|
|
||||||
|
if (PrivRead(sdev->fd, sdev->buffer, len) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct SensorDone done =
|
||||||
|
{
|
||||||
|
SensorDeviceOpen,
|
||||||
|
NULL,
|
||||||
|
SensorDeviceRead,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Init G8S sensor and register
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
static void SensorDeviceG8sInit(void)
|
||||||
|
{
|
||||||
|
g8s.name = SENSOR_DEVICE_G8S;
|
||||||
|
g8s.info = &info;
|
||||||
|
g8s.done = &done;
|
||||||
|
g8s.status = SENSOR_DEVICE_PASSIVE;
|
||||||
|
|
||||||
|
SensorDeviceRegister(&g8s);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct SensorQuantity g8s_co2;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Analysis G8S CO2 result
|
||||||
|
* @param quant - sensor quantity pointer
|
||||||
|
* @return quantity value
|
||||||
|
*/
|
||||||
|
static int32_t QuantityRead(struct SensorQuantity *quant)
|
||||||
|
{
|
||||||
|
if (!quant)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
int i, ascii_length;
|
||||||
|
int32_t result = 0;
|
||||||
|
uint8_t result_ascii[9], result_hex[9];
|
||||||
|
|
||||||
|
memset(result_ascii, 0, 9);
|
||||||
|
memset(result_hex, 0, 9);
|
||||||
|
|
||||||
|
if (quant->sdev->done->read != NULL) {
|
||||||
|
if(quant->sdev->status == SENSOR_DEVICE_PASSIVE) {
|
||||||
|
quant->sdev->done->read(quant->sdev, 9);
|
||||||
|
|
||||||
|
for (i = 0; i < 9; i ++) {
|
||||||
|
if (0x09 == quant->sdev->buffer[i]) {
|
||||||
|
ascii_length = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
result_ascii[i] = quant->sdev->buffer[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
if (8 == ascii_length) {
|
||||||
|
for (i = 0; i < ascii_length; i ++) {
|
||||||
|
result_hex[i] = result_ascii[i] - 0x30;
|
||||||
|
result += result_hex[i] * pow(10, ascii_length - 1 - i);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
} else {
|
||||||
|
printf("This reading is wrong\n");
|
||||||
|
result = SENSOR_QUANTITY_VALUE_ERROR;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (quant->sdev->status == SENSOR_DEVICE_ACTIVE) {
|
||||||
|
printf("Please set passive mode.\n");
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
printf("%s don't have read done.\n", quant->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Init G8S CO2 quantity and register
|
||||||
|
* @return 0
|
||||||
|
*/
|
||||||
|
int G8sCo2Init(void)
|
||||||
|
{
|
||||||
|
SensorDeviceG8sInit();
|
||||||
|
|
||||||
|
g8s_co2.name = SENSOR_QUANTITY_G8S_CO2;
|
||||||
|
g8s_co2.type = SENSOR_QUANTITY_CO2;
|
||||||
|
g8s_co2.value.decimal_places = 0;
|
||||||
|
g8s_co2.value.max_std = 2000;
|
||||||
|
g8s_co2.value.min_std = 0;
|
||||||
|
g8s_co2.value.last_value = SENSOR_QUANTITY_VALUE_ERROR;
|
||||||
|
g8s_co2.value.max_value = SENSOR_QUANTITY_VALUE_ERROR;
|
||||||
|
g8s_co2.value.min_value = SENSOR_QUANTITY_VALUE_ERROR;
|
||||||
|
g8s_co2.sdev = &g8s;
|
||||||
|
g8s_co2.ReadValue = QuantityRead;
|
||||||
|
|
||||||
|
SensorQuantityRegister(&g8s_co2);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -69,28 +69,11 @@ static int SensorDeviceOpen(struct SensorDevice *sdev)
|
||||||
*/
|
*/
|
||||||
static int SensorDeviceRead(struct SensorDevice *sdev, size_t len)
|
static int SensorDeviceRead(struct SensorDevice *sdev, size_t len)
|
||||||
{
|
{
|
||||||
#ifdef ADD_NUTTX_FETURES
|
|
||||||
int ret;
|
|
||||||
ret = PrivRead(sdev->fd, sdev->buffer, len);
|
|
||||||
if (ret != len ){
|
|
||||||
perror("Failed to read data!\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
#else
|
|
||||||
//send i2c device start signal and address, need to implemente in OS i2c driver
|
|
||||||
if (PrivWrite(sdev->fd, NULL, 0) != 1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
PrivTaskDelay(50);
|
|
||||||
|
|
||||||
//Read i2c device data from i2c device address
|
//Read i2c device data from i2c device address
|
||||||
if (PrivRead(sdev->fd, sdev->buffer, len) != 1)
|
if (PrivRead(sdev->fd, sdev->buffer, len) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct SensorDone done =
|
static struct SensorDone done =
|
||||||
|
|
|
@ -55,6 +55,9 @@ extern "C" {
|
||||||
#define SENSOR_ABILITY_IAQ ((uint32_t)(1 << SENSOR_QUANTITY_IAQ))
|
#define SENSOR_ABILITY_IAQ ((uint32_t)(1 << SENSOR_QUANTITY_IAQ))
|
||||||
#define SENSOR_ABILITY_TVOC ((uint32_t)(1 << SENSOR_QUANTITY_TVOC))
|
#define SENSOR_ABILITY_TVOC ((uint32_t)(1 << SENSOR_QUANTITY_TVOC))
|
||||||
#define SENSOR_ABILITY_HCHO ((uint32_t)(1 << SENSOR_QUANTITY_HCHO))
|
#define SENSOR_ABILITY_HCHO ((uint32_t)(1 << SENSOR_QUANTITY_HCHO))
|
||||||
|
#define SENSOR_ABILITY_WINDSPEED ((uint32_t)(1 << SENSOR_QUANTITY_WINDSPEED))
|
||||||
|
#define SENSOR_ABILITY_WINDDIRECTION ((uint32_t)(1 << SENSOR_QUANTITY_WINDDIRECTION))
|
||||||
|
#define SENSOR_ABILITY_ALTITUDE ((uint32_t)(1 << SENSOR_QUANTITY_ALTITUDE))
|
||||||
|
|
||||||
struct SensorProductInfo {
|
struct SensorProductInfo {
|
||||||
uint32_t ability; /* Bitwise OR of sensor ability */
|
uint32_t ability; /* Bitwise OR of sensor ability */
|
||||||
|
@ -96,6 +99,9 @@ enum SensorQuantityType {
|
||||||
SENSOR_QUANTITY_CH4,
|
SENSOR_QUANTITY_CH4,
|
||||||
SENSOR_QUANTITY_IAQ,
|
SENSOR_QUANTITY_IAQ,
|
||||||
SENSOR_QUANTITY_TVOC,
|
SENSOR_QUANTITY_TVOC,
|
||||||
|
SENSOR_QUANTITY_WINDSPEED,
|
||||||
|
SENSOR_QUANTITY_WINDDIRECTION,
|
||||||
|
SENSOR_QUANTITY_ALTITUDE,
|
||||||
/* ...... */
|
/* ...... */
|
||||||
SENSOR_QUANTITY_END,
|
SENSOR_QUANTITY_END,
|
||||||
};
|
};
|
||||||
|
|
|
@ -68,28 +68,11 @@ static int SensorDeviceOpen(struct SensorDevice *sdev)
|
||||||
*/
|
*/
|
||||||
static int SensorDeviceRead(struct SensorDevice *sdev, size_t len)
|
static int SensorDeviceRead(struct SensorDevice *sdev, size_t len)
|
||||||
{
|
{
|
||||||
#ifdef ADD_NUTTX_FETURES
|
|
||||||
int ret;
|
|
||||||
ret = PrivRead(sdev->fd, sdev->buffer, len);
|
|
||||||
if (ret != len ){
|
|
||||||
perror("Failed to read data!\n");
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
#else
|
|
||||||
//send i2c device start signal and address, need to implemente in OS i2c driver
|
|
||||||
if (PrivWrite(sdev->fd, NULL, 0) != 1)
|
|
||||||
return -1;
|
|
||||||
|
|
||||||
PrivTaskDelay(50);
|
|
||||||
|
|
||||||
//Read i2c device data from i2c device address
|
//Read i2c device data from i2c device address
|
||||||
if (PrivRead(sdev->fd, sdev->buffer, len) != 1)
|
if (PrivRead(sdev->fd, sdev->buffer, len) < 0)
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct SensorDone done =
|
static struct SensorDone done =
|
||||||
|
|
|
@ -0,0 +1,43 @@
|
||||||
|
|
||||||
|
config SENSOR_QS_FX
|
||||||
|
bool "Using qs-fx wind direction sensor"
|
||||||
|
default n
|
||||||
|
|
||||||
|
if SENSOR_QS_FX
|
||||||
|
config SENSOR_DEVICE_QS_FX
|
||||||
|
string "qs-fx sensor name"
|
||||||
|
default "qs_fx"
|
||||||
|
|
||||||
|
config SENSOR_QUANTITY_QS_FX_WINDDIRECTION
|
||||||
|
string "qs-fx quantity name"
|
||||||
|
default "winddirection_1"
|
||||||
|
|
||||||
|
if ADD_XIZI_FETURES
|
||||||
|
config SENSOR_QS_FX_DRIVER_EXTUART
|
||||||
|
bool "Using extra uart to support qs-fx"
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SENSOR_DEVICE_QS_FX_DEV
|
||||||
|
string "qs-fx device name"
|
||||||
|
default "/dev/uart2_dev2"
|
||||||
|
depends on !SENSOR_QS_FX_DRIVER_EXTUART
|
||||||
|
|
||||||
|
if SENSOR_QS_FX_DRIVER_EXTUART
|
||||||
|
config SENSOR_DEVICE_QS_FX_DEV
|
||||||
|
string "qs-fx device extra uart path"
|
||||||
|
default "/dev/extuart_dev2"
|
||||||
|
|
||||||
|
config SENSOR_DEVICE_QS_FX_DEV_EXT_PORT
|
||||||
|
int "if qs-fx device using extuart, choose port"
|
||||||
|
default "2"
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ADD_NUTTX_FETURES
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ADD_RTTHREAD_FETURES
|
||||||
|
|
||||||
|
endif
|
||||||
|
endif
|
|
@ -0,0 +1,5 @@
|
||||||
|
ifeq ($(CONFIG_SENSOR_QS_FX),y)
|
||||||
|
SRC_DIR += qs-fx
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -0,0 +1,14 @@
|
||||||
|
import os
|
||||||
|
Import('RTT_ROOT')
|
||||||
|
from building import *
|
||||||
|
|
||||||
|
cwd = GetCurrentDir()
|
||||||
|
objs = []
|
||||||
|
list = os.listdir(cwd)
|
||||||
|
|
||||||
|
for d in list:
|
||||||
|
path = os.path.join(cwd, d)
|
||||||
|
if os.path.isfile(os.path.join(path, 'SConscript')):
|
||||||
|
objs = objs + SConscript(os.path.join(path, 'SConscript'))
|
||||||
|
|
||||||
|
Return('objs')
|
|
@ -0,0 +1,3 @@
|
||||||
|
SRC_FILES := qs-fx.c
|
||||||
|
|
||||||
|
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -0,0 +1,10 @@
|
||||||
|
from building import *
|
||||||
|
import os
|
||||||
|
|
||||||
|
cwd = GetCurrentDir()
|
||||||
|
src = []
|
||||||
|
if GetDepend(['SENSOR_QS_FX']):
|
||||||
|
src += ['qs-fx.c']
|
||||||
|
group = DefineGroup('sensor wind direction qs-fx', src, depend = [], CPPPATH = [cwd])
|
||||||
|
|
||||||
|
Return('group')
|
|
@ -0,0 +1,162 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 AIIT XUOS Lab
|
||||||
|
* XiUOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file qs-fx.c
|
||||||
|
* @brief qs-fx wind direction driver base sensor
|
||||||
|
* @version 1.1
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2021.12.10
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sensor.h>
|
||||||
|
|
||||||
|
static struct SensorDevice qs_fx;
|
||||||
|
static char instructions[] = {0x02, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x39};
|
||||||
|
|
||||||
|
static struct SensorProductInfo info =
|
||||||
|
{
|
||||||
|
SENSOR_ABILITY_WINDDIRECTION,
|
||||||
|
"清易电子",
|
||||||
|
"QS-FX",
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Open QS-FX voice device
|
||||||
|
* @param sdev - sensor device pointer
|
||||||
|
* @return success: 1 , failure: other
|
||||||
|
*/
|
||||||
|
static int SensorDeviceOpen(struct SensorDevice *sdev)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
sdev->fd = PrivOpen(SENSOR_DEVICE_QS_FX_DEV, O_RDWR);
|
||||||
|
if (sdev->fd < 0) {
|
||||||
|
printf("open %s error\n", SENSOR_DEVICE_QS_FX_DEV);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SerialDataCfg cfg;
|
||||||
|
cfg.serial_baud_rate = BAUD_RATE_9600;
|
||||||
|
cfg.serial_data_bits = DATA_BITS_8;
|
||||||
|
cfg.serial_stop_bits = STOP_BITS_1;
|
||||||
|
cfg.serial_buffer_size = 64;
|
||||||
|
cfg.serial_parity_mode = PARITY_NONE;
|
||||||
|
cfg.serial_bit_order = 0;
|
||||||
|
cfg.serial_invert_mode = 0;
|
||||||
|
#ifdef SENSOR_QS_FX_DRIVER_EXTUART
|
||||||
|
cfg.ext_uart_no = SENSOR_DEVICE_QS_FX_DEV_EXT_PORT;
|
||||||
|
cfg.port_configure = PORT_CFG_INIT;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct PrivIoctlCfg ioctl_cfg;
|
||||||
|
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
|
||||||
|
ioctl_cfg.args = &cfg;
|
||||||
|
result = PrivIoctl(sdev->fd, OPE_INT, &ioctl_cfg);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Read sensor device
|
||||||
|
* @param sdev - sensor device pointer
|
||||||
|
* @param len - the length of the read data
|
||||||
|
* @return get data length
|
||||||
|
*/
|
||||||
|
static int SensorDeviceRead(struct SensorDevice *sdev, size_t len)
|
||||||
|
{
|
||||||
|
if (PrivWrite(sdev->fd, instructions, sizeof(instructions)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (PrivRead(sdev->fd, sdev->buffer, len) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct SensorDone done =
|
||||||
|
{
|
||||||
|
SensorDeviceOpen,
|
||||||
|
NULL,
|
||||||
|
SensorDeviceRead,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Init QS-FX sensor and register
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
static void QsFxInit(void)
|
||||||
|
{
|
||||||
|
qs_fx.name = SENSOR_DEVICE_QS_FX;
|
||||||
|
qs_fx.info = &info;
|
||||||
|
qs_fx.done = &done;
|
||||||
|
qs_fx.status = SENSOR_DEVICE_PASSIVE;
|
||||||
|
|
||||||
|
SensorDeviceRegister(&qs_fx);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct SensorQuantity qs_fx_wind_direction;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Analysis QS-FX wind direction
|
||||||
|
* @param quant - sensor quantity pointer
|
||||||
|
* @return quantity value
|
||||||
|
*/
|
||||||
|
static int32_t ReadWindDirection(struct SensorQuantity *quant)
|
||||||
|
{
|
||||||
|
if (!quant)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
short result;
|
||||||
|
if (quant->sdev->done->read != NULL) {
|
||||||
|
if (quant->sdev->status == SENSOR_DEVICE_PASSIVE) {
|
||||||
|
quant->sdev->done->read(quant->sdev, 6);
|
||||||
|
result = (quant->sdev->buffer[3] << 8) | quant->sdev->buffer[4];
|
||||||
|
|
||||||
|
return (int32_t)result;
|
||||||
|
}
|
||||||
|
if (quant->sdev->status == SENSOR_DEVICE_ACTIVE) {
|
||||||
|
printf("Please set passive mode.\n");
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
printf("%s don't have read done.\n", quant->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Init QS-FX voice quantity and register
|
||||||
|
* @return 0
|
||||||
|
*/
|
||||||
|
int QsFxWindDirectionInit(void)
|
||||||
|
{
|
||||||
|
QsFxInit();
|
||||||
|
|
||||||
|
qs_fx_wind_direction.name = SENSOR_QUANTITY_QS_FX_WINDDIRECTION;
|
||||||
|
qs_fx_wind_direction.type = SENSOR_QUANTITY_WINDDIRECTION;
|
||||||
|
qs_fx_wind_direction.value.decimal_places = 1;
|
||||||
|
qs_fx_wind_direction.value.max_std = 600;
|
||||||
|
qs_fx_wind_direction.value.min_std = 0;
|
||||||
|
qs_fx_wind_direction.value.last_value = SENSOR_QUANTITY_VALUE_ERROR;
|
||||||
|
qs_fx_wind_direction.value.max_value = SENSOR_QUANTITY_VALUE_ERROR;
|
||||||
|
qs_fx_wind_direction.value.min_value = SENSOR_QUANTITY_VALUE_ERROR;
|
||||||
|
qs_fx_wind_direction.sdev = &qs_fx;
|
||||||
|
qs_fx_wind_direction.ReadValue = ReadWindDirection;
|
||||||
|
|
||||||
|
SensorQuantityRegister(&qs_fx_wind_direction);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,43 @@
|
||||||
|
|
||||||
|
config SENSOR_QS_FS
|
||||||
|
bool "Using qs-fs wind speed sensor"
|
||||||
|
default n
|
||||||
|
|
||||||
|
if SENSOR_QS_FS
|
||||||
|
config SENSOR_DEVICE_QS_FS
|
||||||
|
string "qs-fs sensor name"
|
||||||
|
default "qs-fs"
|
||||||
|
|
||||||
|
config SENSOR_QUANTITY_QS_FS_WINDSPEED
|
||||||
|
string "qs-fs quantity name"
|
||||||
|
default "windspeed_1"
|
||||||
|
|
||||||
|
if ADD_XIZI_FETURES
|
||||||
|
config SENSOR_QS_FS_DRIVER_EXTUART
|
||||||
|
bool "Using extra uart to support qs-fx"
|
||||||
|
default y
|
||||||
|
|
||||||
|
config SENSOR_DEVICE_QS_FS_DEV
|
||||||
|
string "qs-fx device name"
|
||||||
|
default "/dev/uart2_dev2"
|
||||||
|
depends on !SENSOR_QS_FS_DRIVER_EXTUART
|
||||||
|
|
||||||
|
if SENSOR_QS_FS_DRIVER_EXTUART
|
||||||
|
config SENSOR_DEVICE_QS_FS_DEV
|
||||||
|
string "qs-fx device extra uart path"
|
||||||
|
default "/dev/extuart_dev7"
|
||||||
|
|
||||||
|
config SENSOR_DEVICE_QS_FS_DEV_EXT_PORT
|
||||||
|
int "if qs-fx device using extuart, choose port"
|
||||||
|
default "7"
|
||||||
|
endif
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ADD_NUTTX_FETURES
|
||||||
|
|
||||||
|
endif
|
||||||
|
|
||||||
|
if ADD_RTTHREAD_FETURES
|
||||||
|
|
||||||
|
endif
|
||||||
|
endif
|
|
@ -0,0 +1,5 @@
|
||||||
|
ifeq ($(CONFIG_SENSOR_QS_FS),y)
|
||||||
|
SRC_DIR += qs-fs
|
||||||
|
endif
|
||||||
|
|
||||||
|
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -0,0 +1,14 @@
|
||||||
|
import os
|
||||||
|
Import('RTT_ROOT')
|
||||||
|
from building import *
|
||||||
|
|
||||||
|
cwd = GetCurrentDir()
|
||||||
|
objs = []
|
||||||
|
list = os.listdir(cwd)
|
||||||
|
|
||||||
|
for d in list:
|
||||||
|
path = os.path.join(cwd, d)
|
||||||
|
if os.path.isfile(os.path.join(path, 'SConscript')):
|
||||||
|
objs = objs + SConscript(os.path.join(path, 'SConscript'))
|
||||||
|
|
||||||
|
Return('objs')
|
|
@ -0,0 +1,3 @@
|
||||||
|
SRC_FILES := qs-fs.c
|
||||||
|
|
||||||
|
include $(KERNEL_ROOT)/compiler.mk
|
|
@ -0,0 +1,10 @@
|
||||||
|
from building import *
|
||||||
|
import os
|
||||||
|
|
||||||
|
cwd = GetCurrentDir()
|
||||||
|
src = []
|
||||||
|
if GetDepend(['SENSOR_QS_FS']):
|
||||||
|
src += ['qs-fs.c']
|
||||||
|
group = DefineGroup('sensor wind speed qs-fs', src, depend = [], CPPPATH = [cwd])
|
||||||
|
|
||||||
|
Return('group')
|
|
@ -0,0 +1,162 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020 AIIT XUOS Lab
|
||||||
|
* XiUOS is licensed under Mulan PSL v2.
|
||||||
|
* You can use this software according to the terms and conditions of the Mulan PSL v2.
|
||||||
|
* You may obtain a copy of Mulan PSL v2 at:
|
||||||
|
* http://license.coscl.org.cn/MulanPSL2
|
||||||
|
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
|
||||||
|
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
|
||||||
|
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
|
||||||
|
* See the Mulan PSL v2 for more details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file qs-fs.c
|
||||||
|
* @brief qs-fs wind speed driver base sensor
|
||||||
|
* @version 1.1
|
||||||
|
* @author AIIT XUOS Lab
|
||||||
|
* @date 2021.12.10
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sensor.h>
|
||||||
|
|
||||||
|
static struct SensorDevice qs_fs;
|
||||||
|
static const unsigned char instructions[] = {0x01, 0x03, 0x00, 0x00, 0x00, 0x01, 0x84, 0x0A};
|
||||||
|
|
||||||
|
static struct SensorProductInfo info =
|
||||||
|
{
|
||||||
|
SENSOR_ABILITY_WINDSPEED,
|
||||||
|
"清易电子",
|
||||||
|
"QS-FS",
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Open QS-FS voice device
|
||||||
|
* @param sdev - sensor device pointer
|
||||||
|
* @return success: 1 , failure: other
|
||||||
|
*/
|
||||||
|
static int SensorDeviceOpen(struct SensorDevice *sdev)
|
||||||
|
{
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
|
sdev->fd = PrivOpen(SENSOR_DEVICE_QS_FS_DEV, O_RDWR);
|
||||||
|
if (sdev->fd < 0) {
|
||||||
|
printf("open %s error\n", SENSOR_DEVICE_QS_FS_DEV);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SerialDataCfg cfg;
|
||||||
|
cfg.serial_baud_rate = BAUD_RATE_9600;
|
||||||
|
cfg.serial_data_bits = DATA_BITS_8;
|
||||||
|
cfg.serial_stop_bits = STOP_BITS_1;
|
||||||
|
cfg.serial_buffer_size = 64;
|
||||||
|
cfg.serial_parity_mode = PARITY_NONE;
|
||||||
|
cfg.serial_bit_order = 0;
|
||||||
|
cfg.serial_invert_mode = 0;
|
||||||
|
#ifdef SENSOR_QS_FS_DRIVER_EXTUART
|
||||||
|
cfg.ext_uart_no = SENSOR_DEVICE_QS_FS_DEV_EXT_PORT;
|
||||||
|
cfg.port_configure = PORT_CFG_INIT;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
struct PrivIoctlCfg ioctl_cfg;
|
||||||
|
ioctl_cfg.ioctl_driver_type = SERIAL_TYPE;
|
||||||
|
ioctl_cfg.args = &cfg;
|
||||||
|
result = PrivIoctl(sdev->fd, OPE_INT, &ioctl_cfg);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Read sensor device
|
||||||
|
* @param sdev - sensor device pointer
|
||||||
|
* @param len - the length of the read data
|
||||||
|
* @return get data length
|
||||||
|
*/
|
||||||
|
static int SensorDeviceRead(struct SensorDevice *sdev, size_t len)
|
||||||
|
{
|
||||||
|
if (PrivWrite(sdev->fd, instructions, sizeof(instructions)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if (PrivRead(sdev->fd, sdev->buffer, len) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct SensorDone done =
|
||||||
|
{
|
||||||
|
SensorDeviceOpen,
|
||||||
|
NULL,
|
||||||
|
SensorDeviceRead,
|
||||||
|
NULL,
|
||||||
|
NULL,
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Init QS-FS sensor and register
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
static void QsFsInit(void)
|
||||||
|
{
|
||||||
|
qs_fs.name = SENSOR_DEVICE_QS_FS;
|
||||||
|
qs_fs.info = &info;
|
||||||
|
qs_fs.done = &done;
|
||||||
|
qs_fs.status = SENSOR_DEVICE_PASSIVE;
|
||||||
|
|
||||||
|
SensorDeviceRegister(&qs_fs);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static struct SensorQuantity qs_fs_wind_speed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Analysis QS-FS wind speed
|
||||||
|
* @param quant - sensor quantity pointer
|
||||||
|
* @return quantity value
|
||||||
|
*/
|
||||||
|
static int32_t ReadWindSpeed(struct SensorQuantity *quant)
|
||||||
|
{
|
||||||
|
if (!quant)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
short result;
|
||||||
|
if (quant->sdev->done->read != NULL) {
|
||||||
|
if (quant->sdev->status == SENSOR_DEVICE_PASSIVE) {
|
||||||
|
quant->sdev->done->read(quant->sdev, 6);
|
||||||
|
result = (quant->sdev->buffer[3] << 8) | quant->sdev->buffer[4];
|
||||||
|
|
||||||
|
return (int32_t)result;
|
||||||
|
}
|
||||||
|
if (quant->sdev->status == SENSOR_DEVICE_ACTIVE) {
|
||||||
|
printf("Please set passive mode.\n");
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
printf("%s don't have read done.\n", quant->name);
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @description: Init QS-FS voice quantity and register
|
||||||
|
* @return 0
|
||||||
|
*/
|
||||||
|
int QsFsWindSpeedInit(void)
|
||||||
|
{
|
||||||
|
QsFsInit();
|
||||||
|
|
||||||
|
qs_fs_wind_speed.name = SENSOR_QUANTITY_QS_FS_WINDSPEED;
|
||||||
|
qs_fs_wind_speed.type = SENSOR_QUANTITY_WINDSPEED;
|
||||||
|
qs_fs_wind_speed.value.decimal_places = 1;
|
||||||
|
qs_fs_wind_speed.value.max_std = 600;
|
||||||
|
qs_fs_wind_speed.value.min_std = 0;
|
||||||
|
qs_fs_wind_speed.value.last_value = SENSOR_QUANTITY_VALUE_ERROR;
|
||||||
|
qs_fs_wind_speed.value.max_value = SENSOR_QUANTITY_VALUE_ERROR;
|
||||||
|
qs_fs_wind_speed.value.min_value = SENSOR_QUANTITY_VALUE_ERROR;
|
||||||
|
qs_fs_wind_speed.sdev = &qs_fs;
|
||||||
|
qs_fs_wind_speed.ReadValue = ReadWindSpeed;
|
||||||
|
|
||||||
|
SensorQuantityRegister(&qs_fs_wind_speed);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -171,9 +171,6 @@ int PrivMutexDelete(pthread_mutex_t *p_mutex);
|
||||||
int PrivMutexObtain(pthread_mutex_t *p_mutex);
|
int PrivMutexObtain(pthread_mutex_t *p_mutex);
|
||||||
int PrivMutexAbandon(pthread_mutex_t *p_mutex);
|
int PrivMutexAbandon(pthread_mutex_t *p_mutex);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*********************semaphore**********************/
|
/*********************semaphore**********************/
|
||||||
|
|
||||||
int PrivSemaphoreCreate(sem_t *sem, int pshared, unsigned int value);
|
int PrivSemaphoreCreate(sem_t *sem, int pshared, unsigned int value);
|
||||||
|
|
|
@ -141,6 +141,7 @@ static int PrivSerialIoctl(int fd, int cmd, void *args)
|
||||||
config.bufsz = RT_SERIAL_RB_BUFSZ;
|
config.bufsz = RT_SERIAL_RB_BUFSZ;
|
||||||
config.parity = serial_cfg->serial_parity_mode;
|
config.parity = serial_cfg->serial_parity_mode;
|
||||||
config.invert = serial_cfg->serial_invert_mode;
|
config.invert = serial_cfg->serial_invert_mode;
|
||||||
|
config.reserved = serial_cfg->ext_uart_no; ///< using extuart port number
|
||||||
rt_fd = fd_get(fd);
|
rt_fd = fd_get(fd);
|
||||||
ret = rt_fd->fops->ioctl(rt_fd, RT_DEVICE_CTRL_CONFIG, &config);
|
ret = rt_fd->fops->ioctl(rt_fd, RT_DEVICE_CTRL_CONFIG, &config);
|
||||||
return ret;
|
return ret;
|
||||||
|
|
|
@ -12,4 +12,5 @@ menu "lib"
|
||||||
source "$APP_DIR/lib/cJSON/Kconfig"
|
source "$APP_DIR/lib/cJSON/Kconfig"
|
||||||
source "$APP_DIR/lib/queue/Kconfig"
|
source "$APP_DIR/lib/queue/Kconfig"
|
||||||
source "$APP_DIR/lib/lvgl/Kconfig"
|
source "$APP_DIR/lib/lvgl/Kconfig"
|
||||||
|
source "$APP_DIR/lib/embedded_database/Kconfig"
|
||||||
endmenu
|
endmenu
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
menuconfig USING_EMBEDDED_DATABASE
|
||||||
|
bool "embedded database"
|
||||||
|
default n
|
||||||
|
if USING_EMBEDDED_DATABASE
|
||||||
|
source "$APP_DIR/lib/embedded_database/flashdb/Kconfig"
|
||||||
|
endif
|
|
@ -0,0 +1,14 @@
|
||||||
|
import os
|
||||||
|
Import('RTT_ROOT')
|
||||||
|
from building import *
|
||||||
|
|
||||||
|
cwd = GetCurrentDir()
|
||||||
|
objs = []
|
||||||
|
list = os.listdir(cwd)
|
||||||
|
|
||||||
|
for d in list:
|
||||||
|
path = os.path.join(cwd, d)
|
||||||
|
if os.path.isfile(os.path.join(path, 'SConscript')):
|
||||||
|
objs = objs + SConscript(os.path.join(path, 'SConscript'))
|
||||||
|
|
||||||
|
Return('objs')
|
|
@ -0,0 +1,25 @@
|
||||||
|
menuconfig USING_EMBEDDED_DATABASE_FLASHDB
|
||||||
|
bool "flashdb an ultra-lightweight embedded database "
|
||||||
|
default n
|
||||||
|
|
||||||
|
if USING_EMBEDDED_DATABASE_FLASHDB
|
||||||
|
comment " fal io is not supported so far"
|
||||||
|
choice
|
||||||
|
prompt "select io mode"
|
||||||
|
default FDB_USING_FILE_POSIX_MODE
|
||||||
|
help
|
||||||
|
Select io mode
|
||||||
|
config FDB_USING_FILE_POSIX_MODE
|
||||||
|
bool "file posix io "
|
||||||
|
config FDB_USING_FILE_LIBC_MODE
|
||||||
|
bool "file libc io "
|
||||||
|
config FDB_USING_FAL_MODE
|
||||||
|
bool "flash fal io "
|
||||||
|
endchoice
|
||||||
|
config FDB_USING_KVDB
|
||||||
|
bool "Use key value database"
|
||||||
|
default n
|
||||||
|
config FDB_USING_TSDB
|
||||||
|
bool "Use time series database"
|
||||||
|
default n
|
||||||
|
endif
|
|
@ -0,0 +1,10 @@
|
||||||
|
from building import *
|
||||||
|
import os
|
||||||
|
|
||||||
|
cwd = GetCurrentDir()
|
||||||
|
|
||||||
|
src = Glob('*.c')
|
||||||
|
|
||||||
|
group = DefineGroup('embedded database', src, depend = ['USING_EMBEDDED_DATABASE_FLASHDB'], CPPPATH = [cwd])
|
||||||
|
|
||||||
|
Return('group')
|
|
@ -0,0 +1,121 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Initialize interface.
|
||||||
|
*
|
||||||
|
* Some initialize interface for this library.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <flashdb.h>
|
||||||
|
#include <fdb_low_lvl.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define FDB_LOG_TAG ""
|
||||||
|
|
||||||
|
#if !defined(FDB_USING_FAL_MODE) && !defined(FDB_USING_FILE_MODE)
|
||||||
|
#error "Please defined the FDB_USING_FAL_MODE or FDB_USING_FILE_MODE macro"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
fdb_err_t _fdb_init_ex(fdb_db_t db, const char *name, const char *path, fdb_db_type type, void *user_data)
|
||||||
|
{
|
||||||
|
FDB_ASSERT(db);
|
||||||
|
FDB_ASSERT(name);
|
||||||
|
FDB_ASSERT(path);
|
||||||
|
|
||||||
|
if (db->init_ok) {
|
||||||
|
return FDB_NO_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
db->name = name;
|
||||||
|
db->type = type;
|
||||||
|
db->user_data = user_data;
|
||||||
|
|
||||||
|
if (db->file_mode) {
|
||||||
|
#ifdef FDB_USING_FILE_MODE
|
||||||
|
/* must set when using file mode */
|
||||||
|
FDB_ASSERT(db->sec_size != 0);
|
||||||
|
FDB_ASSERT(db->max_size != 0);
|
||||||
|
#ifdef FDB_USING_FILE_POSIX_MODE
|
||||||
|
db->cur_file = -1;
|
||||||
|
#else
|
||||||
|
db->cur_file = 0;
|
||||||
|
#endif
|
||||||
|
db->storage.dir = path;
|
||||||
|
FDB_ASSERT(strlen(path) != 0)
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
#ifdef FDB_USING_FAL_MODE
|
||||||
|
size_t block_size;
|
||||||
|
|
||||||
|
/* FAL (Flash Abstraction Layer) initialization */
|
||||||
|
fal_init();
|
||||||
|
/* check the flash partition */
|
||||||
|
if ((db->storage.part = fal_partition_find(path)) == NULL) {
|
||||||
|
FDB_INFO("Error: Partition (%s) not found.\n", path);
|
||||||
|
return FDB_PART_NOT_FOUND;
|
||||||
|
}
|
||||||
|
|
||||||
|
block_size = fal_flash_device_find(db->storage.part->flash_name)->blk_size;
|
||||||
|
if (db->sec_size == 0) {
|
||||||
|
db->sec_size = block_size;
|
||||||
|
} else {
|
||||||
|
/* must be aligned with block size */
|
||||||
|
FDB_ASSERT(db->sec_size % block_size == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
db->max_size = db->storage.part->len;
|
||||||
|
#endif /* FDB_USING_FAL_MODE */
|
||||||
|
}
|
||||||
|
|
||||||
|
/* must align with sector size */
|
||||||
|
FDB_ASSERT(db->max_size % db->sec_size == 0);
|
||||||
|
/* must have more than or equal 2 sector */
|
||||||
|
FDB_ASSERT(db->max_size / db->sec_size >= 2);
|
||||||
|
|
||||||
|
return FDB_NO_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
void _fdb_init_finish(fdb_db_t db, fdb_err_t result)
|
||||||
|
{
|
||||||
|
static bool log_is_show = false;
|
||||||
|
if (result == FDB_NO_ERR) {
|
||||||
|
db->init_ok = true;
|
||||||
|
if (!log_is_show) {
|
||||||
|
FDB_INFO("FlashDB V%s is initialize success.\n", FDB_SW_VERSION);
|
||||||
|
FDB_INFO("You can get the latest version on https://github.com/armink/FlashDB .\n");
|
||||||
|
log_is_show = true;
|
||||||
|
}
|
||||||
|
} else if (!db->not_formatable) {
|
||||||
|
FDB_INFO("Error: %s (%s) is initialize fail (%d).\n", db->type == FDB_DB_TYPE_KV ? "KVDB" : "TSDB",
|
||||||
|
db->name, (int)result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void _fdb_deinit(fdb_db_t db)
|
||||||
|
{
|
||||||
|
FDB_ASSERT(db);
|
||||||
|
|
||||||
|
if (db->init_ok) {
|
||||||
|
#ifdef FDB_USING_FILE_MODE
|
||||||
|
#ifdef FDB_USING_FILE_POSIX_MODE
|
||||||
|
if (db->cur_file > 0) {
|
||||||
|
#if !defined(_MSC_VER)
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
close(db->cur_file);
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
if (db->cur_file != 0) {
|
||||||
|
fclose(db->cur_file);
|
||||||
|
}
|
||||||
|
#endif /* FDB_USING_FILE_POSIX_MODE */
|
||||||
|
#endif /* FDB_USING_FILE_MODE */
|
||||||
|
}
|
||||||
|
|
||||||
|
db->init_ok = false;
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief configuration file
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FDB_CFG_H_
|
||||||
|
#define _FDB_CFG_H_
|
||||||
|
|
||||||
|
#ifdef FDB_USING_FAL_MODE
|
||||||
|
/* the flash write granularity, unit: bit
|
||||||
|
* only support 1(nor flash)/ 8(stm32f2/f4)/ 32(stm32f1) */
|
||||||
|
#define FDB_WRITE_GRAN /* @note you must define it for a value */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Using file storage mode by LIBC file API, like fopen/fread/fwrte/fclose */
|
||||||
|
/* #define FDB_USING_FILE_LIBC_MODE */
|
||||||
|
|
||||||
|
/* Using file storage mode by POSIX file API, like open/read/write/close */
|
||||||
|
/* #define FDB_USING_FILE_POSIX_MODE */
|
||||||
|
|
||||||
|
/* MCU Endian Configuration, default is Little Endian Order. */
|
||||||
|
/* #define FDB_BIG_ENDIAN */
|
||||||
|
|
||||||
|
/* log print macro. default EF_PRINT macro is printf() */
|
||||||
|
/* #define FDB_PRINT(...) my_printf(__VA_ARGS__) */
|
||||||
|
|
||||||
|
/* print debug information */
|
||||||
|
#define FDB_DEBUG_ENABLE
|
||||||
|
|
||||||
|
#endif /* _FDB_CFG_H_ */
|
|
@ -0,0 +1,340 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @file
|
||||||
|
* @brief Public definition.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef _FDB_DEF_H_
|
||||||
|
#define _FDB_DEF_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* software version number */
|
||||||
|
#define FDB_SW_VERSION "1.1.0"
|
||||||
|
#define FDB_SW_VERSION_NUM 0x10100
|
||||||
|
|
||||||
|
/* the KV max name length must less then it */
|
||||||
|
#ifndef FDB_KV_NAME_MAX
|
||||||
|
#define FDB_KV_NAME_MAX 64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* the KV cache table size, it will improve KV search speed when using cache */
|
||||||
|
#ifndef FDB_KV_CACHE_TABLE_SIZE
|
||||||
|
#define FDB_KV_CACHE_TABLE_SIZE 64
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* the sector cache table size, it will improve KV save speed when using cache */
|
||||||
|
#ifndef FDB_SECTOR_CACHE_TABLE_SIZE
|
||||||
|
#define FDB_SECTOR_CACHE_TABLE_SIZE 4
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if (FDB_KV_CACHE_TABLE_SIZE > 0) && (FDB_SECTOR_CACHE_TABLE_SIZE > 0)
|
||||||
|
#define FDB_KV_USING_CACHE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(FDB_USING_FILE_LIBC_MODE) || defined(FDB_USING_FILE_POSIX_MODE)
|
||||||
|
#define FDB_USING_FILE_MODE
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef FDB_WRITE_GRAN
|
||||||
|
#define FDB_WRITE_GRAN 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* log function. default FDB_PRINT macro is printf() */
|
||||||
|
#ifndef FDB_PRINT
|
||||||
|
#define FDB_PRINT(...) printf(__VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
#define FDB_LOG_PREFIX1() FDB_PRINT("[FlashDB]" FDB_LOG_TAG)
|
||||||
|
#define FDB_LOG_PREFIX2() FDB_PRINT(" ")
|
||||||
|
#define FDB_LOG_PREFIX() FDB_LOG_PREFIX1();FDB_LOG_PREFIX2()
|
||||||
|
#ifdef FDB_DEBUG_ENABLE
|
||||||
|
#define FDB_DEBUG(...) FDB_LOG_PREFIX();FDB_PRINT("(%s:%d) ", __FILE__, __LINE__);FDB_PRINT(__VA_ARGS__)
|
||||||
|
#else
|
||||||
|
#define FDB_DEBUG(...)
|
||||||
|
#endif
|
||||||
|
/* routine print function. Must be implement by user. */
|
||||||
|
#define FDB_INFO(...) FDB_LOG_PREFIX();FDB_PRINT(__VA_ARGS__)
|
||||||
|
/* assert for developer. */
|
||||||
|
#define FDB_ASSERT(EXPR) \
|
||||||
|
if (!(EXPR)) \
|
||||||
|
{ \
|
||||||
|
FDB_DEBUG("(%s) has assert failed at %s.\n", #EXPR, __FUNCTION__); \
|
||||||
|
while (1); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define FDB_KVDB_CTRL_SET_SEC_SIZE 0x00 /**< set sector size control command, this change MUST before database initialization */
|
||||||
|
#define FDB_KVDB_CTRL_GET_SEC_SIZE 0x01 /**< get sector size control command */
|
||||||
|
#define FDB_KVDB_CTRL_SET_LOCK 0x02 /**< set lock function control command */
|
||||||
|
#define FDB_KVDB_CTRL_SET_UNLOCK 0x03 /**< set unlock function control command */
|
||||||
|
#define FDB_KVDB_CTRL_SET_FILE_MODE 0x09 /**< set file mode control command, this change MUST before database initialization */
|
||||||
|
#define FDB_KVDB_CTRL_SET_MAX_SIZE 0x0A /**< set database max size in file mode control command, this change MUST before database initialization */
|
||||||
|
#define FDB_KVDB_CTRL_SET_NOT_FORMAT 0x0B /**< set database NOT format mode control command, this change MUST before database initialization */
|
||||||
|
|
||||||
|
#define FDB_TSDB_CTRL_SET_SEC_SIZE 0x00 /**< set sector size control command, this change MUST before database initialization */
|
||||||
|
#define FDB_TSDB_CTRL_GET_SEC_SIZE 0x01 /**< get sector size control command */
|
||||||
|
#define FDB_TSDB_CTRL_SET_LOCK 0x02 /**< set lock function control command */
|
||||||
|
#define FDB_TSDB_CTRL_SET_UNLOCK 0x03 /**< set unlock function control command */
|
||||||
|
#define FDB_TSDB_CTRL_SET_ROLLOVER 0x04 /**< set rollover control command, this change MUST after database initialization */
|
||||||
|
#define FDB_TSDB_CTRL_GET_ROLLOVER 0x05 /**< get rollover control command */
|
||||||
|
#define FDB_TSDB_CTRL_GET_LAST_TIME 0x06 /**< get last save time control command */
|
||||||
|
#define FDB_TSDB_CTRL_SET_FILE_MODE 0x09 /**< set file mode control command, this change MUST before database initialization */
|
||||||
|
#define FDB_TSDB_CTRL_SET_MAX_SIZE 0x0A /**< set database max size in file mode control command, this change MUST before database initialization */
|
||||||
|
#define FDB_TSDB_CTRL_SET_NOT_FORMAT 0x0B /**< set database NOT formatable mode control command, this change MUST before database initialization */
|
||||||
|
|
||||||
|
#ifdef FDB_USING_TIMESTAMP_64BIT
|
||||||
|
typedef int64_t fdb_time_t;
|
||||||
|
#else
|
||||||
|
typedef int32_t fdb_time_t;
|
||||||
|
#endif /* FDB_USING_TIMESTAMP_64BIT */
|
||||||
|
|
||||||
|
typedef fdb_time_t (*fdb_get_time)(void);
|
||||||
|
|
||||||
|
struct fdb_default_kv_node {
|
||||||
|
char *key;
|
||||||
|
void *value;
|
||||||
|
size_t value_len;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct fdb_default_kv {
|
||||||
|
struct fdb_default_kv_node *kvs;
|
||||||
|
size_t num;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* error code */
|
||||||
|
typedef enum {
|
||||||
|
FDB_NO_ERR,
|
||||||
|
FDB_ERASE_ERR,
|
||||||
|
FDB_READ_ERR,
|
||||||
|
FDB_WRITE_ERR,
|
||||||
|
FDB_PART_NOT_FOUND,
|
||||||
|
FDB_KV_NAME_ERR,
|
||||||
|
FDB_KV_NAME_EXIST,
|
||||||
|
FDB_SAVED_FULL,
|
||||||
|
FDB_INIT_FAILED,
|
||||||
|
} fdb_err_t;
|
||||||
|
|
||||||
|
enum fdb_kv_status {
|
||||||
|
FDB_KV_UNUSED,
|
||||||
|
FDB_KV_PRE_WRITE,
|
||||||
|
FDB_KV_WRITE,
|
||||||
|
FDB_KV_PRE_DELETE,
|
||||||
|
FDB_KV_DELETED,
|
||||||
|
FDB_KV_ERR_HDR,
|
||||||
|
#define FDB_KV_STATUS_NUM 6
|
||||||
|
};
|
||||||
|
typedef enum fdb_kv_status fdb_kv_status_t;
|
||||||
|
|
||||||
|
enum fdb_tsl_status {
|
||||||
|
FDB_TSL_UNUSED,
|
||||||
|
FDB_TSL_PRE_WRITE,
|
||||||
|
FDB_TSL_WRITE,
|
||||||
|
FDB_TSL_USER_STATUS1,
|
||||||
|
FDB_TSL_DELETED,
|
||||||
|
FDB_TSL_USER_STATUS2,
|
||||||
|
#define FDB_TSL_STATUS_NUM 6
|
||||||
|
};
|
||||||
|
typedef enum fdb_tsl_status fdb_tsl_status_t;
|
||||||
|
|
||||||
|
/* key-value node object */
|
||||||
|
struct fdb_kv {
|
||||||
|
fdb_kv_status_t status; /**< node status, @see fdb_kv_status_t */
|
||||||
|
bool crc_is_ok; /**< node CRC32 check is OK */
|
||||||
|
uint8_t name_len; /**< name length */
|
||||||
|
uint32_t magic; /**< magic word(`K`, `V`, `4`, `0`) */
|
||||||
|
uint32_t len; /**< node total length (header + name + value), must align by FDB_WRITE_GRAN */
|
||||||
|
uint32_t value_len; /**< value length */
|
||||||
|
char name[FDB_KV_NAME_MAX]; /**< name */
|
||||||
|
struct {
|
||||||
|
uint32_t start; /**< node start address */
|
||||||
|
uint32_t value; /**< value start address */
|
||||||
|
} addr;
|
||||||
|
};
|
||||||
|
typedef struct fdb_kv *fdb_kv_t;
|
||||||
|
|
||||||
|
struct fdb_kv_iterator {
|
||||||
|
struct fdb_kv curr_kv; /**< Current KV we get from the iterator */
|
||||||
|
uint32_t iterated_cnt; /**< How many KVs have we iterated already */
|
||||||
|
size_t iterated_obj_bytes; /**< Total storage size of KVs we have iterated. */
|
||||||
|
size_t iterated_value_bytes; /**< Total value size of KVs we have iterated. */
|
||||||
|
uint32_t sector_addr; /**< Current sector address we're iterating. DO NOT touch it. */
|
||||||
|
};
|
||||||
|
typedef struct fdb_kv_iterator *fdb_kv_iterator_t;
|
||||||
|
|
||||||
|
/* time series log node object */
|
||||||
|
struct fdb_tsl {
|
||||||
|
fdb_tsl_status_t status; /**< node status, @see fdb_log_status_t */
|
||||||
|
fdb_time_t time; /**< node timestamp */
|
||||||
|
uint32_t log_len; /**< log length, must align by FDB_WRITE_GRAN */
|
||||||
|
struct {
|
||||||
|
uint32_t index; /**< node index address */
|
||||||
|
uint32_t log; /**< log data address */
|
||||||
|
} addr;
|
||||||
|
};
|
||||||
|
typedef struct fdb_tsl *fdb_tsl_t;
|
||||||
|
typedef bool (*fdb_tsl_cb)(fdb_tsl_t tsl, void *arg);
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
FDB_DB_TYPE_KV,
|
||||||
|
FDB_DB_TYPE_TS,
|
||||||
|
} fdb_db_type;
|
||||||
|
|
||||||
|
/* the flash sector store status */
|
||||||
|
enum fdb_sector_store_status {
|
||||||
|
FDB_SECTOR_STORE_UNUSED,
|
||||||
|
FDB_SECTOR_STORE_EMPTY,
|
||||||
|
FDB_SECTOR_STORE_USING,
|
||||||
|
FDB_SECTOR_STORE_FULL,
|
||||||
|
#define FDB_SECTOR_STORE_STATUS_NUM 4
|
||||||
|
};
|
||||||
|
typedef enum fdb_sector_store_status fdb_sector_store_status_t;
|
||||||
|
|
||||||
|
/* the flash sector dirty status */
|
||||||
|
enum fdb_sector_dirty_status {
|
||||||
|
FDB_SECTOR_DIRTY_UNUSED,
|
||||||
|
FDB_SECTOR_DIRTY_FALSE,
|
||||||
|
FDB_SECTOR_DIRTY_TRUE,
|
||||||
|
FDB_SECTOR_DIRTY_GC,
|
||||||
|
#define FDB_SECTOR_DIRTY_STATUS_NUM 4
|
||||||
|
};
|
||||||
|
typedef enum fdb_sector_dirty_status fdb_sector_dirty_status_t;
|
||||||
|
|
||||||
|
/* KVDB section information */
|
||||||
|
struct kvdb_sec_info {
|
||||||
|
bool check_ok; /**< sector header check is OK */
|
||||||
|
struct {
|
||||||
|
fdb_sector_store_status_t store; /**< sector store status @see fdb_sector_store_status_t */
|
||||||
|
fdb_sector_dirty_status_t dirty; /**< sector dirty status @see sector_dirty_status_t */
|
||||||
|
} status;
|
||||||
|
uint32_t addr; /**< sector start address */
|
||||||
|
uint32_t magic; /**< magic word(`E`, `F`, `4`, `0`) */
|
||||||
|
uint32_t combined; /**< the combined next sector number, 0xFFFFFFFF: not combined */
|
||||||
|
size_t remain; /**< remain size */
|
||||||
|
uint32_t empty_kv; /**< the next empty KV node start address */
|
||||||
|
};
|
||||||
|
typedef struct kvdb_sec_info *kv_sec_info_t;
|
||||||
|
|
||||||
|
/* TSDB section information */
|
||||||
|
struct tsdb_sec_info {
|
||||||
|
bool check_ok; /**< sector header check is OK */
|
||||||
|
fdb_sector_store_status_t status; /**< sector store status @see fdb_sector_store_status_t */
|
||||||
|
uint32_t addr; /**< sector start address */
|
||||||
|
uint32_t magic; /**< magic word(`T`, `S`, `L`, `0`) */
|
||||||
|
fdb_time_t start_time; /**< the first start node's timestamp, 0xFFFFFFFF: unused */
|
||||||
|
fdb_time_t end_time; /**< the last end node's timestamp, 0xFFFFFFFF: unused */
|
||||||
|
uint32_t end_idx; /**< the last end node's index, 0xFFFFFFFF: unused */
|
||||||
|
fdb_tsl_status_t end_info_stat[2]; /**< the last end node's info status */
|
||||||
|
size_t remain; /**< remain size */
|
||||||
|
uint32_t empty_idx; /**< the next empty node index address */
|
||||||
|
uint32_t empty_data; /**< the next empty node's data end address */
|
||||||
|
};
|
||||||
|
typedef struct tsdb_sec_info *tsdb_sec_info_t;
|
||||||
|
|
||||||
|
struct kv_cache_node {
|
||||||
|
uint16_t name_crc; /**< KV name's CRC32 low 16bit value */
|
||||||
|
uint16_t active; /**< KV node access active degree */
|
||||||
|
uint32_t addr; /**< KV node address */
|
||||||
|
};
|
||||||
|
typedef struct kv_cache_node *kv_cache_node_t;
|
||||||
|
|
||||||
|
struct sector_cache_node {
|
||||||
|
uint32_t addr; /**< sector start address */
|
||||||
|
uint32_t empty_addr; /**< sector empty address */
|
||||||
|
};
|
||||||
|
typedef struct sector_cache_node *sector_cache_node_t;
|
||||||
|
|
||||||
|
/* database structure */
|
||||||
|
typedef struct fdb_db *fdb_db_t;
|
||||||
|
struct fdb_db {
|
||||||
|
const char *name; /**< database name */
|
||||||
|
fdb_db_type type; /**< database type */
|
||||||
|
union {
|
||||||
|
#ifdef FDB_USING_FAL_MODE
|
||||||
|
const struct fal_partition *part; /**< flash partition for saving database */
|
||||||
|
#endif
|
||||||
|
#ifdef FDB_USING_FILE_MODE
|
||||||
|
const char *dir; /**< directory path for saving database */
|
||||||
|
#endif
|
||||||
|
} storage;
|
||||||
|
uint32_t sec_size; /**< flash section size. It's a multiple of block size */
|
||||||
|
uint32_t max_size; /**< database max size. It's a multiple of section size */
|
||||||
|
bool init_ok; /**< initialized successfully */
|
||||||
|
bool file_mode; /**< is file mode, default is false */
|
||||||
|
bool not_formatable; /**< is can NOT be formated mode, default is false */
|
||||||
|
#ifdef FDB_USING_FILE_MODE
|
||||||
|
#if defined(FDB_USING_FILE_POSIX_MODE)
|
||||||
|
int cur_file; /**< current file object */
|
||||||
|
#elif defined(FDB_USING_FILE_LIBC_MODE)
|
||||||
|
FILE *cur_file; /**< current file object */
|
||||||
|
#endif
|
||||||
|
uint32_t cur_sec; /**< current operate sector address */
|
||||||
|
#endif
|
||||||
|
void (*lock)(fdb_db_t db); /**< lock the database operate */
|
||||||
|
void (*unlock)(fdb_db_t db); /**< unlock the database operate */
|
||||||
|
|
||||||
|
void *user_data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/* KVDB structure */
|
||||||
|
struct fdb_kvdb {
|
||||||
|
struct fdb_db parent; /**< inherit from fdb_db */
|
||||||
|
struct fdb_default_kv default_kvs; /**< default KV */
|
||||||
|
bool gc_request; /**< request a GC check */
|
||||||
|
bool in_recovery_check; /**< is in recovery check status when first reboot */
|
||||||
|
struct fdb_kv cur_kv;
|
||||||
|
struct kvdb_sec_info cur_sector;
|
||||||
|
bool last_is_complete_del;
|
||||||
|
|
||||||
|
#ifdef FDB_KV_USING_CACHE
|
||||||
|
/* KV cache table */
|
||||||
|
struct kv_cache_node kv_cache_table[FDB_KV_CACHE_TABLE_SIZE];
|
||||||
|
/* sector cache table, it caching the sector info which status is current using */
|
||||||
|
struct sector_cache_node sector_cache_table[FDB_SECTOR_CACHE_TABLE_SIZE];
|
||||||
|
#endif /* FDB_KV_USING_CACHE */
|
||||||
|
|
||||||
|
#ifdef FDB_KV_AUTO_UPDATE
|
||||||
|
uint32_t ver_num; /**< setting version number for update */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void *user_data;
|
||||||
|
};
|
||||||
|
typedef struct fdb_kvdb *fdb_kvdb_t;
|
||||||
|
|
||||||
|
/* TSDB structure */
|
||||||
|
struct fdb_tsdb {
|
||||||
|
struct fdb_db parent; /**< inherit from fdb_db */
|
||||||
|
struct tsdb_sec_info cur_sec; /**< current using sector */
|
||||||
|
fdb_time_t last_time; /**< last TSL timestamp */
|
||||||
|
fdb_get_time get_time; /**< the current timestamp get function */
|
||||||
|
size_t max_len; /**< the maximum length of each log */
|
||||||
|
uint32_t oldest_addr; /**< the oldest sector start address */
|
||||||
|
bool rollover; /**< the oldest data will rollover by newest data, default is true */
|
||||||
|
|
||||||
|
void *user_data;
|
||||||
|
};
|
||||||
|
typedef struct fdb_tsdb *fdb_tsdb_t;
|
||||||
|
|
||||||
|
/* blob structure */
|
||||||
|
struct fdb_blob {
|
||||||
|
void *buf; /**< blob data buffer */
|
||||||
|
size_t size; /**< blob data buffer size */
|
||||||
|
struct {
|
||||||
|
uint32_t meta_addr; /**< saved KV or TSL index address */
|
||||||
|
uint32_t addr; /**< blob data saved address */
|
||||||
|
size_t len; /**< blob data saved length */
|
||||||
|
} saved;
|
||||||
|
};
|
||||||
|
typedef struct fdb_blob *fdb_blob_t;
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _FDB_DEF_H_ */
|
||||||
|
|
|
@ -0,0 +1,221 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2020, Armink, <armink.ztl@gmail.com>
|
||||||
|
* Copyright (c) 2020, enkiller, <462747508@qq.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <flashdb.h>
|
||||||
|
#include <fdb_low_lvl.h>
|
||||||
|
|
||||||
|
#define FDB_LOG_TAG "[file]"
|
||||||
|
|
||||||
|
#ifdef FDB_USING_FILE_MODE
|
||||||
|
|
||||||
|
#define DB_PATH_MAX 256
|
||||||
|
|
||||||
|
static void get_db_file_path(fdb_db_t db, uint32_t addr, char *path, size_t size)
|
||||||
|
{
|
||||||
|
#define DB_NAME_MAX 8
|
||||||
|
|
||||||
|
/* from db_name.fdb.0 to db_name.fdb.n */
|
||||||
|
char file_name[DB_NAME_MAX + 4 + 10];
|
||||||
|
uint32_t sec_addr = FDB_ALIGN_DOWN(addr, db->sec_size);
|
||||||
|
int index = sec_addr / db->sec_size;
|
||||||
|
|
||||||
|
snprintf(file_name, sizeof(file_name), "%.*s.fdb.%d", DB_NAME_MAX, db->name, index);
|
||||||
|
if (strlen(db->storage.dir) + 1 + strlen(file_name) >= size) {
|
||||||
|
/* path is too long */
|
||||||
|
FDB_ASSERT(0)
|
||||||
|
}
|
||||||
|
snprintf(path, size, "%s/%s", db->storage.dir, file_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if defined(FDB_USING_FILE_POSIX_MODE)
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#if !defined(_MSC_VER)
|
||||||
|
#include <unistd.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int open_db_file(fdb_db_t db, uint32_t addr, bool clean)
|
||||||
|
{
|
||||||
|
uint32_t sec_addr = FDB_ALIGN_DOWN(addr, db->sec_size);
|
||||||
|
int fd = db->cur_file;
|
||||||
|
char path[DB_PATH_MAX];
|
||||||
|
|
||||||
|
if (sec_addr != db->cur_sec || fd <= 0 || clean) {
|
||||||
|
get_db_file_path(db, addr, path, DB_PATH_MAX);
|
||||||
|
|
||||||
|
if (fd > 0) {
|
||||||
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
|
}
|
||||||
|
if (clean) {
|
||||||
|
/* clean the old file */
|
||||||
|
fd = open(path, O_RDWR | O_CREAT | O_TRUNC, 0777);
|
||||||
|
if (fd <= 0) {
|
||||||
|
FDB_INFO("Error: open (%s) file failed.\n", path);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* open the database file */
|
||||||
|
fd = open(path, O_RDWR, 0777);
|
||||||
|
db->cur_sec = sec_addr;
|
||||||
|
}
|
||||||
|
db->cur_file = fd;
|
||||||
|
|
||||||
|
return db->cur_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
fdb_err_t _fdb_file_read(fdb_db_t db, uint32_t addr, void *buf, size_t size)
|
||||||
|
{
|
||||||
|
fdb_err_t result = FDB_NO_ERR;
|
||||||
|
int fd = open_db_file(db, addr, false);
|
||||||
|
if (fd > 0) {
|
||||||
|
addr = addr % db->sec_size;
|
||||||
|
lseek(fd, addr, SEEK_SET);
|
||||||
|
read(fd, buf, size);
|
||||||
|
} else {
|
||||||
|
result = FDB_READ_ERR;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fdb_err_t _fdb_file_write(fdb_db_t db, uint32_t addr, const void *buf, size_t size, bool sync)
|
||||||
|
{
|
||||||
|
fdb_err_t result = FDB_NO_ERR;
|
||||||
|
int fd = open_db_file(db, addr, false);
|
||||||
|
if (fd > 0) {
|
||||||
|
addr = addr % db->sec_size;
|
||||||
|
lseek(fd, addr, SEEK_SET);
|
||||||
|
write(fd, buf, size);
|
||||||
|
if(sync) {
|
||||||
|
fsync(fd);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = FDB_READ_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fdb_err_t _fdb_file_erase(fdb_db_t db, uint32_t addr, size_t size)
|
||||||
|
{
|
||||||
|
fdb_err_t result = FDB_NO_ERR;
|
||||||
|
int fd = open_db_file(db, addr, true);
|
||||||
|
if (fd > 0) {
|
||||||
|
#define BUF_SIZE 32
|
||||||
|
uint8_t buf[BUF_SIZE];
|
||||||
|
size_t i;
|
||||||
|
lseek(fd, 0, SEEK_SET);
|
||||||
|
for (i = 0; i * BUF_SIZE < size; i++)
|
||||||
|
{
|
||||||
|
memset(buf, 0xFF, BUF_SIZE);
|
||||||
|
write(fd, buf, BUF_SIZE);
|
||||||
|
}
|
||||||
|
memset(buf, 0xFF, BUF_SIZE);
|
||||||
|
write(fd, buf, size - i * BUF_SIZE);
|
||||||
|
fsync(fd);
|
||||||
|
} else {
|
||||||
|
result = FDB_ERASE_ERR;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#elif defined(FDB_USING_FILE_LIBC_MODE)
|
||||||
|
static FILE *open_db_file(fdb_db_t db, uint32_t addr, bool clean)
|
||||||
|
{
|
||||||
|
uint32_t sec_addr = FDB_ALIGN_DOWN(addr, db->sec_size);
|
||||||
|
|
||||||
|
if (sec_addr != db->cur_sec || db->cur_file == NULL || clean) {
|
||||||
|
char path[DB_PATH_MAX];
|
||||||
|
|
||||||
|
get_db_file_path(db, addr, path, DB_PATH_MAX);
|
||||||
|
|
||||||
|
if (db->cur_file) {
|
||||||
|
fclose(db->cur_file);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clean) {
|
||||||
|
/* clean the old file */
|
||||||
|
db->cur_file = fopen(path, "wb+");
|
||||||
|
if (db->cur_file == NULL) {
|
||||||
|
FDB_INFO("Error: open (%s) file failed.\n", path);
|
||||||
|
} else {
|
||||||
|
fclose(db->cur_file);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* open the database file */
|
||||||
|
db->cur_file = fopen(path, "rb+");
|
||||||
|
db->cur_sec = sec_addr;
|
||||||
|
}
|
||||||
|
|
||||||
|
return db->cur_file;
|
||||||
|
}
|
||||||
|
|
||||||
|
fdb_err_t _fdb_file_read(fdb_db_t db, uint32_t addr, void *buf, size_t size)
|
||||||
|
{
|
||||||
|
fdb_err_t result = FDB_NO_ERR;
|
||||||
|
FILE *fp = open_db_file(db, addr, false);
|
||||||
|
if (fp) {
|
||||||
|
addr = addr % db->sec_size;
|
||||||
|
fseek(fp, addr, SEEK_SET);
|
||||||
|
fread(buf, size, 1, fp);
|
||||||
|
} else {
|
||||||
|
result = FDB_READ_ERR;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fdb_err_t _fdb_file_write(fdb_db_t db, uint32_t addr, const void *buf, size_t size, bool sync)
|
||||||
|
{
|
||||||
|
fdb_err_t result = FDB_NO_ERR;
|
||||||
|
FILE *fp = open_db_file(db, addr, false);
|
||||||
|
if (fp) {
|
||||||
|
addr = addr % db->sec_size;
|
||||||
|
fseek(fp, addr, SEEK_SET);
|
||||||
|
fwrite(buf, size, 1, fp);
|
||||||
|
if(sync) {
|
||||||
|
fflush(fp);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = FDB_READ_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
fdb_err_t _fdb_file_erase(fdb_db_t db, uint32_t addr, size_t size)
|
||||||
|
{
|
||||||
|
fdb_err_t result = FDB_NO_ERR;
|
||||||
|
|
||||||
|
FILE *fp = open_db_file(db, addr, true);
|
||||||
|
if (fp != NULL) {
|
||||||
|
#define BUF_SIZE 32
|
||||||
|
uint8_t buf[BUF_SIZE];
|
||||||
|
size_t i;
|
||||||
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
for (i = 0; i * BUF_SIZE < size; i++)
|
||||||
|
{
|
||||||
|
memset(buf, 0xFF, BUF_SIZE);
|
||||||
|
fwrite(buf, BUF_SIZE, 1, fp);
|
||||||
|
}
|
||||||
|
memset(buf, 0xFF, BUF_SIZE);
|
||||||
|
fwrite(buf, size - i * BUF_SIZE, 1, fp);
|
||||||
|
fflush(fp);
|
||||||
|
} else {
|
||||||
|
result = FDB_ERASE_ERR;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
#endif /* defined(FDB_USING_FILE_LIBC_MODE) */
|
||||||
|
|
||||||
|
#endif /* FDB_USING_FILE_MODE */
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue