Compare commits
No commits in common. "master" and "prepare_for_master" have entirely different histories.
master
...
prepare_fo
|
|
@ -0,0 +1,5 @@
|
|||
*.vscode
|
||||
*.o
|
||||
*libmusl.a
|
||||
*liblwip.a
|
||||
.DS_Store
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
[submodule "Ubiquitous/RT-Thread_Fusion_XiUOS/rt-thread"]
|
||||
path = Ubiquitous/RT-Thread_Fusion_XiUOS/rt-thread
|
||||
url = https://code.gitlink.org.cn/chunyexixiaoyu/rt-thread.git
|
||||
[submodule "Ubiquitous/RT-Thread_Fusion_XiUOS/aiit_board/k210/kendryte-sdk/kendryte-sdk-source"]
|
||||
path = Ubiquitous/RT-Thread_Fusion_XiUOS/aiit_board/k210/kendryte-sdk/kendryte-sdk-source
|
||||
url = https://code.gitlink.org.cn/chunyexixiaoyu/kendryte-sdk-source.git
|
||||
[submodule "Ubiquitous/RT-Thread_Fusion_XiUOS/aiit_board/aiit-riscv64-board/kendryte-sdk/kendryte-sdk-source"]
|
||||
path = Ubiquitous/RT-Thread_Fusion_XiUOS/aiit_board/aiit-riscv64-board/kendryte-sdk/kendryte-sdk-source
|
||||
url = https://code.gitlink.org.cn/chunyexixiaoyu/kendryte-sdk-source.git
|
||||
[submodule "Ubiquitous/XiZi/fs/lwext4/lwext4_submodule"]
|
||||
path = Ubiquitous/XiZi/fs/lwext4/lwext4_submodule
|
||||
url = https://gitlink.org.cn/xuos/lwext4_filesystem_support_XiUOS.git
|
||||
[submodule "Ubiquitous/Nuttx_Fusion_XiUOS/nuttx"]
|
||||
path = Ubiquitous/Nuttx_Fusion_XiUOS/nuttx
|
||||
url = https://code.gitlink.org.cn/wgzAIIT/incubator-nuttx.git
|
||||
[submodule "Ubiquitous/Nuttx_Fusion_XiUOS/apps"]
|
||||
path = Ubiquitous/Nuttx_Fusion_XiUOS/apps
|
||||
url = https://code.gitlink.org.cn/wgzAIIT/incubator-nuttx-apps.git
|
||||
[submodule "APP_Framework/Applications/webnet/WebNet_XiUOS"]
|
||||
path = APP_Framework/Applications/webnet/WebNet_XiUOS
|
||||
url = https://gitlink.org.cn/xuos/WebNet_XiUOS.git
|
||||
[submodule "Ubiquitous/RT-Thread_Fusion_XiUOS/aiit_board/xidatong-riscv64/kendryte-sdk/kendryte-sdk-source"]
|
||||
path = Ubiquitous/RT-Thread_Fusion_XiUOS/aiit_board/xidatong-riscv64/kendryte-sdk/kendryte-sdk-source
|
||||
url = https://code.gitlink.org.cn/chunyexixiaoyu/kendryte-sdk-source.git
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
menu "Applications"
|
||||
|
||||
menu "config stack size and priority of main task"
|
||||
config MAIN_KTASK_STACK_SIZE
|
||||
int "Set main task stack size"
|
||||
default 1024
|
||||
config MAIN_KTASK_PRIORITY
|
||||
int
|
||||
default 4 if KTASK_PRIORITY_8
|
||||
default 16 if KTASK_PRIORITY_32
|
||||
default 85 if KTASK_PRIORITY_256
|
||||
endmenu
|
||||
|
||||
source "$APP_DIR/Applications/ota/Kconfig"
|
||||
|
||||
source "$APP_DIR/Applications/app_test/Kconfig"
|
||||
source "$APP_DIR/Applications/connection_app/Kconfig"
|
||||
source "$APP_DIR/Applications/control_app/Kconfig"
|
||||
source "$APP_DIR/Applications/knowing_app/Kconfig"
|
||||
source "$APP_DIR/Applications/sensor_app/Kconfig"
|
||||
source "$APP_DIR/Applications/embedded_database_app/Kconfig"
|
||||
source "$APP_DIR/Applications/webnet/Kconfig"
|
||||
endmenu
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
############################################################################
|
||||
# APP_Framework/Applications/Make.defs
|
||||
############################################################################
|
||||
CONFIGURED_APPS += $(APPDIR)/../../../APP_Framework/Applications
|
||||
CONFIGURED_APPS += $(APPDIR)/../../../APP_Framework/Applications/general_functions/list
|
||||
|
||||
include $(wildcard $(APPDIR)/../../../APP_Framework/Applications/*/Make.defs)
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
include $(KERNEL_ROOT)/.config
|
||||
|
||||
ifeq ($(CONFIG_ADD_NUTTX_FETURES),y)
|
||||
include $(APPDIR)/Make.defs
|
||||
CSRCS += framework_init.c
|
||||
include $(APPDIR)/Application.mk
|
||||
endif
|
||||
|
||||
|
||||
ifeq ($(CONFIG_ADD_XIZI_FETURES),y)
|
||||
SRC_DIR := general_functions app_test
|
||||
|
||||
SRC_FILES := main.c framework_init.c
|
||||
ifeq ($(CONFIG_LIB_LV),y)
|
||||
SRC_DIR += lv_app
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_APPLICATION_OTA),y)
|
||||
SRC_DIR += ota
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_APPLICATION_SENSOR),y)
|
||||
SRC_DIR += sensor_app
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_APPLICATION_CONNECTION),y)
|
||||
SRC_DIR += connection_app
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_APPLICATION_KNOWING),y)
|
||||
SRC_DIR += knowing_app
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_APPLICATION_CONTROL),y)
|
||||
SRC_DIR += control_app
|
||||
endif
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
endif
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
import os
|
||||
Import('RTT_ROOT')
|
||||
Import('rtconfig')
|
||||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
|
||||
SOURCES = ['framework_init.c']
|
||||
path = [cwd]
|
||||
objs = []
|
||||
group = DefineGroup('sensor', SOURCES, depend = [], CPPPATH = [cwd])
|
||||
objs = objs + group
|
||||
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,33 @@
|
|||
menu "test app"
|
||||
menuconfig USER_TEST
|
||||
bool "Enable application test function "
|
||||
default n
|
||||
|
||||
if USER_TEST
|
||||
config USER_TEST_SPI_FLASH
|
||||
bool "Config test spi flash"
|
||||
default n
|
||||
|
||||
menuconfig USER_TEST_ADC
|
||||
bool "Config test adc"
|
||||
default n
|
||||
if USER_TEST_ADC
|
||||
if ADD_XIZI_FETURES
|
||||
config ADC_DEV_DRIVER
|
||||
string "Set ADC dev path"
|
||||
default "/dev/adc1_dev"
|
||||
endif
|
||||
endif
|
||||
|
||||
menuconfig USER_TEST_DAC
|
||||
bool "Config test dac"
|
||||
default n
|
||||
if USER_TEST_DAC
|
||||
if ADD_XIZI_FETURES
|
||||
config DAC_DEV_DRIVER
|
||||
string "Set DAC dev path"
|
||||
default "/dev/dac_dev"
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
endmenu
|
||||
|
|
@ -0,0 +1,15 @@
|
|||
SRC_FILES :=
|
||||
|
||||
ifeq ($(CONFIG_USER_TEST_SPI_FLASH),y)
|
||||
SRC_FILES += test_spi_flash.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_USER_TEST_ADC),y)
|
||||
SRC_FILES += test_adc.c
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_USER_TEST_DAC),y)
|
||||
SRC_FILES += test_dac.c
|
||||
endif
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* 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: test_adc.c
|
||||
* @brief: a application of adc function
|
||||
* @version: 1.1
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2022/1/7
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <transform.h>
|
||||
|
||||
void test_adc()
|
||||
{
|
||||
int adc_fd;
|
||||
uint8 adc_channel = 0x0;
|
||||
uint16 adc_sample, adc_value_decimal = 0;
|
||||
float adc_value;
|
||||
|
||||
adc_fd = PrivOpen(ADC_DEV_DRIVER, O_RDWR);
|
||||
if (adc_fd < 0) {
|
||||
printf("open adc fd error %d\n", adc_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
struct PrivIoctlCfg ioctl_cfg;
|
||||
ioctl_cfg.ioctl_driver_type = ADC_TYPE;
|
||||
ioctl_cfg.args = &adc_channel;
|
||||
if (0 != PrivIoctl(adc_fd, OPE_CFG, &ioctl_cfg)) {
|
||||
printf("ioctl adc fd error %d\n", adc_fd);
|
||||
PrivClose(adc_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
PrivRead(adc_fd, &adc_sample, 2);
|
||||
|
||||
adc_value = (float)adc_sample * (3.3 / 4096);
|
||||
|
||||
adc_value_decimal = (adc_value - (uint16)adc_value) * 1000;
|
||||
|
||||
printf("adc sample %u value integer %u decimal %u\n", adc_sample, (uint16)adc_value, adc_value_decimal);
|
||||
|
||||
PrivClose(adc_fd);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN),
|
||||
adc, test_adc, read 3.3 voltage data from adc);
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
/*
|
||||
* 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: test_dac.c
|
||||
* @brief: a application of dac function
|
||||
* @version: 2.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2022/1/11
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <transform.h>
|
||||
|
||||
void test_dac()
|
||||
{
|
||||
int dac_fd;
|
||||
uint16 dac_set_value = 800;
|
||||
uint16 dac_sample, dac_value_decimal = 0;
|
||||
float dac_value;
|
||||
|
||||
dac_fd = PrivOpen(DAC_DEV_DRIVER, O_RDWR);
|
||||
if (dac_fd < 0) {
|
||||
KPrintf("open dac fd error %d\n", dac_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
struct PrivIoctlCfg ioctl_cfg;
|
||||
ioctl_cfg.ioctl_driver_type = DAC_TYPE;
|
||||
ioctl_cfg.args = &dac_set_value;
|
||||
if (0 != PrivIoctl(dac_fd, OPE_CFG, &ioctl_cfg)) {
|
||||
KPrintf("ioctl dac fd error %d\n", dac_fd);
|
||||
PrivClose(dac_fd);
|
||||
return;
|
||||
}
|
||||
|
||||
PrivRead(dac_fd, &dac_sample, 2);
|
||||
|
||||
dac_value = (float)dac_sample * (3.3 / 4096);//Vref+ need to be 3.3V
|
||||
|
||||
dac_value_decimal = (dac_value - (uint16)dac_value) * 1000;
|
||||
|
||||
printf("dac sample %u value integer %u decimal %u\n", dac_sample, (uint16)dac_value, dac_value_decimal);
|
||||
|
||||
PrivClose(dac_fd);
|
||||
|
||||
return;
|
||||
}
|
||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN),
|
||||
test_dac, test_dac, set digital data to dac);
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
/*
|
||||
* Copyright (c) 2006-2021, RT-Thread Development Team
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Change Logs:
|
||||
* Date Author Notes
|
||||
* 2016-09-28 armink first version.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @file test_spi_flash.c
|
||||
* @brief support to test spi flash function
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021-05-17
|
||||
*/
|
||||
|
||||
/*************************************************
|
||||
File name: test_spi_flash.c
|
||||
Description: support spi flash function test
|
||||
Others: add spi flash test cmd from SFUD/blob/master/demo/stm32f2xx_rtt/RT-Thread-2.1.0/components/drivers/spi/spi_flash_sfud.c
|
||||
https://github.com/armink/SFUD/
|
||||
History:
|
||||
1. Date: 2021-05-17
|
||||
Author: AIIT XUOS Lab
|
||||
Modification:
|
||||
1. support spi flash open, read and write function
|
||||
*************************************************/
|
||||
|
||||
#include <xizi.h>
|
||||
#include <device.h>
|
||||
#include <flash_spi.h>
|
||||
#include <user_api.h>
|
||||
|
||||
#define SPI_FLASH_PATH "/dev/spi1_W25Q64"
|
||||
#define FlashDataPrint(ch) ((unsigned int)((ch) - ' ') < 127u - ' ')
|
||||
|
||||
static int spi_flash_fd;
|
||||
|
||||
void FlashOpen(void)
|
||||
{
|
||||
x_err_t ret = EOK;
|
||||
|
||||
spi_flash_fd = open(SPI_FLASH_PATH, O_RDWR);
|
||||
if (spi_flash_fd < 0) {
|
||||
KPrintf("open spi flash fd error %d\n", spi_flash_fd);
|
||||
}
|
||||
|
||||
KPrintf("Spi Flash init succeed\n");
|
||||
|
||||
return;
|
||||
}
|
||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN),
|
||||
FlashOpen, FlashOpen, open spi flash device);
|
||||
|
||||
void FlashRead(int argc, char *argv[])
|
||||
{
|
||||
x_size_t i, j = 0;
|
||||
uint32 addr;
|
||||
uint32 size;
|
||||
uint8 data[16];
|
||||
|
||||
struct BusBlockReadParam read_param;
|
||||
memset(&read_param, 0, sizeof(struct BusBlockReadParam));
|
||||
|
||||
memset(data, 0, 16);
|
||||
|
||||
if (3 != argc) {
|
||||
KPrintf("FlashRead cmd format: FlashRead addr size.\n");
|
||||
return;
|
||||
} else {
|
||||
addr = strtol(argv[1], NULL, 0);
|
||||
size = strtol(argv[2], NULL, 0);
|
||||
|
||||
read_param.buffer = data;
|
||||
read_param.pos = addr;
|
||||
read_param.size = size;
|
||||
|
||||
if (read_param.buffer) {
|
||||
read(spi_flash_fd, &read_param, size);
|
||||
if (size == read_param.read_length) {
|
||||
KPrintf("Read the %s flash data success. Start from 0x%08X, size is %ld. The data is:\n",
|
||||
SPI_FLASH_PATH, addr, size);
|
||||
KPrintf("Offset (h) 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\n");
|
||||
for (i = 0; i < size; i += 16) {
|
||||
KPrintf("[%08X] ", addr + i);
|
||||
/* dump hex */
|
||||
for (j = 0; j < 16; j++) {
|
||||
if (i + j < size) {
|
||||
KPrintf("%02X ", data[i + j]);
|
||||
} else {
|
||||
KPrintf(" ");
|
||||
}
|
||||
}
|
||||
/* dump char for hex */
|
||||
for (j = 0; j < 16; j++) {
|
||||
if (i + j < size) {
|
||||
KPrintf("%c", FlashDataPrint(data[i + j]) ? data[i + j] : '.');
|
||||
}
|
||||
}
|
||||
KPrintf("\n");
|
||||
}
|
||||
KPrintf("\n");
|
||||
}
|
||||
} else {
|
||||
KPrintf("SpiFlashRead alloc read buffer failed!\n");
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN),
|
||||
FlashRead, FlashRead, read data from spi flash device);
|
||||
|
||||
void FlashWrite(int argc, char *argv[])
|
||||
{
|
||||
x_err_t ret = EOK;
|
||||
x_size_t i, j = 0;
|
||||
uint32 addr;
|
||||
uint32 size;
|
||||
uint8 data[16];
|
||||
|
||||
struct BusBlockWriteParam write_param;
|
||||
memset(&write_param, 0, sizeof(struct BusBlockWriteParam));
|
||||
|
||||
memset(data, 0, 16);
|
||||
|
||||
if (argc < 3) {
|
||||
KPrintf("FlashWrite cmd format: FlashWrite addr data.\n");
|
||||
return;
|
||||
} else {
|
||||
addr = strtol(argv[1], NULL, 0);
|
||||
size = argc - 2;
|
||||
|
||||
write_param.buffer = data;
|
||||
write_param.pos = addr;
|
||||
write_param.size = size;
|
||||
|
||||
if (data) {
|
||||
for (i = 0; i < size; i++) {
|
||||
data[i] = strtol(argv[2 + i], NULL, 0);
|
||||
}
|
||||
|
||||
ret = write(spi_flash_fd, &write_param, size);
|
||||
if (EOK == ret) {
|
||||
KPrintf("Write the %s flash data success. Start from 0x%08X, size is %ld.\n",
|
||||
SPI_FLASH_PATH, addr, size);
|
||||
KPrintf("Write data: ");
|
||||
for (i = 0; i < size; i++) {
|
||||
KPrintf("%d ", data[i]);
|
||||
}
|
||||
KPrintf(".\n");
|
||||
}
|
||||
} else {
|
||||
KPrintf("SpiFlashWrite alloc write buffer failed!\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN),
|
||||
FlashWrite, FlashWrite, write data to spi flash device);
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
menu "connection app"
|
||||
|
||||
menuconfig APPLICATION_CONNECTION
|
||||
bool "Using connection apps"
|
||||
default n
|
||||
|
||||
endmenu
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
SRC_DIR :=
|
||||
|
||||
ifeq ($(CONFIG_RESOURCES_LWIP),y)
|
||||
SRC_DIR += socket_demo
|
||||
endif
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
SRC_FILES := lwip_tcp_socket_demo.c lwip_udp_socket_demo.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
|
@ -0,0 +1,186 @@
|
|||
/*
|
||||
* 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 lwip_tcp_socket_demo.c
|
||||
* @brief TCP socket demo based on LwIP
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2022-03-21
|
||||
*/
|
||||
|
||||
#include <transform.h>
|
||||
#include "sys_arch.h"
|
||||
#include <lwip/sockets.h>
|
||||
#include "lwip/sys.h"
|
||||
|
||||
#define TCP_DEMO_BUF_SIZE 65535
|
||||
|
||||
char tcp_socket_ip[] = {192, 168, 250, 252};
|
||||
u16_t tcp_socket_port = LWIP_TARGET_PORT;
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
static void TCPSocketRecvTask(void *arg)
|
||||
{
|
||||
int fd = -1, clientfd;
|
||||
int recv_len;
|
||||
char *recv_buf;
|
||||
struct sockaddr_in tcp_addr;
|
||||
socklen_t addr_len;
|
||||
|
||||
while(1)
|
||||
{
|
||||
recv_buf = (char *)malloc(TCP_DEMO_BUF_SIZE);
|
||||
if (recv_buf == NULL)
|
||||
{
|
||||
lw_error("No memory\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fd < 0)
|
||||
{
|
||||
lw_error("Socket error\n");
|
||||
free(recv_buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
tcp_addr.sin_family = AF_INET;
|
||||
tcp_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
tcp_addr.sin_port = htons(tcp_socket_port);
|
||||
memset(&(tcp_addr.sin_zero), 0, sizeof(tcp_addr.sin_zero));
|
||||
|
||||
if (bind(fd, (struct sockaddr *)&tcp_addr, sizeof(struct sockaddr)) == -1)
|
||||
{
|
||||
lw_error("Unable to bind\n");
|
||||
closesocket(fd);
|
||||
free(recv_buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
lw_print("tcp bind success, start to receive.\n");
|
||||
lw_notice("\n\nLocal Port:%d\n\n", tcp_socket_port);
|
||||
|
||||
// setup socket fd as listening mode
|
||||
if (listen(fd, 5) != 0 )
|
||||
{
|
||||
lw_error("Unable to listen\n");
|
||||
closesocket(fd);
|
||||
free(recv_buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
// accept client connection
|
||||
clientfd = accept(fd, (struct sockaddr *)&tcp_addr, (socklen_t*)&addr_len);
|
||||
lw_notice("client %s connected\n", inet_ntoa(tcp_addr.sin_addr));
|
||||
|
||||
while(1)
|
||||
{
|
||||
memset(recv_buf, 0, TCP_DEMO_BUF_SIZE);
|
||||
recv_len = recvfrom(clientfd, recv_buf, TCP_DEMO_BUF_SIZE, 0, (struct sockaddr *)&tcp_addr, &addr_len);
|
||||
if(recv_len > 0)
|
||||
{
|
||||
lw_notice("Receive from : %s\n", inet_ntoa(tcp_addr.sin_addr));
|
||||
lw_notice("Receive data : %d - %s\n\n", recv_len, recv_buf);
|
||||
}
|
||||
sendto(clientfd, recv_buf, recv_len, 0, (struct sockaddr*)&tcp_addr, addr_len);
|
||||
}
|
||||
}
|
||||
|
||||
closesocket(fd);
|
||||
free(recv_buf);
|
||||
}
|
||||
|
||||
void TCPSocketRecvTest(int argc, char *argv[])
|
||||
{
|
||||
int result = 0;
|
||||
|
||||
if(argc >= 2)
|
||||
{
|
||||
lw_print("lw: [%s] target ip %s\n", __func__, argv[1]);
|
||||
if(sscanf(argv[1], "%d.%d.%d.%d:%d", &tcp_socket_ip[0], &tcp_socket_ip[1], &tcp_socket_ip[2], &tcp_socket_ip[3], &tcp_socket_port) == EOK)
|
||||
{
|
||||
sscanf(argv[1], "%d.%d.%d.%d", &tcp_socket_ip[0], &tcp_socket_ip[1], &tcp_socket_ip[2], &tcp_socket_ip[3]);
|
||||
}
|
||||
}
|
||||
|
||||
lwip_config_tcp(lwip_ipaddr, lwip_netmask, tcp_socket_ip);
|
||||
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),
|
||||
TCPSocketRecv, TCPSocketRecvTest, TCP recv echo);
|
||||
|
||||
static void TCPSocketSendTask(void *arg)
|
||||
{
|
||||
int cnt = LWIP_DEMO_TIMES;
|
||||
int fd = -1;
|
||||
char send_msg[128];
|
||||
|
||||
lw_print("%s start\n", __func__);
|
||||
|
||||
memset(send_msg, 0, sizeof(send_msg));
|
||||
fd = socket(AF_INET, SOCK_STREAM, 0);
|
||||
if (fd < 0)
|
||||
{
|
||||
lw_print("Socket error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
struct sockaddr_in tcp_sock;
|
||||
tcp_sock.sin_family = AF_INET;
|
||||
tcp_sock.sin_port = htons(tcp_socket_port);
|
||||
tcp_sock.sin_addr.s_addr = PP_HTONL(LWIP_MAKEU32(tcp_socket_ip[0], tcp_socket_ip[1], tcp_socket_ip[2], tcp_socket_ip[3]));
|
||||
memset(&(tcp_sock.sin_zero), 0, sizeof(tcp_sock.sin_zero));
|
||||
|
||||
if (connect(fd, (struct sockaddr *)&tcp_sock, sizeof(struct sockaddr)))
|
||||
{
|
||||
lw_print("Unable to connect\n");
|
||||
closesocket(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
lw_notice("\n\nTarget Port:%d\n\n", tcp_socket_port);
|
||||
|
||||
while (cnt --)
|
||||
{
|
||||
lw_print("Lwip client is running.\n");
|
||||
snprintf(send_msg, sizeof(send_msg), "TCP test package times %d\r\n", cnt);
|
||||
sendto(fd, send_msg, strlen(send_msg), 0, (struct sockaddr*)&tcp_sock, sizeof(struct sockaddr));
|
||||
lw_notice("Send tcp msg: %s ", send_msg);
|
||||
MdelayKTask(1000);
|
||||
}
|
||||
|
||||
closesocket(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
void TCPSocketSendTest(int argc, char *argv[])
|
||||
{
|
||||
if(argc >= 2)
|
||||
{
|
||||
lw_print("lw: [%s] target ip %s\n", __func__, argv[1]);
|
||||
if(sscanf(argv[1], "%d.%d.%d.%d:%d", &tcp_socket_ip[0], &tcp_socket_ip[1], &tcp_socket_ip[2], &tcp_socket_ip[3], &tcp_socket_port) == EOK)
|
||||
{
|
||||
sscanf(argv[1], "%d.%d.%d.%d", &tcp_socket_ip[0], &tcp_socket_ip[1], &tcp_socket_ip[2], &tcp_socket_ip[3]);
|
||||
}
|
||||
}
|
||||
|
||||
lwip_config_tcp(lwip_ipaddr, lwip_netmask, tcp_socket_ip);
|
||||
sys_thread_new("TCP Socket Send", 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),
|
||||
TCPSocketSend, TCPSocketSendTest, TCP send demo);
|
||||
|
||||
|
|
@ -0,0 +1,167 @@
|
|||
/*
|
||||
* 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 lwip_udp_socket_demo.c
|
||||
* @brief UDP demo based on LwIP
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2022-03-21
|
||||
*/
|
||||
#include <transform.h>
|
||||
#include "sys_arch.h"
|
||||
#include "lwip/sockets.h"
|
||||
|
||||
#define UDP_BUF_SIZE 65536
|
||||
|
||||
char udp_socket_ip[] = {192, 168, 250, 252};
|
||||
u16_t udp_socket_port = LWIP_LOCAL_PORT;
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void UdpSocketRecvTask(void *arg)
|
||||
{
|
||||
int fd = -1;
|
||||
char *recv_buf;
|
||||
struct sockaddr_in udp_addr, server_addr;
|
||||
int recv_len;
|
||||
socklen_t addr_len;
|
||||
|
||||
while(1)
|
||||
{
|
||||
recv_buf = (char *)malloc(UDP_BUF_SIZE);
|
||||
if(recv_buf == NULL)
|
||||
{
|
||||
lw_error("No memory\n");
|
||||
continue;
|
||||
}
|
||||
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if(fd < 0)
|
||||
{
|
||||
lw_error("Socket error\n");
|
||||
free(recv_buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
udp_addr.sin_family = AF_INET;
|
||||
udp_addr.sin_addr.s_addr = INADDR_ANY;
|
||||
udp_addr.sin_port = htons(udp_socket_port);
|
||||
memset(&(udp_addr.sin_zero), 0, sizeof(udp_addr.sin_zero));
|
||||
|
||||
if(bind(fd, (struct sockaddr *)&udp_addr, sizeof(struct sockaddr)) == -1)
|
||||
{
|
||||
lw_error("Unable to bind\n");
|
||||
closesocket(fd);
|
||||
free(recv_buf);
|
||||
continue;
|
||||
}
|
||||
|
||||
lw_notice("UDP bind sucess, start to receive.\n");
|
||||
lw_notice("\n\nLocal Port:%d\n\n", udp_socket_port);
|
||||
|
||||
while(1)
|
||||
{
|
||||
memset(recv_buf, 0, UDP_BUF_SIZE);
|
||||
recv_len = recvfrom(fd, recv_buf, UDP_BUF_SIZE, 0, (struct sockaddr *)&server_addr, &addr_len);
|
||||
if(recv_len > 0)
|
||||
{
|
||||
lw_notice("Receive from : %s\n", inet_ntoa(server_addr.sin_addr));
|
||||
lw_notice("Receive data : %s\n\n", recv_buf);
|
||||
}
|
||||
sendto(fd, recv_buf, recv_len, 0, (struct sockaddr*)&server_addr, addr_len);
|
||||
}
|
||||
|
||||
closesocket(fd);
|
||||
free(recv_buf);
|
||||
}
|
||||
}
|
||||
|
||||
void UdpSocketRecvTest(int argc, char *argv[])
|
||||
{
|
||||
if(argc >= 2)
|
||||
{
|
||||
lw_notice("lw: [%s] target ip %s\n", __func__, argv[1]);
|
||||
if(sscanf(argv[1], "%d.%d.%d.%d:%d", &udp_socket_ip[0], &udp_socket_ip[1], &udp_socket_ip[2], &udp_socket_ip[3], &udp_socket_port) == EOK)
|
||||
{
|
||||
sscanf(argv[1], "%d.%d.%d.%d", &udp_socket_ip[0], &udp_socket_ip[1], &udp_socket_ip[2], &udp_socket_ip[3]);
|
||||
}
|
||||
}
|
||||
|
||||
lwip_config_tcp(lwip_ipaddr, lwip_netmask, udp_socket_ip);
|
||||
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),
|
||||
UDPSocketRecv, UdpSocketRecvTest, UDP Receive DEMO);
|
||||
|
||||
static void UdpSocketSendTask(void *arg)
|
||||
{
|
||||
int cnt = LWIP_DEMO_TIMES;
|
||||
char send_str[128];
|
||||
int fd = -1;
|
||||
|
||||
memset(send_str, 0, sizeof(send_str));
|
||||
|
||||
fd = socket(AF_INET, SOCK_DGRAM, 0);
|
||||
if(fd < 0)
|
||||
{
|
||||
lw_error("Socket error\n");
|
||||
return;
|
||||
}
|
||||
|
||||
struct sockaddr_in udp_sock;
|
||||
udp_sock.sin_family = AF_INET;
|
||||
udp_sock.sin_port = htons(udp_socket_port);
|
||||
udp_sock.sin_addr.s_addr = PP_HTONL(LWIP_MAKEU32(udp_socket_ip[0], udp_socket_ip[1], udp_socket_ip[2], udp_socket_ip[3]));
|
||||
memset(&(udp_sock.sin_zero), 0, sizeof(udp_sock.sin_zero));
|
||||
|
||||
if(connect(fd, (struct sockaddr *)&udp_sock, sizeof(struct sockaddr)))
|
||||
{
|
||||
lw_error("Unable to connect\n");
|
||||
closesocket(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
lw_print("UDP connect success, start to send.\n");
|
||||
lw_notice("\n\nTarget Port:%d\n\n", udp_sock.sin_port);
|
||||
|
||||
while (cnt --)
|
||||
{
|
||||
snprintf(send_str, sizeof(send_str), "UDP test package times %d\r\n", cnt);
|
||||
sendto(fd, send_str, strlen(send_str), 0, (struct sockaddr*)&udp_sock, sizeof(struct sockaddr));
|
||||
lw_notice("Send UDP msg: %s ", send_str);
|
||||
MdelayKTask(1000);
|
||||
}
|
||||
|
||||
closesocket(fd);
|
||||
return;
|
||||
}
|
||||
|
||||
void UdpSocketSendTest(int argc, char *argv[])
|
||||
{
|
||||
if(argc >= 2)
|
||||
{
|
||||
lw_notice("lw: [%s] target ip %s\n", __func__, argv[1]);
|
||||
if(sscanf(argv[1], "%d.%d.%d.%d:%d", &udp_socket_ip[0], &udp_socket_ip[1], &udp_socket_ip[2], &udp_socket_ip[3], &udp_socket_port) == EOK)
|
||||
{
|
||||
sscanf(argv[1], "%d.%d.%d.%d", &udp_socket_ip[0], &udp_socket_ip[1], &udp_socket_ip[2], &udp_socket_ip[3]);
|
||||
}
|
||||
}
|
||||
|
||||
lwip_config_tcp(lwip_ipaddr, lwip_netmask, udp_socket_ip);
|
||||
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),
|
||||
UDPSocketSend, UdpSocketSendTest, UDP send echo);
|
||||
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
menu "control app"
|
||||
|
||||
menuconfig APPLICATION_CONTROL
|
||||
bool "Using control apps"
|
||||
default n
|
||||
depends on SUPPORT_CONTROL_FRAMEWORK
|
||||
|
||||
endmenu
|
||||
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
SRC_DIR :=
|
||||
|
||||
ifeq ($(CONFIG_RESOURCES_LWIP),y)
|
||||
|
||||
ifeq ($(CONFIG_USING_CONTROL_PLC_OPCUA), y)
|
||||
SRC_DIR += opcua_demo plc_demo
|
||||
endif
|
||||
|
||||
endif
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
SRC_FILES :=opcua_demo.c
|
||||
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
# OPCUA DEMO README
|
||||
|
||||
## 文件说明
|
||||
|
||||
用于OPCUA 相关测试命令演示,需要开启LWIP和OPCUA协议.
|
||||
|
||||
### 命令行
|
||||
|
||||
UaConnect [IP]
|
||||
|
||||
用于测试与OPCUA服务器连接,连接成功应显示OK
|
||||
|
||||
UaObject [IP]
|
||||
|
||||
用于显示对应的OPCUA设备的节点信息
|
||||
|
||||
|
|
@ -0,0 +1,266 @@
|
|||
/*
|
||||
* 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 opcua_demo.c
|
||||
* @brief Demo for OpcUa function
|
||||
* @version 1.0
|
||||
* @author AIIT XUOS Lab
|
||||
* @date 2021.11.11
|
||||
*/
|
||||
|
||||
#include <list.h>
|
||||
#include <transform.h>
|
||||
#include "board.h"
|
||||
#include "open62541.h"
|
||||
#include "ua_api.h"
|
||||
|
||||
/*******************************************************************************
|
||||
* Definitions
|
||||
******************************************************************************/
|
||||
|
||||
#define UA_URL_SIZE 100
|
||||
#define UA_STACK_SIZE 4096
|
||||
#define UA_TASK_PRIO 15
|
||||
|
||||
/*******************************************************************************
|
||||
* Prototypes
|
||||
******************************************************************************/
|
||||
|
||||
/*******************************************************************************
|
||||
* Variables
|
||||
******************************************************************************/
|
||||
// to count test
|
||||
static int test_cnt = 0;
|
||||
static int fail_cnt = 0; // count failure times
|
||||
|
||||
char test_ua_ip[] = {192, 168, 250, 2};
|
||||
|
||||
/*******************************************************************************
|
||||
* Code
|
||||
******************************************************************************/
|
||||
|
||||
static void UaConnectTestTask(void* arg)
|
||||
{
|
||||
struct netif net;
|
||||
UA_StatusCode ret;
|
||||
char url[UA_URL_SIZE];
|
||||
memset(url, 0, sizeof(url));
|
||||
|
||||
UA_Client* client = UA_Client_new();
|
||||
|
||||
if(client == NULL)
|
||||
{
|
||||
ua_error("ua: [%s] tcp client null\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
UA_ClientConfig* config = UA_Client_getConfig(client);
|
||||
|
||||
UA_ClientConfig_setDefault(config);
|
||||
|
||||
snprintf(url, sizeof(url), "opc.tcp://%d.%d.%d.%d:4840",
|
||||
test_ua_ip[0], test_ua_ip[1], test_ua_ip[2], test_ua_ip[3]);
|
||||
|
||||
ua_notice("ua connect cnt %d fail %d\n", test_cnt++, fail_cnt ++);
|
||||
ua_notice("ua connect uri: %.*s\n", strlen(url), url);
|
||||
|
||||
ret = UA_Client_connect(client, url);
|
||||
|
||||
if(ret != UA_STATUSCODE_GOOD)
|
||||
{
|
||||
ua_error("ua: [%s] connected failed %x\n", __func__, ret);
|
||||
UA_Client_delete(client);
|
||||
fail_cnt++;
|
||||
return;
|
||||
}
|
||||
|
||||
ua_notice("ua connected ok!\n");
|
||||
UA_Client_delete(client);
|
||||
}
|
||||
|
||||
static void UaConnectTest(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_notice("input wrong ip\n");
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lwip_config_tcp(lwip_ipaddr, lwip_netmask, test_ua_ip);
|
||||
sys_thread_new("ua test", UaConnectTestTask, NULL, UA_STACK_SIZE, UA_TASK_PRIO);
|
||||
}
|
||||
|
||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0) | SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN) | SHELL_CMD_PARAM_NUM(0),
|
||||
UaConnect, UaConnectTest, Test Opc UA connection);
|
||||
|
||||
void UaBrowserObjectsTestTask(void* param)
|
||||
{
|
||||
ua_notice("ua: [%s] start %d ...\n", __func__, test_cnt++);
|
||||
|
||||
UA_Client* client = UA_Client_new();
|
||||
|
||||
if(client == NULL)
|
||||
{
|
||||
ua_error("ua: [%s] tcp client NULL\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
UA_ClientConfig* config = UA_Client_getConfig(client);
|
||||
UA_ClientConfig_setDefault(config);
|
||||
UA_StatusCode ret = UA_Client_connect(client, opc_server_url);
|
||||
|
||||
if(ret != UA_STATUSCODE_GOOD)
|
||||
{
|
||||
ua_error("ua: [%s] connect failed %#x\n", __func__, ret);
|
||||
UA_Client_delete(client);
|
||||
return;
|
||||
}
|
||||
|
||||
ua_notice("--- start read time ---\n", __func__);
|
||||
UaGetServerTime(client);
|
||||
|
||||
ua_notice("--- get server info ---\n", __func__);
|
||||
UaTestBrowserObjects(client);
|
||||
|
||||
/* Clean up */
|
||||
UA_Client_delete(client); /* Disconnects the client internally */
|
||||
}
|
||||
|
||||
static void* UaBrowserObjectsTest(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_notice("input wrong ip\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lwip_config_tcp(lwip_ipaddr, lwip_netmask, test_ua_ip);
|
||||
sys_thread_new("ua object", UaBrowserObjectsTestTask, 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),
|
||||
UaObject, UaBrowserObjectsTest, UaObject [IP]);
|
||||
|
||||
void UaGetInfoTestTask(void* param)
|
||||
{
|
||||
UA_Client* client = UA_Client_new();
|
||||
ua_notice("--- Get OPUCA objects ---\n", __func__);
|
||||
|
||||
if(client == NULL)
|
||||
{
|
||||
ua_error("ua: [%s] tcp client null\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
UA_ClientConfig* config = UA_Client_getConfig(client);
|
||||
UA_ClientConfig_setDefault(config);
|
||||
UA_StatusCode ret = UA_Client_connect(client, opc_server_url);
|
||||
|
||||
if(ret != UA_STATUSCODE_GOOD)
|
||||
{
|
||||
ua_error("ua: [%s] connect failed %#x\n", __func__, ret);
|
||||
UA_Client_delete(client);
|
||||
return;
|
||||
}
|
||||
|
||||
ua_notice("--- interactive server ---\n", __func__);
|
||||
UaTestInteractServer(client);
|
||||
|
||||
UA_Client_delete(client); /* Disconnects the client internally */
|
||||
}
|
||||
|
||||
void* UaGetInfoTest(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_notice("input wrong ip\n");
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
lwip_config_tcp(lwip_ipaddr, lwip_netmask, test_ua_ip);
|
||||
sys_thread_new("ua info", UaGetInfoTestTask, 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),
|
||||
UaInfo, UaGetInfoTest, UaInfo [IP]);
|
||||
|
||||
void UaAddNodesTask(void* param)
|
||||
{
|
||||
UA_Client* client = UA_Client_new();
|
||||
ua_notice("ua: [%s] start ...\n", __func__);
|
||||
|
||||
if(client == NULL)
|
||||
{
|
||||
ua_error("ua: [%s] client null\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
UA_ClientConfig* config = UA_Client_getConfig(client);
|
||||
UA_ClientConfig_setDefault(config);
|
||||
UA_StatusCode ret = UA_Client_connect(client, opc_server_url);
|
||||
|
||||
if(ret != UA_STATUSCODE_GOOD)
|
||||
{
|
||||
ua_print("ua: [%s] connect failed %#x\n", __func__, ret);
|
||||
UA_Client_delete(client);
|
||||
return;
|
||||
}
|
||||
|
||||
ua_notice("--- add nodes ---\n", __func__);
|
||||
UaAddNodes(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_notice("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,48 @@
|
|||
# PLC DEMO README
|
||||
|
||||
## 文件说明
|
||||
|
||||
用于PLC设备相关测试命令演示,目前支持OPCUA协议对PLC进行远程控制,该命令基于LWIP和OPCUA,需要开启相关开关。
|
||||
|
||||
多个PLC设备可以组成一个channel,用于一条相关业务线控制。
|
||||
|
||||
### 命令行
|
||||
|
||||
ShowChannel
|
||||
|
||||
显示注册到channel上的PLC设备,范例如下:
|
||||
|
||||
ch_type ch_name drv_name dev_name cnt
|
||||
-----------------------------------------------------------------
|
||||
PLC_Channel PLC OPCUA PLC Demo 4 1
|
||||
PLC Demo 3 2
|
||||
PLC Demo 2 3
|
||||
PLC Demo 1 4
|
||||
PLC Demo 0 5
|
||||
|
||||
ShowPLC
|
||||
|
||||
用于显示PLC,范例如下:
|
||||
|
||||
device vendor model product id
|
||||
-----------------------------------------------------------------
|
||||
PLC Demo 4 B&R X20 X20 CP1381 5
|
||||
PLC Demo 3 B&R X20 X20 CP1586 4
|
||||
PLC Demo 2 SIEMSNS S7-200 CPU SR60 3
|
||||
PLC Demo 1 SIEMENS S7-1200 CPU 1215C 2
|
||||
PLC Demo 0 SIEMENS S7-1500 CPU 1512SP-1PN 1
|
||||
|
||||
PlcRead [NodeID]
|
||||
|
||||
用于读取PLC节点信息
|
||||
|
||||
- [NodeID]: 如n4,1, 其中4代表namespace,1代表节点号
|
||||
|
||||
|
||||
PlcWrite
|
||||
|
||||
用于写入PLC节点数值
|
||||
|
||||
- [NodeID]: 如n4,1, 其中4代表namespace,1代表节点号
|
||||
|
||||
- [value]: 为写入数值,目前支持bool类型,和int类型。bool型应为0b(代表false), 1b(代表true)
|
||||
|
|
@ -0,0 +1,354 @@
|
|||
/*
|
||||
* 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;
|
||||
|
||||
int plc_test_flag = 0;
|
||||
|
||||
PlcCtrlParamType plc_ctrl_param;
|
||||
|
||||
UA_NodeId test_nodeid = {4, UA_NODEIDTYPE_NUMERIC, 5};
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
void PlcDelay(int sec)
|
||||
{
|
||||
volatile uint32_t i = 0;
|
||||
for (i = 0; i < 100000000 * sec; ++i)
|
||||
{
|
||||
__asm("NOP"); /* delay */
|
||||
}
|
||||
}
|
||||
|
||||
// get NodeId from str
|
||||
void PlcGetTestNodeId(char *str, UA_NodeId *id)
|
||||
{
|
||||
static char node_str[UA_NODE_LEN];
|
||||
memset(node_str, 0, sizeof(node_str));
|
||||
|
||||
plc_print("plc: arg %s\n", str);
|
||||
|
||||
if(sscanf(str, PLC_NS_FORMAT, &id->namespaceIndex, node_str) != EOF)
|
||||
{
|
||||
if(isdigit(node_str[0]))
|
||||
{
|
||||
id->identifierType = UA_NODEIDTYPE_NUMERIC;
|
||||
id->identifier.numeric = atoi(node_str);
|
||||
plc_print("ns %d num %d\n", id->namespaceIndex, id->identifier.numeric);
|
||||
}
|
||||
else
|
||||
{
|
||||
id->identifierType = UA_NODEIDTYPE_STRING;
|
||||
id->identifier.string.length = strlen(node_str);
|
||||
id->identifier.string.data = node_str;
|
||||
plc_print("ns %d str %s\n", id->namespaceIndex, id->identifier.string.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 PlcGetDemoDev(PlcDeviceType *dev, UA_NodeId *id)
|
||||
{
|
||||
// register plc device
|
||||
dev->state = CHDEV_INIT;
|
||||
strcpy(dev->name, "UA Demo");
|
||||
dev->info.product = "CPU 1215C";
|
||||
dev->info.vendor = "SIEMENS";
|
||||
dev->info.model = "S7-1200";
|
||||
dev->info.id = 123;
|
||||
dev->net = PLC_IND_ENET_OPCUA;
|
||||
|
||||
// register UA parameter
|
||||
if(!dev->priv_data)
|
||||
{
|
||||
dev->priv_data = (UaParamType*)malloc(sizeof(UaParamType));
|
||||
}
|
||||
UaParamType* ua_ptr = 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, id, sizeof(*id));
|
||||
}
|
||||
|
||||
static void PlcCtrlDemoInit(void)
|
||||
{
|
||||
static uint8_t init_flag = 0;
|
||||
|
||||
PlcDemoChannelDrvInit();
|
||||
|
||||
// register plc device
|
||||
PlcGetDemoDev(&plc_demo_dev, &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);
|
||||
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 PlcReadTestShell(int argc, char* argv[])
|
||||
{
|
||||
static char node_str[UA_NODE_LEN];
|
||||
memset(node_str, 0, sizeof(node_str));
|
||||
|
||||
if(argc > 1)
|
||||
{
|
||||
PlcGetTestNodeId(argv[1], &test_nodeid);
|
||||
}
|
||||
|
||||
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, PlcReadTestShell, 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);
|
||||
return;
|
||||
}
|
||||
|
||||
ret = ops->write(&plc_demo_dev, arg, PLC_BUF_SIZE);
|
||||
|
||||
if(EOK != ret)
|
||||
{
|
||||
plc_print("plc: [%s] write failed\n", __func__);
|
||||
}
|
||||
|
||||
ops->close(&plc_demo_dev);
|
||||
}
|
||||
|
||||
void PlcWriteTestShell(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)
|
||||
{
|
||||
PlcGetTestNodeId(argv[1], &test_nodeid);
|
||||
}
|
||||
|
||||
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, PlcWriteTestShell, Read PLC);
|
||||
|
||||
// test motor
|
||||
// clear parameter
|
||||
// PlcWrite n4,2 0b
|
||||
// PlcWrite n4,3 0b
|
||||
// PlcWrite n4,4 0b
|
||||
// PlcWrite n4,5 0b
|
||||
//
|
||||
// enable
|
||||
// PlcWrite n4,2 1b
|
||||
//
|
||||
// set rotate speed
|
||||
// PlcWrite n4,3 50
|
||||
//
|
||||
// positive turn
|
||||
// PlcWrite n4,4 1b
|
||||
//
|
||||
// reversal turn
|
||||
// PlcWrite n4,5 1b
|
||||
|
||||
static int plc_test_speed = 50;
|
||||
static int plc_test_dir = 1; // direction positive: 1 reversal: 0
|
||||
|
||||
void PlcMotorTestTask(void* arg)
|
||||
{
|
||||
//support node id
|
||||
char *test_nodeid[] = {"n4,2", "n4,3", "n4,4", "n4,5", "n4,7"};
|
||||
// enable -> speed -> positive dir or inversal dir -> stop -> enable
|
||||
char test_sort[] = {0, 4, 2, 1, 0};
|
||||
char test_cmd[][4] = {"1b", "50", "1b", "1b", "0b"};
|
||||
char *test_notice[] = {"Enable Motor", "Set Speed", "Set Forward", "Set Reverse", "Stop Motor"};
|
||||
|
||||
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);
|
||||
return;
|
||||
}
|
||||
|
||||
UaParamType* ua_ptr = plc_demo_dev.priv_data;
|
||||
|
||||
// initialize step
|
||||
for(int i = 0; i < 5; i++)
|
||||
{
|
||||
plc_print("###\n### Clear %s\n###\n", test_notice[i]);
|
||||
PlcGetTestNodeId(test_nodeid[i], &ua_ptr->ua_id);
|
||||
ret = ops->write(&plc_demo_dev, "0b", PLC_BUF_SIZE);
|
||||
if(EOK != ret)
|
||||
{
|
||||
plc_print("plc: [%s] %d write failed\n", __func__, __LINE__);
|
||||
}
|
||||
PlcDelay(1);
|
||||
}
|
||||
|
||||
if(plc_test_speed != 50)
|
||||
{
|
||||
snprintf(test_cmd[1], 4, "%d", plc_test_speed);
|
||||
}
|
||||
|
||||
if(plc_test_dir == 0) // if not postive, next running
|
||||
test_sort[2] = 3;
|
||||
|
||||
for(int i = 0; i < sizeof(test_sort)/sizeof(test_sort[0]); i++)
|
||||
{
|
||||
PlcGetTestNodeId(test_nodeid[test_sort[i]], &ua_ptr->ua_id);
|
||||
plc_print("###\n### %s\n###\n", test_notice[i]);
|
||||
ret = ops->write(&plc_demo_dev, test_cmd[i], PLC_BUF_SIZE);
|
||||
if(EOK != ret)
|
||||
{
|
||||
plc_print("plc: [%s] %d write failed\n", __func__, __LINE__);
|
||||
}
|
||||
PlcDelay(1);
|
||||
if(i == 2) // postive
|
||||
{
|
||||
PlcDelay(10);
|
||||
}
|
||||
}
|
||||
ops->close(&plc_demo_dev);
|
||||
plc_test_flag = 0;
|
||||
}
|
||||
|
||||
// get parameter from
|
||||
void PlcGetMotorParam(char *str)
|
||||
{
|
||||
static char node_str[UA_NODE_LEN];
|
||||
memset(node_str, 0, sizeof(node_str));
|
||||
|
||||
plc_print("plc: arg %s\n", str);
|
||||
|
||||
sscanf(str, "speed=%d", &plc_test_speed);
|
||||
sscanf(str, "dir=%d", &plc_test_dir);
|
||||
plc_print("speed is %d\n", plc_test_speed);
|
||||
plc_print("dir is %d\n", plc_test_dir);
|
||||
}
|
||||
|
||||
void PlcMotorTestShell(int argc, char* argv[])
|
||||
{
|
||||
if(plc_test_flag)
|
||||
{
|
||||
plc_print("PLC Motor testing!\n");
|
||||
return;
|
||||
}
|
||||
plc_test_flag = 1;
|
||||
|
||||
if(argc > 1)
|
||||
{
|
||||
for(int i = 0; i < argc; i++)
|
||||
{
|
||||
PlcGetMotorParam(argv[i]);
|
||||
}
|
||||
}
|
||||
|
||||
sys_thread_new("plc motor", PlcMotorTestTask, 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),
|
||||
PlcMotorTest, PlcMotorTestShell, Run motor);
|
||||
|
||||
|
|
@ -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,116 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <xizi.h>
|
||||
#include <stdio.h>
|
||||
#include <cstdlib>
|
||||
using namespace std;
|
||||
extern "C" void KPrintf(const char *fmt, ...);
|
||||
|
||||
class Animal //parent class
|
||||
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
virtual void Eat()
|
||||
{
|
||||
|
||||
KPrintf("eat\n");
|
||||
|
||||
}
|
||||
|
||||
void Sleep()
|
||||
{
|
||||
KPrintf("sleep\n");
|
||||
}
|
||||
|
||||
|
||||
};
|
||||
|
||||
class Fish :public Animal //subclass
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
void Eat()
|
||||
{
|
||||
KPrintf("fish eat\n");
|
||||
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
void Doeat(Animal& animal)
|
||||
{
|
||||
animal.Eat();
|
||||
}
|
||||
|
||||
void MemTest2()
|
||||
{
|
||||
int i;
|
||||
char *ptr = NULL; /* memory pointer */
|
||||
|
||||
for (i = 0; ; i++) {
|
||||
/* allocate (1<<i) bytes memory every single time */
|
||||
ptr = (char *)operator new(1 << i);
|
||||
|
||||
/* if allocate successfully */
|
||||
if (ptr != NULL) {
|
||||
KPrintf("get memory :%d byte\n", (1 << i));
|
||||
/* release the memory */
|
||||
operator delete(ptr);
|
||||
KPrintf("free memory :%d byte\n", (1 << i));
|
||||
ptr = NULL;
|
||||
} else {
|
||||
KPrintf("try to get %d byte memory failed!\n", (1 << i));
|
||||
break;
|
||||
//return 0;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
void OverLoadTest(int a)
|
||||
{
|
||||
KPrintf("output is a int number: %d\n", a);
|
||||
}
|
||||
|
||||
void OverLoadTestDouble(int a,int b )
|
||||
{
|
||||
KPrintf("output is 2 int number: %d and %d\n", a,b);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void MySwap(T& a, T& b)
|
||||
{
|
||||
T temp = a;
|
||||
a = b;
|
||||
b = temp;
|
||||
}
|
||||
|
||||
extern "C" int cppmain(void)
|
||||
{
|
||||
MemTest2();
|
||||
|
||||
class Fish fish;
|
||||
Doeat(fish);
|
||||
|
||||
int a = 3;
|
||||
int b = 5;
|
||||
void OverLoadTestDouble(int a, int b);
|
||||
OverLoadTestDouble(a, b);
|
||||
MySwap(a,b);
|
||||
KPrintf("with template the output is: %d and %d\n", a,b);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -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 */
|
||||
|
|
@ -0,0 +1,237 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <transform.h>
|
||||
|
||||
extern int SensorFrameworkInit(void);
|
||||
extern int AdapterFrameworkInit(void);
|
||||
|
||||
extern int Adapter4GInit(void);
|
||||
extern int AdapterNbiotInit(void);
|
||||
extern int AdapterBlueToothInit(void);
|
||||
extern int AdapterWifiInit(void);
|
||||
extern int AdapterEthernetInit(void);
|
||||
extern int AdapterEthercatInit(void);
|
||||
extern int AdapterZigbeeInit(void);
|
||||
extern int AdapterLoraInit(void);
|
||||
|
||||
extern int D124VoiceInit(void);
|
||||
extern int Hs300xTemperatureInit(void);
|
||||
extern int Hs300xHumidityInit(void);
|
||||
extern int Ps5308Pm1_0Init(void);
|
||||
extern int Ps5308Pm2_5Init(void);
|
||||
extern int Ps5308Pm10Init(void);
|
||||
extern int Zg09Co2Init(void);
|
||||
extern int G8sCo2Init(void);
|
||||
extern int As830Ch4Init(void);
|
||||
extern int Tb600bIaq10IaqInit(void);
|
||||
extern int Tb600bTvoc10TvocInit(void);
|
||||
extern int Tb600bWqHcho1osInit(void);
|
||||
extern int QsFxWindDirectionInit(void);
|
||||
extern int QsFsWindSpeedInit(void);
|
||||
|
||||
extern int lv_port_init(void);
|
||||
|
||||
typedef int (*InitFunc)(void);
|
||||
struct InitDesc
|
||||
{
|
||||
const char* fn_name;
|
||||
const InitFunc fn;
|
||||
};
|
||||
|
||||
static int AppInitDesc(struct InitDesc sub_desc[])
|
||||
{
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
for( i = 0; sub_desc[i].fn != NULL; i++ ) {
|
||||
ret = sub_desc[i].fn();
|
||||
printf("initialize %s %s\n",sub_desc[i].fn_name, ret == 0 ? "success" : "failed");
|
||||
if(0 != ret) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static struct InitDesc framework[] =
|
||||
{
|
||||
#ifdef SUPPORT_SENSOR_FRAMEWORK
|
||||
{ "sensor_framework", SensorFrameworkInit },
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORT_CONNECTION_FRAMEWORK
|
||||
{ "connection_framework", AdapterFrameworkInit },
|
||||
#endif
|
||||
|
||||
{ "NULL", NULL },
|
||||
};
|
||||
|
||||
static struct InitDesc sensor_desc[] =
|
||||
{
|
||||
#ifdef SENSOR_DEVICE_D124
|
||||
{ "d124_voice", D124VoiceInit },
|
||||
#endif
|
||||
|
||||
#ifdef SENSOR_DEVICE_HS300X
|
||||
#ifdef SENSOR_QUANTITY_HS300X_TEMPERATURE
|
||||
{ "hs300x_temperature", Hs300xTemperatureInit },
|
||||
#endif
|
||||
#ifdef SENSOR_QUANTITY_HS300X_HUMIDITY
|
||||
{ "hs300x_humidity", Hs300xHumidityInit },
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SENSOR_PS5308
|
||||
#ifdef SENSOR_QUANTITY_PS5308_PM1_0
|
||||
{ "ps5308_pm1_0", Ps5308Pm1_0Init },
|
||||
#endif
|
||||
#ifdef SENSOR_QUANTITY_PS5308_PM2_5
|
||||
{ "ps5308_pm2_5", Ps5308Pm2_5Init },
|
||||
#endif
|
||||
#ifdef SENSOR_QUANTITY_PS5308_PM10
|
||||
{ "ps5308_pm10", Ps5308Pm10Init },
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#ifdef SENSOR_ZG09
|
||||
{ "zg09_co2", Zg09Co2Init },
|
||||
#endif
|
||||
|
||||
#ifdef SENSOR_G8S
|
||||
{ "g8s_co2", G8sCo2Init },
|
||||
#endif
|
||||
|
||||
#ifdef SENSOR_QS_FX
|
||||
{ "qs_fx_wind_direction", QsFxWindDirectionInit },
|
||||
#endif
|
||||
|
||||
#ifdef SENSOR_QS_FS
|
||||
{ "qs_fs_wind_speed", QsFsWindSpeedInit },
|
||||
#endif
|
||||
|
||||
#ifdef SENSOR_AS830
|
||||
{ "ch4_as830", As830Ch4Init },
|
||||
#endif
|
||||
|
||||
#ifdef SENSOR_TB600B_IAQ10
|
||||
{ "iaq_tb600b_iaq10", Tb600bIaq10IaqInit },
|
||||
#endif
|
||||
|
||||
#ifdef SENSOR_TB600B_TVOC10
|
||||
{ "tvoc_tb600b_tvoc10", Tb600bTvoc10TvocInit },
|
||||
#endif
|
||||
|
||||
#ifdef SENSOR_TB600B_WQ_HCHO1OS
|
||||
{ "tvoc_tb600b_wq_hcho1os", Tb600bWqHcho1osInit },
|
||||
#endif
|
||||
|
||||
{ "NULL", NULL },
|
||||
};
|
||||
|
||||
static struct InitDesc connection_desc[] =
|
||||
{
|
||||
#ifdef CONNECTION_ADAPTER_4G
|
||||
{ "4G adapter", Adapter4GInit},
|
||||
#endif
|
||||
#ifdef CONNECTION_ADAPTER_NB
|
||||
{ "NB adpter", AdapterNbiotInit},
|
||||
#endif
|
||||
#ifdef CONNECTION_ADAPTER_ZIGBEE
|
||||
{ "zigbee adapter", AdapterZigbeeInit},
|
||||
#endif
|
||||
#ifdef CONNECTION_ADAPTER_BLUETOOTH
|
||||
{ "bluetooth adapter", AdapterBlueToothInit},
|
||||
#endif
|
||||
#ifdef CONNECTION_ADAPTER_WIFI
|
||||
{ "wifi adapter", AdapterWifiInit},
|
||||
#endif
|
||||
#ifdef CONNECTION_ADAPTER_ETHERNET
|
||||
{ "ethernet adapter", AdapterEthernetInit},
|
||||
#endif
|
||||
#ifdef CONNECTION_ADAPTER_ETHERCAT
|
||||
{ "ethercat adapter", AdapterEthercatInit},
|
||||
#endif
|
||||
#ifdef CONNECTION_ADAPTER_LORA
|
||||
{ "lora adapter", AdapterLoraInit},
|
||||
#endif
|
||||
{ "NULL", NULL },
|
||||
};
|
||||
|
||||
/**
|
||||
* This function will init sensor framework and all sub sensors
|
||||
* @param sub_desc framework
|
||||
*
|
||||
*/
|
||||
static int SensorDeviceFrameworkInit(struct InitDesc sub_desc[])
|
||||
{
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
for ( i = 0; sub_desc[i].fn != NULL; i++ ) {
|
||||
if (0 == strncmp(sub_desc[i].fn_name, "sensor_framework", strlen("sensor_framework"))) {
|
||||
ret = sub_desc[i].fn();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == ret) {
|
||||
printf("initialize sensor_framework success.\n");
|
||||
AppInitDesc(sensor_desc);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will init connection framework and all sub components
|
||||
* @param sub_desc framework
|
||||
*
|
||||
*/
|
||||
static int ConnectionDeviceFrameworkInit(struct InitDesc sub_desc[])
|
||||
{
|
||||
int i = 0;
|
||||
int ret = 0;
|
||||
for ( i = 0; sub_desc[i].fn != NULL; i++ ) {
|
||||
if (0 == strncmp(sub_desc[i].fn_name, "connection_framework", strlen("connection_framework"))) {
|
||||
ret = sub_desc[i].fn();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (0 == ret) {
|
||||
printf("initialize connection_framework success.\n");
|
||||
AppInitDesc(connection_desc);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will init system framework
|
||||
*
|
||||
*/
|
||||
int FrameworkInit(void)
|
||||
{
|
||||
#ifdef SUPPORT_SENSOR_FRAMEWORK
|
||||
SensorDeviceFrameworkInit(framework);
|
||||
#endif
|
||||
|
||||
#ifdef SUPPORT_CONNECTION_FRAMEWORK
|
||||
ConnectionDeviceFrameworkInit(framework);
|
||||
#endif
|
||||
|
||||
#ifdef LIB_LV
|
||||
lv_port_init();
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
SRC_DIR := list
|
||||
|
||||
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,11 @@
|
|||
include $(KERNEL_ROOT)/.config
|
||||
ifeq ($(CONFIG_ADD_NUTTX_FETURES),y)
|
||||
include $(APPDIR)/Make.defs
|
||||
CSRCS += double_list.c single_list.c
|
||||
include $(APPDIR)/Application.mk
|
||||
endif
|
||||
|
||||
ifeq ($(CONFIG_ADD_XIZI_FETURES),y)
|
||||
SRC_FILES := double_list.c single_list.c
|
||||
include $(KERNEL_ROOT)/compiler.mk
|
||||
endif
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
import os
|
||||
from building import *
|
||||
Import('RTT_ROOT')
|
||||
Import('rtconfig')
|
||||
cwd = GetCurrentDir()
|
||||
DEPENDS = [""]
|
||||
|
||||
SOURCES = ['double_list.c'] + ['single_list.c']
|
||||
path = [cwd]
|
||||
objs = DefineGroup('list', src = SOURCES, depend = DEPENDS,CPPPATH = path)
|
||||
Return("objs")
|
||||
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* 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: double_link.c
|
||||
* @brief: functions definition of double list for application
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include "list.h"
|
||||
|
||||
void AppInitDoubleList(DoublelistType *list_head)
|
||||
{
|
||||
list_head->node_next = list_head;
|
||||
list_head->node_prev = list_head;
|
||||
}
|
||||
|
||||
void AppDoubleListInsertNodeAfter(DoublelistType *list, DoublelistType *list_node)
|
||||
{
|
||||
list->node_next->node_prev = list_node;
|
||||
list_node->node_next = list->node_next;
|
||||
|
||||
list->node_next = list_node;
|
||||
list_node->node_prev = list;
|
||||
}
|
||||
|
||||
void AppDoubleListInsertNodeBefore(DoublelistType *list, DoublelistType *list_node)
|
||||
{
|
||||
list->node_prev->node_next = list_node;
|
||||
list_node->node_prev = list->node_prev;
|
||||
|
||||
list->node_prev = list_node;
|
||||
list_node->node_next = list;
|
||||
}
|
||||
|
||||
void AppDoubleListRmNode(DoublelistType *list_node)
|
||||
{
|
||||
list_node->node_next->node_prev = list_node->node_prev;
|
||||
list_node->node_prev->node_next = list_node->node_next;
|
||||
|
||||
list_node->node_next = list_node;
|
||||
list_node->node_prev = list_node;
|
||||
}
|
||||
|
||||
int AppIsDoubleListEmpty(const DoublelistType *list)
|
||||
{
|
||||
return list->node_next == list;
|
||||
}
|
||||
|
||||
struct DoublelistNode *AppDoubleListGetHead(const DoublelistType *list)
|
||||
{
|
||||
return AppIsDoubleListEmpty(list) ? NULL : list->node_next;
|
||||
}
|
||||
|
||||
struct DoublelistNode *AppDoubleListGetNext(const DoublelistType *list,
|
||||
const struct DoublelistNode *list_node)
|
||||
{
|
||||
return list_node->node_next == list ? NULL : list_node->node_next;
|
||||
}
|
||||
|
||||
unsigned int AppDoubleListLenGet(const DoublelistType *list)
|
||||
{
|
||||
unsigned int linklist_length = 0;
|
||||
const DoublelistType *tmp_node = list;
|
||||
while (tmp_node->node_next != list)
|
||||
{
|
||||
tmp_node = tmp_node->node_next;
|
||||
linklist_length ++;
|
||||
}
|
||||
|
||||
return linklist_length;
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* 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: list.h
|
||||
* @brief: function declaration and structure defintion of list
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2021/6/23
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __LIST_H__
|
||||
#define __LIST_H__
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdarg.h>
|
||||
#include <fcntl.h>
|
||||
#include<stddef.h>
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct DoublelistNode
|
||||
{
|
||||
struct DoublelistNode *node_next;
|
||||
struct DoublelistNode *node_prev;
|
||||
} DoublelistType;
|
||||
|
||||
// Single List
|
||||
typedef struct SinglelistNode
|
||||
{
|
||||
struct SinglelistNode *node_next;
|
||||
} SinglelistType;
|
||||
|
||||
|
||||
#define CONTAINER_OF(item, type, member) \
|
||||
((type *)((char *)(item) - (unsigned long)(&((type *)0)->member)))
|
||||
|
||||
|
||||
#define DOUBLE_LIST_OBJ_INIT(obj) { &(obj), &(obj) }
|
||||
|
||||
void AppInitDoubleList(DoublelistType *linklist_head);
|
||||
void AppDoubleListInsertNodeAfter(DoublelistType *list, DoublelistType *list_node);
|
||||
void AppDoubleListInsertNodeBefore(DoublelistType *list, DoublelistType *list_node);
|
||||
void AppDoubleListRmNode(DoublelistType *list_node);
|
||||
int AppIsDoubleListEmpty(const DoublelistType *list);
|
||||
struct DoublelistNode *AppDoubleLinkListGetHead(const DoublelistType *list);
|
||||
struct DoublelistNode *AppDoubleLinkListGetNext(const DoublelistType *list,
|
||||
const struct DoublelistNode *list_node);
|
||||
unsigned int AppDoubleListLenGet(const DoublelistType *list);
|
||||
|
||||
#define DOUBLE_LIST_ENTRY(item, type, member) \
|
||||
CONTAINER_OF(item, type, member)
|
||||
|
||||
#define DOUBLE_LIST_FOR_EACH(item, head) \
|
||||
for (item = (head)->node_next; item != (head); item = item->node_next)
|
||||
|
||||
#define DOUBLE_LIST_FOR_EACH_SAFE(item, node_next, head) \
|
||||
for (item = (head)->node_next, node_next = item->node_next; item != (head); \
|
||||
item = node_next, node_next = item->node_next)
|
||||
|
||||
#define DOUBLE_LIST_FOR_EACH_ENTRY(item, head, member) \
|
||||
for (item = DOUBLE_LIST_ENTRY((head)->node_next, typeof(*item), member); \
|
||||
&item->member != (head); \
|
||||
item = DOUBLE_LIST_ENTRY(item->member.node_next, typeof(*item), member))
|
||||
|
||||
#define DOUBLE_LIST_FOR_EACH_ENTRY_SAFE(item, node_next, head, member) \
|
||||
for (item = DOUBLE_LIST_ENTRY((head)->node_next, typeof(*item), member), \
|
||||
node_next = DOUBLE_LIST_ENTRY(item->member.node_next, typeof(*item), member); \
|
||||
&item->member != (head); \
|
||||
item = node_next, node_next = DOUBLE_LIST_ENTRY(node_next->member.node_next, typeof(*node_next), member))
|
||||
|
||||
#define DOUBLE_LIST_FIRST_ENTRY(ptr, type, member) \
|
||||
DOUBLE_LIST_ENTRY((ptr)->node_next, type, member)
|
||||
|
||||
#define SINGLE_LIST_OBJ_INIT(obj) { NONE }
|
||||
|
||||
void AppInitSingleList(SinglelistType *list);
|
||||
void AppAppendSingleList(SinglelistType *list, SinglelistType *list_node);
|
||||
void AppSingleListNodeInsert(SinglelistType *list, SinglelistType *list_node);
|
||||
unsigned int AppSingleListGetLen(const SinglelistType *list);
|
||||
SinglelistType *AppSingleListRmNode(SinglelistType *list, SinglelistType *list_node);
|
||||
SinglelistType *AppSingleListGetFirstNode(SinglelistType *list);
|
||||
SinglelistType *AppSingleListGetTailNode(SinglelistType *list);
|
||||
SinglelistType *AppSingleListGetNextNode(SinglelistType *list_node);
|
||||
int AppIsSingleListEmpty(SinglelistType *list);
|
||||
|
||||
#define SINGLE_LIST_ENTRY(node, type, member) \
|
||||
CONTAINER_OF(node, type, member)
|
||||
|
||||
#define SINGLE_LIST_FOR_EACH(item, head) \
|
||||
for (item = (head)->node_next; item != NONE; item = item->node_next)
|
||||
|
||||
#define SINGLE_LIST_FOR_EACH_ENTRY(item, head, member) \
|
||||
for (item = SINGLE_LIST_ENTRY((head)->node_next, typeof(*item), member); \
|
||||
&item->member != (NONE); \
|
||||
item = SINGLE_LIST_ENTRY(item->member.node_next, typeof(*item), member))
|
||||
|
||||
#define SINGLE_LIST_FIRST_ENTRY(ptr, type, member) \
|
||||
SINGLE_LIST_ENTRY((ptr)->node_next, type, member)
|
||||
|
||||
#define SINGLE_LIST_TAIL_ENTRY(ptr, type, member) \
|
||||
SINGLE_LIST_ENTRY(AppSingleListGetTailNode(ptr), type, member)
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
* 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: double_link.c
|
||||
* @brief: functions definition of single list for application
|
||||
* @version: 1.0
|
||||
* @author: AIIT XUOS Lab
|
||||
* @date: 2020/3/15
|
||||
*
|
||||
*/
|
||||
|
||||
#include "list.h"
|
||||
|
||||
void AppInitSingleList(SinglelistType *list)
|
||||
{
|
||||
list->node_next = NULL;
|
||||
}
|
||||
|
||||
void AppAppendSingleList(SinglelistType *list, SinglelistType *list_node)
|
||||
{
|
||||
struct SinglelistNode *node;
|
||||
|
||||
node = list;
|
||||
while (node->node_next) node = node->node_next;
|
||||
|
||||
node->node_next = list_node;
|
||||
list_node->node_next = NULL;
|
||||
}
|
||||
|
||||
void AppSingleListNodeInsert(SinglelistType *list, SinglelistType *list_node)
|
||||
{
|
||||
list_node->node_next = list->node_next;
|
||||
list->node_next = list_node;
|
||||
}
|
||||
|
||||
unsigned int AppSingleListGetLen(const SinglelistType *list)
|
||||
{
|
||||
unsigned int length = 0;
|
||||
const SinglelistType *tmp_list = list->node_next;
|
||||
while (tmp_list != NULL)
|
||||
{
|
||||
tmp_list = tmp_list->node_next;
|
||||
length ++;
|
||||
}
|
||||
|
||||
return length;
|
||||
}
|
||||
|
||||
SinglelistType *AppSingleListRmNode(SinglelistType *list, SinglelistType *list_node)
|
||||
{
|
||||
struct SinglelistNode *node = list;
|
||||
while (node->node_next && node->node_next != list_node) node = node->node_next;
|
||||
|
||||
if (node->node_next != (SinglelistType *)0){
|
||||
node->node_next = node->node_next->node_next;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
SinglelistType *AppSingleListGetFirstNode(SinglelistType *list)
|
||||
{
|
||||
return list->node_next;
|
||||
}
|
||||
|
||||
SinglelistType *AppSingleListGetTailNode(SinglelistType *list)
|
||||
{
|
||||
while (list->node_next) list = list->node_next;
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
SinglelistType *AppSingleListGetNextNode(SinglelistType *list_node)
|
||||
{
|
||||
return list_node->node_next;
|
||||
}
|
||||
|
||||
int AppIsSingleListEmpty(SinglelistType *list)
|
||||
{
|
||||
return list->node_next == NULL;
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
menu "knowing app"
|
||||
menuconfig APPLICATION_KNOWING
|
||||
bool "Using knowing apps"
|
||||
default n
|
||||
|
||||
if APPLICATION_KNOWING
|
||||
source "$APP_DIR/Applications/knowing_app/mnist/Kconfig"
|
||||
source "$APP_DIR/Applications/knowing_app/k210_detect_entry/Kconfig"
|
||||
source "$APP_DIR/Applications/knowing_app/iris_ml_demo/Kconfig"
|
||||
source "$APP_DIR/Applications/knowing_app/k210_fft_test/Kconfig"
|
||||
source "$APP_DIR/Applications/knowing_app/image_processing/Kconfig"
|
||||
source "$APP_DIR/Applications/knowing_app/cmsis_5_demo/Kconfig"
|
||||
source "$APP_DIR/Applications/knowing_app/nnom_demo/Kconfig"
|
||||
|
||||
endif
|
||||
endmenu
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
############################################################################
|
||||
# Applications/knowing_app/Make.defs
|
||||
############################################################################
|
||||
ifneq ($(CONFIG_APPLICATION_KNOWING),)
|
||||
include $(wildcard $(APPDIR)/../../../APP_Framework/Applications/knowing_app/*/Make.defs)
|
||||
endif
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
SRC_DIR := mnist
|
||||
|
||||
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,21 @@
|
|||
menuconfig USING_CMSIS_5_DEMOAPP
|
||||
bool "CMSIS-5 demo app"
|
||||
depends on USING_CMSIS_5_NN
|
||||
default n
|
||||
|
||||
if USING_CMSIS_5_DEMOAPP
|
||||
|
||||
config USING_CMSIS_5_NN_DEMOAPP
|
||||
bool "Using CMSIS-5 NN demo app"
|
||||
select USING_IMAGE_PROCESSING
|
||||
select IMAGE_PROCESSING_USING_TJPGD
|
||||
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
|
||||
|
||||
|
||||
|
|
@ -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,14 @@
|
|||
# CMSIS-NN cifar10 example
|
||||
|
||||
The model of this example is from [[ARM-software](https://github.com/ARM-software)/**[ML-examples](https://github.com/ARM-software/ML-examples)**] and can be deployed on Arm Cortex-M CPUs using [CMSIS-NN](https://github.com/ARM-software/CMSIS_5).
|
||||
|
||||
## Requirements:
|
||||
- CMSIS-NN in Framework/knowing/cmsis_5
|
||||
- TJpgDec in Framework/knowing/image_processing
|
||||
- Enough stack size (recommend 10240) for finsh thread which can be changed in "RT-Thread Components->Command shell->finsh shell" by menuconfig.
|
||||
|
||||
## To run this demo:
|
||||
- Place the photo where you want
|
||||
- Run demo by type the command
|
||||
```
|
||||
cmsisnn_demo /path/to/photo
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
from building import *
|
||||
import os
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
|
||||
src = Split('''
|
||||
model/m4/nn.c
|
||||
demo/cmsisnn_demo.c
|
||||
''')
|
||||
|
||||
path = [
|
||||
cwd + '/model/m4',
|
||||
cwd + '/demo'
|
||||
]
|
||||
|
||||
group = DefineGroup('CMSISNN-cifar10', src, depend = ['USING_CMSIS_5_NN_DEMOAPP'], CPPPATH = path)
|
||||
|
||||
Return('group')
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 1000 B |
|
|
@ -0,0 +1,157 @@
|
|||
#include <transform.h>
|
||||
#include <tjpgd.h>
|
||||
#include "../model/m4/nn.h"
|
||||
|
||||
#define WORK_POOL_SIZE (4 * 1024 + 32)
|
||||
|
||||
const char *cifar10_label[] = {"Plane", "Car", "Bird", "Cat", "Deer", "Dog", "Frog", "Horse", "Ship", "Truck"};
|
||||
|
||||
int get_top_prediction(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(uint8_t *input_data)
|
||||
{
|
||||
q7_t output_data[10];
|
||||
run_nn((q7_t *)input_data, output_data);
|
||||
arm_softmax_q7(output_data, IP1_OUT_DIM, output_data);
|
||||
int top_ind = get_top_prediction(output_data);
|
||||
printf("\rPrediction: %s \r\n", cifar10_label[top_ind]);
|
||||
return top_ind;
|
||||
}
|
||||
|
||||
typedef struct
|
||||
{
|
||||
FILE *fp;
|
||||
uint8_t *fbuf;
|
||||
uint16_t wfbuf;
|
||||
} IODEV;
|
||||
|
||||
unsigned int in_func_cmsisnn(JDEC *jd, uint8_t *buff, unsigned int nbyte)
|
||||
{
|
||||
IODEV *dev = (IODEV *)jd->device;
|
||||
|
||||
if (buff)
|
||||
{
|
||||
return (uint16_t)fread(buff, 1, nbyte, dev->fp);
|
||||
}
|
||||
else
|
||||
{
|
||||
return fseek(dev->fp, nbyte, SEEK_CUR) ? 0 : nbyte;
|
||||
}
|
||||
}
|
||||
|
||||
int out_func_cmsisnn(JDEC *jd, void *bitmap, JRECT *rect)
|
||||
{
|
||||
IODEV *dev = (IODEV *)jd->device;
|
||||
uint8_t *src, *dst;
|
||||
uint16_t y, bws, bwd;
|
||||
|
||||
if (rect->left == 0)
|
||||
{
|
||||
printf("\r%lu%%", (rect->top << jd->scale) * 100UL / jd->height);
|
||||
}
|
||||
|
||||
src = (uint8_t *)bitmap;
|
||||
dst = dev->fbuf + 3 * (rect->top * dev->wfbuf + rect->left);
|
||||
bws = 3 * (rect->right - rect->left + 1);
|
||||
bwd = 3 * dev->wfbuf;
|
||||
for (y = rect->top; y <= rect->bottom; y++)
|
||||
{
|
||||
memcpy(dst, src, bws);
|
||||
src += bws;
|
||||
dst += bwd;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int cmsisnn_demo(int argc, char *argv[])
|
||||
{
|
||||
void *work;
|
||||
JDEC jdec;
|
||||
JRESULT res;
|
||||
IODEV devid;
|
||||
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("Jpeg_Dec illegal arguments ...\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
devid.fp = fopen(argv[1], "r+");
|
||||
if (!devid.fp)
|
||||
{
|
||||
printf("Jpeg_Dec open the file failed...\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
work = malloc(WORK_POOL_SIZE);
|
||||
if (work == NULL)
|
||||
{
|
||||
printf("Jpeg_Dec work malloc failed...\n");
|
||||
res = -1;
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
res = jd_prepare(&jdec, in_func_cmsisnn, work, WORK_POOL_SIZE, &devid);
|
||||
if (res == JDR_OK)
|
||||
{
|
||||
printf("Image dimensions: %u by %u. %u bytes used.\n", jdec.width, jdec.height, 3100 - jdec.sz_pool);
|
||||
|
||||
devid.fbuf = malloc(3 * jdec.width * jdec.height);
|
||||
if (devid.fbuf == NULL)
|
||||
{
|
||||
printf("Jpeg_Dec devid.fbuf malloc failed, need to use %d Bytes ...\n", 3 * jdec.width * jdec.height);
|
||||
res = -1;
|
||||
goto __exit;
|
||||
}
|
||||
devid.wfbuf = jdec.width;
|
||||
|
||||
res = jd_decomp(&jdec, out_func_cmsisnn, 0);
|
||||
if (res == JDR_OK)
|
||||
{
|
||||
printf("\rDecompress success \n");
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Failed to decompress: rc=%d\n", res);
|
||||
}
|
||||
|
||||
cmsisnn_inference(devid.fbuf);
|
||||
|
||||
if (devid.fbuf != NULL)
|
||||
{
|
||||
free(devid.fbuf);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Failed to prepare: rc=%d\n", res);
|
||||
}
|
||||
|
||||
__exit:
|
||||
if (work != NULL)
|
||||
{
|
||||
free(work);
|
||||
}
|
||||
|
||||
fclose(devid.fp);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#ifdef __RT_THREAD_H__
|
||||
MSH_CMD_EXPORT(cmsisnn_demo, cifar10 demo and filename should be followed);
|
||||
#endif
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
#include "nn.h"
|
||||
|
||||
// Timer t;
|
||||
|
||||
static uint8_t mean[DATA_OUT_CH*DATA_OUT_DIM*DATA_OUT_DIM] = MEAN_DATA;
|
||||
|
||||
static q7_t conv1_wt[CONV1_IN_CH*CONV1_KER_DIM*CONV1_KER_DIM*CONV1_OUT_CH] = CONV1_WT;
|
||||
static q7_t conv1_bias[CONV1_OUT_CH] = CONV1_BIAS;
|
||||
|
||||
static q7_t conv2_wt[CONV2_IN_CH*CONV2_KER_DIM*CONV2_KER_DIM*CONV2_OUT_CH] = CONV2_WT;
|
||||
static q7_t conv2_bias[CONV2_OUT_CH] = CONV2_BIAS;
|
||||
|
||||
static q7_t conv3_wt[CONV3_IN_CH*CONV3_KER_DIM*CONV3_KER_DIM*CONV3_OUT_CH] = CONV3_WT;
|
||||
static q7_t conv3_bias[CONV3_OUT_CH] = CONV3_BIAS;
|
||||
|
||||
static q7_t ip1_wt[IP1_IN_DIM*IP1_OUT_DIM] = IP1_WT;
|
||||
static q7_t ip1_bias[IP1_OUT_DIM] = IP1_BIAS;
|
||||
|
||||
//Add input_data and output_data in top main.cpp file
|
||||
//uint8_t input_data[DATA_OUT_CH*DATA_OUT_DIM*DATA_OUT_DIM];
|
||||
//q7_t output_data[IP1_OUT_DIM];
|
||||
|
||||
q7_t col_buffer[3200];
|
||||
q7_t scratch_buffer[40960];
|
||||
|
||||
void mean_subtract(q7_t* image_data) {
|
||||
for(int i=0; i<DATA_OUT_CH*DATA_OUT_DIM*DATA_OUT_DIM; i++) {
|
||||
image_data[i] = (q7_t)__SSAT( ((int)(image_data[i] - mean[i]) >> DATA_RSHIFT), 8);
|
||||
}
|
||||
}
|
||||
|
||||
void run_nn(q7_t* input_data, q7_t* output_data) {
|
||||
q7_t* buffer1 = scratch_buffer;
|
||||
q7_t* buffer2 = buffer1 + 32768;
|
||||
mean_subtract(input_data);
|
||||
arm_convolve_HWC_q7_RGB(input_data, CONV1_IN_DIM, CONV1_IN_CH, conv1_wt, CONV1_OUT_CH, CONV1_KER_DIM, CONV1_PAD, CONV1_STRIDE, conv1_bias, CONV1_BIAS_LSHIFT, CONV1_OUT_RSHIFT, buffer1, CONV1_OUT_DIM, (q15_t*)col_buffer, NULL);
|
||||
arm_maxpool_q7_HWC(buffer1, POOL1_IN_DIM, POOL1_IN_CH, POOL1_KER_DIM, POOL1_PAD, POOL1_STRIDE, POOL1_OUT_DIM, col_buffer, buffer2);
|
||||
arm_relu_q7(buffer2, RELU1_OUT_DIM*RELU1_OUT_DIM*RELU1_OUT_CH);
|
||||
arm_convolve_HWC_q7_fast(buffer2, CONV2_IN_DIM, CONV2_IN_CH, conv2_wt, CONV2_OUT_CH, CONV2_KER_DIM, CONV2_PAD, CONV2_STRIDE, conv2_bias, CONV2_BIAS_LSHIFT, CONV2_OUT_RSHIFT, buffer1, CONV2_OUT_DIM, (q15_t*)col_buffer, NULL);
|
||||
arm_relu_q7(buffer1, RELU2_OUT_DIM*RELU2_OUT_DIM*RELU2_OUT_CH);
|
||||
arm_avepool_q7_HWC(buffer1, POOL2_IN_DIM, POOL2_IN_CH, POOL2_KER_DIM, POOL2_PAD, POOL2_STRIDE, POOL2_OUT_DIM, col_buffer, buffer2);
|
||||
arm_convolve_HWC_q7_fast(buffer2, CONV3_IN_DIM, CONV3_IN_CH, conv3_wt, CONV3_OUT_CH, CONV3_KER_DIM, CONV3_PAD, CONV3_STRIDE, conv3_bias, CONV3_BIAS_LSHIFT, CONV3_OUT_RSHIFT, buffer1, CONV3_OUT_DIM, (q15_t*)col_buffer, NULL);
|
||||
arm_relu_q7(buffer1, RELU3_OUT_DIM*RELU3_OUT_DIM*RELU3_OUT_CH);
|
||||
arm_avepool_q7_HWC(buffer1, POOL3_IN_DIM, POOL3_IN_CH, POOL3_KER_DIM, POOL3_PAD, POOL3_STRIDE, POOL3_OUT_DIM, col_buffer, buffer2);
|
||||
arm_fully_connected_q7_opt(buffer2, ip1_wt, IP1_IN_DIM, IP1_OUT_DIM, IP1_BIAS_LSHIFT, IP1_OUT_RSHIFT, ip1_bias, output_data, (q15_t*)col_buffer);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef __NN_H__
|
||||
#define __NN_H__
|
||||
|
||||
// #include "mbed.h"
|
||||
#include "arm_math.h"
|
||||
#include "parameter.h"
|
||||
#include "weights.h"
|
||||
#include "arm_nnfunctions.h"
|
||||
|
||||
void run_nn(q7_t* input_data, q7_t* output_data);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
#define DATA_OUT_CH 3
|
||||
#define DATA_OUT_DIM 32
|
||||
|
||||
#define CONV1_IN_DIM 32
|
||||
#define CONV1_IN_CH 3
|
||||
#define CONV1_KER_DIM 5
|
||||
#define CONV1_PAD 2
|
||||
#define CONV1_STRIDE 1
|
||||
#define CONV1_OUT_CH 32
|
||||
#define CONV1_OUT_DIM 32
|
||||
|
||||
#define POOL1_IN_DIM 32
|
||||
#define POOL1_IN_CH 32
|
||||
#define POOL1_KER_DIM 3
|
||||
#define POOL1_STRIDE 2
|
||||
#define POOL1_PAD 0
|
||||
#define POOL1_OUT_DIM 16
|
||||
|
||||
#define RELU1_OUT_CH 32
|
||||
#define RELU1_OUT_DIM 16
|
||||
|
||||
#define CONV2_IN_DIM 16
|
||||
#define CONV2_IN_CH 32
|
||||
#define CONV2_KER_DIM 5
|
||||
#define CONV2_PAD 2
|
||||
#define CONV2_STRIDE 1
|
||||
#define CONV2_OUT_CH 16
|
||||
#define CONV2_OUT_DIM 16
|
||||
|
||||
#define RELU2_OUT_CH 16
|
||||
#define RELU2_OUT_DIM 16
|
||||
|
||||
#define POOL2_IN_DIM 16
|
||||
#define POOL2_IN_CH 16
|
||||
#define POOL2_KER_DIM 3
|
||||
#define POOL2_STRIDE 2
|
||||
#define POOL2_PAD 0
|
||||
#define POOL2_OUT_DIM 8
|
||||
|
||||
#define CONV3_IN_DIM 8
|
||||
#define CONV3_IN_CH 16
|
||||
#define CONV3_KER_DIM 5
|
||||
#define CONV3_PAD 2
|
||||
#define CONV3_STRIDE 1
|
||||
#define CONV3_OUT_CH 32
|
||||
#define CONV3_OUT_DIM 8
|
||||
|
||||
#define RELU3_OUT_CH 32
|
||||
#define RELU3_OUT_DIM 8
|
||||
|
||||
#define POOL3_IN_DIM 8
|
||||
#define POOL3_IN_CH 32
|
||||
#define POOL3_KER_DIM 3
|
||||
#define POOL3_STRIDE 2
|
||||
#define POOL3_PAD 0
|
||||
#define POOL3_OUT_DIM 4
|
||||
|
||||
#define IP1_IN_DIM 512
|
||||
#define IP1_OUT_DIM 10
|
||||
|
||||
#define DATA_RSHIFT 0
|
||||
#define CONV1_BIAS_LSHIFT 0
|
||||
#define CONV1_OUT_RSHIFT 11
|
||||
#define CONV2_BIAS_LSHIFT 0
|
||||
#define CONV2_OUT_RSHIFT 8
|
||||
#define CONV3_BIAS_LSHIFT 0
|
||||
#define CONV3_OUT_RSHIFT 8
|
||||
#define IP1_BIAS_LSHIFT 5
|
||||
#define IP1_OUT_RSHIFT 7
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -0,0 +1,46 @@
|
|||
#include "nn.h"
|
||||
|
||||
// Timer t;
|
||||
|
||||
static uint8_t mean[DATA_OUT_CH*DATA_OUT_DIM*DATA_OUT_DIM] = MEAN_DATA;
|
||||
|
||||
static q7_t conv1_wt[CONV1_IN_CH*CONV1_KER_DIM*CONV1_KER_DIM*CONV1_OUT_CH] = CONV1_WT;
|
||||
static q7_t conv1_bias[CONV1_OUT_CH] = CONV1_BIAS;
|
||||
|
||||
static q7_t conv2_wt[CONV2_IN_CH*CONV2_KER_DIM*CONV2_KER_DIM*CONV2_OUT_CH] = CONV2_WT;
|
||||
static q7_t conv2_bias[CONV2_OUT_CH] = CONV2_BIAS;
|
||||
|
||||
static q7_t conv3_wt[CONV3_IN_CH*CONV3_KER_DIM*CONV3_KER_DIM*CONV3_OUT_CH] = CONV3_WT;
|
||||
static q7_t conv3_bias[CONV3_OUT_CH] = CONV3_BIAS;
|
||||
|
||||
static q7_t ip1_wt[IP1_IN_DIM*IP1_OUT_DIM] = IP1_WT;
|
||||
static q7_t ip1_bias[IP1_OUT_DIM] = IP1_BIAS;
|
||||
|
||||
//Add input_data and output_data in top main.cpp file
|
||||
//uint8_t input_data[DATA_OUT_CH*DATA_OUT_DIM*DATA_OUT_DIM];
|
||||
//q7_t output_data[IP1_OUT_DIM];
|
||||
|
||||
q7_t col_buffer[6400];
|
||||
q7_t scratch_buffer[40960];
|
||||
|
||||
void mean_subtract(q7_t* image_data) {
|
||||
for(int i=0; i<DATA_OUT_CH*DATA_OUT_DIM*DATA_OUT_DIM; i++) {
|
||||
image_data[i] = (q7_t)__SSAT( ((int)(image_data[i] - mean[i]) >> DATA_RSHIFT), 8);
|
||||
}
|
||||
}
|
||||
|
||||
void run_nn(q7_t* input_data, q7_t* output_data) {
|
||||
q7_t* buffer1 = scratch_buffer;
|
||||
q7_t* buffer2 = buffer1 + 32768;
|
||||
mean_subtract(input_data);
|
||||
arm_convolve_HWC_q7_RGB(input_data, CONV1_IN_DIM, CONV1_IN_CH, conv1_wt, CONV1_OUT_CH, CONV1_KER_DIM, CONV1_PAD, CONV1_STRIDE, conv1_bias, CONV1_BIAS_LSHIFT, CONV1_OUT_RSHIFT, buffer1, CONV1_OUT_DIM, (q15_t*)col_buffer, NULL);
|
||||
arm_maxpool_q7_HWC(buffer1, POOL1_IN_DIM, POOL1_IN_CH, POOL1_KER_DIM, POOL1_PAD, POOL1_STRIDE, POOL1_OUT_DIM, col_buffer, buffer2);
|
||||
arm_relu_q7(buffer2, RELU1_OUT_DIM*RELU1_OUT_DIM*RELU1_OUT_CH);
|
||||
arm_convolve_HWC_q7_fast(buffer2, CONV2_IN_DIM, CONV2_IN_CH, conv2_wt, CONV2_OUT_CH, CONV2_KER_DIM, CONV2_PAD, CONV2_STRIDE, conv2_bias, CONV2_BIAS_LSHIFT, CONV2_OUT_RSHIFT, buffer1, CONV2_OUT_DIM, (q15_t*)col_buffer, NULL);
|
||||
arm_relu_q7(buffer1, RELU2_OUT_DIM*RELU2_OUT_DIM*RELU2_OUT_CH);
|
||||
arm_avepool_q7_HWC(buffer1, POOL2_IN_DIM, POOL2_IN_CH, POOL2_KER_DIM, POOL2_PAD, POOL2_STRIDE, POOL2_OUT_DIM, col_buffer, buffer2);
|
||||
arm_convolve_HWC_q7_fast(buffer2, CONV3_IN_DIM, CONV3_IN_CH, conv3_wt, CONV3_OUT_CH, CONV3_KER_DIM, CONV3_PAD, CONV3_STRIDE, conv3_bias, CONV3_BIAS_LSHIFT, CONV3_OUT_RSHIFT, buffer1, CONV3_OUT_DIM, (q15_t*)col_buffer, NULL);
|
||||
arm_relu_q7(buffer1, RELU3_OUT_DIM*RELU3_OUT_DIM*RELU3_OUT_CH);
|
||||
arm_avepool_q7_HWC(buffer1, POOL3_IN_DIM, POOL3_IN_CH, POOL3_KER_DIM, POOL3_PAD, POOL3_STRIDE, POOL3_OUT_DIM, col_buffer, buffer2);
|
||||
arm_fully_connected_q7_opt(buffer2, ip1_wt, IP1_IN_DIM, IP1_OUT_DIM, IP1_BIAS_LSHIFT, IP1_OUT_RSHIFT, ip1_bias, output_data, (q15_t*)col_buffer);
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
#ifndef __NN_H__
|
||||
#define __NN_H__
|
||||
|
||||
// #include "mbed.h"
|
||||
#include "arm_math.h"
|
||||
#include "parameter.h"
|
||||
#include "weights.h"
|
||||
#include "arm_nnfunctions.h"
|
||||
|
||||
void run_nn(q7_t* input_data, q7_t* output_data);
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,69 @@
|
|||
#define DATA_OUT_CH 3
|
||||
#define DATA_OUT_DIM 32
|
||||
|
||||
#define CONV1_IN_DIM 32
|
||||
#define CONV1_IN_CH 3
|
||||
#define CONV1_KER_DIM 5
|
||||
#define CONV1_PAD 2
|
||||
#define CONV1_STRIDE 1
|
||||
#define CONV1_OUT_CH 32
|
||||
#define CONV1_OUT_DIM 32
|
||||
|
||||
#define POOL1_IN_DIM 32
|
||||
#define POOL1_IN_CH 32
|
||||
#define POOL1_KER_DIM 3
|
||||
#define POOL1_STRIDE 2
|
||||
#define POOL1_PAD 0
|
||||
#define POOL1_OUT_DIM 16
|
||||
|
||||
#define RELU1_OUT_CH 32
|
||||
#define RELU1_OUT_DIM 16
|
||||
|
||||
#define CONV2_IN_DIM 16
|
||||
#define CONV2_IN_CH 32
|
||||
#define CONV2_KER_DIM 5
|
||||
#define CONV2_PAD 2
|
||||
#define CONV2_STRIDE 1
|
||||
#define CONV2_OUT_CH 32
|
||||
#define CONV2_OUT_DIM 16
|
||||
|
||||
#define RELU2_OUT_CH 32
|
||||
#define RELU2_OUT_DIM 16
|
||||
|
||||
#define POOL2_IN_DIM 16
|
||||
#define POOL2_IN_CH 32
|
||||
#define POOL2_KER_DIM 3
|
||||
#define POOL2_STRIDE 2
|
||||
#define POOL2_PAD 0
|
||||
#define POOL2_OUT_DIM 8
|
||||
|
||||
#define CONV3_IN_DIM 8
|
||||
#define CONV3_IN_CH 32
|
||||
#define CONV3_KER_DIM 5
|
||||
#define CONV3_PAD 2
|
||||
#define CONV3_STRIDE 1
|
||||
#define CONV3_OUT_CH 64
|
||||
#define CONV3_OUT_DIM 8
|
||||
|
||||
#define RELU3_OUT_CH 64
|
||||
#define RELU3_OUT_DIM 8
|
||||
|
||||
#define POOL3_IN_DIM 8
|
||||
#define POOL3_IN_CH 64
|
||||
#define POOL3_KER_DIM 3
|
||||
#define POOL3_STRIDE 2
|
||||
#define POOL3_PAD 0
|
||||
#define POOL3_OUT_DIM 4
|
||||
|
||||
#define IP1_IN_DIM 1024
|
||||
#define IP1_OUT_DIM 10
|
||||
|
||||
#define DATA_RSHIFT 0
|
||||
#define CONV1_BIAS_LSHIFT 0
|
||||
#define CONV1_OUT_RSHIFT 9
|
||||
#define CONV2_BIAS_LSHIFT 0
|
||||
#define CONV2_OUT_RSHIFT 9
|
||||
#define CONV3_BIAS_LSHIFT 0
|
||||
#define CONV3_OUT_RSHIFT 9
|
||||
#define IP1_BIAS_LSHIFT 3
|
||||
#define IP1_OUT_RSHIFT 5
|
||||
File diff suppressed because one or more lines are too long
|
|
@ -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
|
|
@ -0,0 +1,6 @@
|
|||
menuconfig USING_IMAGE_PROCESSING_APP
|
||||
bool "image processing app "
|
||||
default n
|
||||
if USING_IMAGE_PROCESSING_APP
|
||||
source "$APP_DIR/Applications/knowing_app/image_processing/TJpgDec_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 IMAGE_PROCESSING_TJPGDEC_APP
|
||||
bool "image processing apps/TJpgDec(example)"
|
||||
select USING_IMAGE_PROCESSING
|
||||
select IMAGE_PROCESSING_USING_TJPGD
|
||||
default n
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c') + Glob('*.cpp')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('TJpgDec(example)', src, depend = ['IMAGE_PROCESSING_TJPGDEC_APP'], LOCAL_CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
#include <transform.h>
|
||||
#include <tjpgd.h>
|
||||
#define WORK_POOL_SIZE (4*1024+32)//This value depends on the resolution of the image
|
||||
|
||||
/* User defined device identifier */
|
||||
typedef struct {
|
||||
FILE *fp; /* File pointer for input function */
|
||||
uint8_t *fbuf; /* Pointer to the frame buffer for output function */
|
||||
uint16_t wfbuf; /* Width of the frame buffer [pix] */
|
||||
} IODEV;
|
||||
|
||||
|
||||
/*------------------------------*/
|
||||
/* User defined input funciton */
|
||||
/*------------------------------*/
|
||||
|
||||
unsigned int in_func (JDEC* jd, uint8_t* buff, unsigned int nbyte)
|
||||
{
|
||||
IODEV *dev = (IODEV*)jd->device; /* Device identifier for the session (5th argument of jd_prepare function) */
|
||||
|
||||
|
||||
if (buff) {
|
||||
/* Read bytes from input stream */
|
||||
return (uint16_t)fread(buff, 1, nbyte, dev->fp);
|
||||
} else {
|
||||
/* Remove bytes from input stream */
|
||||
return fseek(dev->fp, nbyte, SEEK_CUR) ? 0 : nbyte;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------*/
|
||||
/* User defined output funciton */
|
||||
/*------------------------------*/
|
||||
|
||||
int out_func (JDEC* jd, void* bitmap, JRECT* rect)
|
||||
{
|
||||
IODEV *dev = (IODEV*)jd->device;
|
||||
uint8_t *src, *dst;
|
||||
uint16_t y, bws, bwd;
|
||||
|
||||
|
||||
/* Put progress indicator */
|
||||
if (rect->left == 0) {
|
||||
printf("\r%lu%%", (rect->top << jd->scale) * 100UL / jd->height);
|
||||
}
|
||||
|
||||
/* Copy the decompressed RGB rectanglar to the frame buffer (assuming RGB888 cfg) */
|
||||
src = (uint8_t*)bitmap;
|
||||
dst = dev->fbuf + 3 * (rect->top * dev->wfbuf + rect->left); /* Left-top of destination rectangular */
|
||||
bws = 3 * (rect->right - rect->left + 1); /* Width of source rectangular [byte] */
|
||||
bwd = 3 * dev->wfbuf; /* Width of frame buffer [byte] */
|
||||
for (y = rect->top; y <= rect->bottom; y++) {
|
||||
memcpy(dst, src, bws); /* Copy a line */
|
||||
src += bws; dst += bwd; /* Next line */
|
||||
}
|
||||
|
||||
return 1; /* Continue to decompress */
|
||||
}
|
||||
|
||||
|
||||
/*------------------------------*/
|
||||
/* Program Jpeg_Dec */
|
||||
/*------------------------------*/
|
||||
|
||||
int Jpeg_Dec (int argc, char* argv[])
|
||||
{
|
||||
void *work; /* Pointer to the decompressor work area */
|
||||
JDEC jdec; /* Decompression object */
|
||||
JRESULT res; /* Result code of TJpgDec API */
|
||||
IODEV devid; /* User defined device identifier */
|
||||
|
||||
/* Open a JPEG file */
|
||||
if (argc < 2)
|
||||
{
|
||||
printf("Jpeg_Dec illegal arguments ...\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
devid.fp = fopen(argv[1], "r+");
|
||||
if (!devid.fp)
|
||||
{
|
||||
printf("Jpeg_Dec open the file failed...\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Allocate a work area for TJpgDec */
|
||||
work = malloc(WORK_POOL_SIZE);
|
||||
if(work == NULL)
|
||||
{
|
||||
printf("Jpeg_Dec work malloc failed...\n");
|
||||
res = -1;
|
||||
goto __exit;
|
||||
}
|
||||
|
||||
/* Prepare to decompress */
|
||||
res = jd_prepare(&jdec, in_func, work, WORK_POOL_SIZE, &devid);
|
||||
if (res == JDR_OK)
|
||||
{
|
||||
/* Ready to dcompress. Image info is available here. */
|
||||
printf("Image dimensions: %u by %u. %u bytes used.\n", jdec.width, jdec.height, 3100 - jdec.sz_pool);
|
||||
|
||||
devid.fbuf = malloc(3 * jdec.width * jdec.height); /* Frame buffer for output image (assuming RGB888 cfg) */
|
||||
if(devid.fbuf == RT_NULL)
|
||||
{
|
||||
printf("Jpeg_Dec devid.fbuf malloc failed, need to use %d Bytes ...\n", 3 * jdec.width * jdec.height);
|
||||
res = -1;
|
||||
goto __exit;
|
||||
}
|
||||
devid.wfbuf = jdec.width;
|
||||
|
||||
res = jd_decomp(&jdec, out_func, 0); /* Start to decompress with 1/1 scaling */
|
||||
if (res == JDR_OK) {
|
||||
/* Decompression succeeded. You have the decompressed image in the frame buffer here. */
|
||||
printf("\rOK \n");
|
||||
// for(int j = 0; j<3 * jdec.width * jdec.height;j++)
|
||||
// {
|
||||
// printf("%d,",*(devid.fbuf+j));
|
||||
// }
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Failed to decompress: rc=%d\n", res);
|
||||
}
|
||||
|
||||
if(devid.fbuf != NULL)
|
||||
{
|
||||
free(devid.fbuf); /* Discard frame buffer */
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Failed to prepare: rc=%d\n", res);
|
||||
}
|
||||
|
||||
__exit:
|
||||
if(work != NULL)
|
||||
{
|
||||
free(work); /* Discard work area */
|
||||
}
|
||||
|
||||
fclose(devid.fp); /* Close the JPEG file */
|
||||
|
||||
return res;
|
||||
}
|
||||
#ifdef __RT_THREAD_H__
|
||||
MSH_CMD_EXPORT(Jpeg_Dec, Jpeg Decode Test);
|
||||
#endif
|
||||
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
#include <stdarg.h>
|
||||
|
||||
/**
|
||||
* Predict class for features vector
|
||||
*/
|
||||
int predict(float *x)
|
||||
{
|
||||
if (x[2] <= 2.449999988079071) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
else {
|
||||
if (x[3] <= 1.75) {
|
||||
if (x[2] <= 4.950000047683716) {
|
||||
if (x[3] <= 1.6500000357627869) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
if (x[3] <= 1.550000011920929) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
else {
|
||||
if (x[2] <= 5.450000047683716) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
if (x[2] <= 4.8500001430511475) {
|
||||
if (x[1] <= 3.100000023841858) {
|
||||
return 2;
|
||||
}
|
||||
|
||||
else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
config IRIS_ML_DEMO
|
||||
bool "enable apps/iris ml demo"
|
||||
default n
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
#include <stdarg.h>
|
||||
|
||||
/**
|
||||
* Compute dot product
|
||||
*/
|
||||
float dot(float *x, ...)
|
||||
{
|
||||
va_list w;
|
||||
va_start(w, 4);
|
||||
float dot = 0.0;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
const float wi = va_arg(w, double);
|
||||
dot += x[i] * wi;
|
||||
}
|
||||
|
||||
return dot;
|
||||
}
|
||||
|
||||
/**
|
||||
* Predict class for features vector
|
||||
*/
|
||||
int predict(float *x)
|
||||
{
|
||||
float votes[3] = {0.0f};
|
||||
votes[0] = dot(x, -0.423405592418, 0.967388282125, -2.517050233286, -1.079182996654) + 9.84868307535428;
|
||||
votes[1] = dot(x, 0.534517184386, -0.321908835083, -0.206465997471, -0.944448257908) + 2.238120068472271;
|
||||
votes[2] = dot(x, -0.111111591968, -0.645479447042, 2.723516230758, 2.023631254562) + -12.086803143826813;
|
||||
// return argmax of votes
|
||||
int classIdx = 0;
|
||||
float maxVotes = votes[0];
|
||||
|
||||
for (int i = 1; i < 3; i++) {
|
||||
if (votes[i] > maxVotes) {
|
||||
classIdx = i;
|
||||
maxVotes = votes[i];
|
||||
}
|
||||
}
|
||||
|
||||
return classIdx;
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
# Machine learning demo using iris dataset
|
||||
|
||||
### Classification task demo, tested on stm32f4 and k210-based edge devices. Training on iris dataset by *Decision Tree classifier*, *Support Vector Machine classifier* and *Logistic Regression classifier*.
|
||||
|
||||
---
|
||||
|
||||
## Training
|
||||
|
||||
Model generated by [Sklearn](https://scikit-learn.org/stable/) and converted to C language by [micromlgen](https://forgeplus.trustie.net/projects/yangtuo250/micromlgen).
|
||||
|
||||
### Enviroment preparation
|
||||
|
||||
```shell
|
||||
pip install scikit-learn
|
||||
git clone https://git.trustie.net/yangtuo250/micromlgen.git -b C
|
||||
cd micromlgen && pip install -e .
|
||||
```
|
||||
|
||||
### Train it!
|
||||
|
||||
```python
|
||||
# load iris dataset
|
||||
from sklearn.datasets import load_iris
|
||||
X, y = load_iris(return_X_y=True)
|
||||
|
||||
# train SVC classifier and convert
|
||||
clf = SVC(kernel='linear', gamma=0.001).fit(X, y)
|
||||
print(port(clf, cplusplus=False, platform=platforms.STM32F4))
|
||||
|
||||
# train logistic regression classifier and convert
|
||||
clf = LogisticRegression(max_iter=1000).fit(X, y)
|
||||
print(port(clf, cplusplus=False, platform=platforms.STM32F4))
|
||||
|
||||
# train decision tree classifier and convert
|
||||
clf = DecisionTreeClassifier().fit(X, y)
|
||||
print(port(clf, cplusplus=False, platform=platforms.STM32F4)
|
||||
```
|
||||
Copy each content generated by print to a single C language file.
|
||||
|
||||
---
|
||||
|
||||
## Deployment
|
||||
|
||||
### compile and burn
|
||||
|
||||
Use `(scons --)menuconfig` in *bsp folder(Ubiquitous/RT_Thread/bsp/k210(or stm32f407-atk-coreboard))*, open **APP_Framwork --> Applications --> knowing app --> enable apps/iris ml demo** to enable this app. `scons -j(n)` to compile and burn in by *st-flash(for ARM)* or *kflash(for k210)*.
|
||||
|
||||
### testing set
|
||||
|
||||
Copy *iris.csv* to SD card */csv/iris.csv*.
|
||||
|
||||
---
|
||||
|
||||
## Run
|
||||
|
||||
In serial terminal:
|
||||
- `iris_SVC_predict` for SVC prediction
|
||||
- `iris_DecisonTree_predict` for decision tree prediction
|
||||
- `iris_LogisticRegression_predict` for logistic regression prediction
|
||||
|
||||
Example output:
|
||||
|
||||
```shell
|
||||
data 1: 5.1000 3.5000 1.4000 0.2000 result: 0
|
||||
data 2: 6.4000 3.2000 4.5000 1.5000 result: 1
|
||||
data 3: 5.8000 2.7000 5.1000 1.9000 result: 2
|
||||
data 4: 7.7000 3.8000 6.7000 2.2000 result: 2
|
||||
data 5: 5.5000 2.6000 4.4000 1.2000 result: 1
|
||||
data 6: 5.1000 3.8000 1.9000 0.4000 result: 0
|
||||
data 7: 5.8000 2.7000 3.9000 1.2000 result: 1
|
||||
```
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c') + Glob('*.cpp')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('Applications', src, depend = ['IRIS_ML_DEMO'], LOCAL_CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
/**
|
||||
* SVC model trained by iris dataset
|
||||
*/
|
||||
#include <stdarg.h>
|
||||
|
||||
/**
|
||||
* Compute kernel between feature vector and support vector.
|
||||
* Kernel type: linear
|
||||
*/
|
||||
float compute_kernel(float *x, ...)
|
||||
{
|
||||
va_list w;
|
||||
va_start(w, 4);
|
||||
float kernel = 0.0;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
kernel += x[i] * va_arg(w, double);
|
||||
}
|
||||
|
||||
return kernel;
|
||||
}
|
||||
|
||||
/**
|
||||
* Predict class for features vector
|
||||
*/
|
||||
int predict(float *x)
|
||||
{
|
||||
float kernels[27] = {0};
|
||||
float decisions[3] = {0};
|
||||
int votes[3] = {0};
|
||||
kernels[0] = compute_kernel(x, 5.1, 3.3, 1.7, 0.5);
|
||||
kernels[1] = compute_kernel(x, 4.8, 3.4, 1.9, 0.2);
|
||||
kernels[2] = compute_kernel(x, 4.5, 2.3, 1.3, 0.3);
|
||||
kernels[3] = compute_kernel(x, 6.9, 3.1, 4.9, 1.5);
|
||||
kernels[4] = compute_kernel(x, 6.3, 3.3, 4.7, 1.6);
|
||||
kernels[5] = compute_kernel(x, 6.1, 2.9, 4.7, 1.4);
|
||||
kernels[6] = compute_kernel(x, 5.6, 3.0, 4.5, 1.5);
|
||||
kernels[7] = compute_kernel(x, 6.2, 2.2, 4.5, 1.5);
|
||||
kernels[8] = compute_kernel(x, 5.9, 3.2, 4.8, 1.8);
|
||||
kernels[9] = compute_kernel(x, 6.3, 2.5, 4.9, 1.5);
|
||||
kernels[10] = compute_kernel(x, 6.8, 2.8, 4.8, 1.4);
|
||||
kernels[11] = compute_kernel(x, 6.7, 3.0, 5.0, 1.7);
|
||||
kernels[12] = compute_kernel(x, 6.0, 2.7, 5.1, 1.6);
|
||||
kernels[13] = compute_kernel(x, 5.4, 3.0, 4.5, 1.5);
|
||||
kernels[14] = compute_kernel(x, 5.1, 2.5, 3.0, 1.1);
|
||||
kernels[15] = compute_kernel(x, 4.9, 2.5, 4.5, 1.7);
|
||||
kernels[16] = compute_kernel(x, 6.5, 3.2, 5.1, 2.0);
|
||||
kernels[17] = compute_kernel(x, 6.0, 2.2, 5.0, 1.5);
|
||||
kernels[18] = compute_kernel(x, 6.3, 2.7, 4.9, 1.8);
|
||||
kernels[19] = compute_kernel(x, 6.2, 2.8, 4.8, 1.8);
|
||||
kernels[20] = compute_kernel(x, 6.1, 3.0, 4.9, 1.8);
|
||||
kernels[21] = compute_kernel(x, 7.2, 3.0, 5.8, 1.6);
|
||||
kernels[22] = compute_kernel(x, 6.3, 2.8, 5.1, 1.5);
|
||||
kernels[23] = compute_kernel(x, 6.0, 3.0, 4.8, 1.8);
|
||||
kernels[24] = compute_kernel(x, 6.3, 2.5, 5.0, 1.9);
|
||||
kernels[25] = compute_kernel(x, 6.5, 3.0, 5.2, 2.0);
|
||||
kernels[26] = compute_kernel(x, 5.9, 3.0, 5.1, 1.8);
|
||||
decisions[0] = 1.452844496978 + kernels[0] * 0.67075289031 + kernels[2] * 0.077097563476 + kernels[14] * -0.747850453786;
|
||||
decisions[1] = 1.507713125178 + kernels[0] * 0.043820415076 + kernels[1] * 0.159872086718 + kernels[15] * -0.203692501794;
|
||||
decisions[2] = 6.78097118511 + kernels[3] + kernels[4] + kernels[5] + kernels[6] + kernels[7] + kernels[8] + kernels[9] +
|
||||
kernels[10] * 0.243261886421 + kernels[11] + kernels[12] + kernels[13] - kernels[15] - kernels[16] -
|
||||
kernels[17] - kernels[18] - kernels[19] - kernels[20] + kernels[21] * -0.437859817863 - kernels[22] -
|
||||
kernels[23] + kernels[24] * -0.645105347981 + kernels[25] * -0.160296720576 - kernels[26];
|
||||
votes[decisions[0] > 0 ? 0 : 1] += 1;
|
||||
votes[decisions[1] > 0 ? 0 : 2] += 1;
|
||||
votes[decisions[2] > 0 ? 1 : 2] += 1;
|
||||
int val = votes[0];
|
||||
int idx = 0;
|
||||
|
||||
for (int i = 1; i < 3; i++) {
|
||||
if (votes[i] > val) {
|
||||
val = votes[i];
|
||||
idx = i;
|
||||
}
|
||||
}
|
||||
|
||||
return idx;
|
||||
}
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
5.1,3.5,1.4,0.2
|
||||
6.4,3.2,4.5,1.5
|
||||
5.8,2.7,5.1,1.9
|
||||
7.7,3.8,6.7,2.2
|
||||
5.5,2.6,4.4,1.2
|
||||
5.1,3.8,1.9,0.4
|
||||
5.8,2.7,3.9,1.2
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
#include <string.h>
|
||||
#include <transform.h>
|
||||
|
||||
#define FEATURE_NUM 4
|
||||
#define CSV_PATH "/csv/iris.csv"
|
||||
#define CSV_BUFFER_SIZE (1 * 1024)
|
||||
|
||||
static float data[10][FEATURE_NUM] = {};
|
||||
static int data_len = 0;
|
||||
|
||||
void simple_CSV_read()
|
||||
{
|
||||
int fin;
|
||||
int col = 0;
|
||||
char buffer[CSV_BUFFER_SIZE] = "";
|
||||
char *tmp = "";
|
||||
char *delim = ",\n ";
|
||||
|
||||
fin = open(CSV_PATH, O_RDONLY);
|
||||
if (!fin) {
|
||||
printf("Error open file %s", CSV_PATH);
|
||||
// exit(-1);
|
||||
return;
|
||||
}
|
||||
read(fin, buffer, sizeof(buffer));
|
||||
close(fin);
|
||||
|
||||
data_len = 0;
|
||||
for (tmp = strtok(buffer, delim); tmp && *tmp; col++, tmp = strtok(NULL, delim)) {
|
||||
if (0 == col % FEATURE_NUM) {
|
||||
// printf("\n");
|
||||
data_len++;
|
||||
col = 0;
|
||||
}
|
||||
data[data_len - 1][col] = atof(tmp);
|
||||
// printf("%.4f ", data[data_len - 1][col]);
|
||||
}
|
||||
// printf("\n");
|
||||
}
|
||||
|
||||
void iris_SVC_predict()
|
||||
{
|
||||
#include "SVCModel.h"
|
||||
int result;
|
||||
|
||||
simple_CSV_read();
|
||||
|
||||
for (int i = 0; i < data_len; i++) {
|
||||
result = predict(data[i]);
|
||||
printf("data %d: ", i + 1);
|
||||
for (int j = 0; j < FEATURE_NUM; j++) {
|
||||
printf("%.4f ", data[i][j]);
|
||||
}
|
||||
printf("result: %d\n", result);
|
||||
}
|
||||
}
|
||||
#ifdef __RT_THREAD_H__
|
||||
MSH_CMD_EXPORT(iris_SVC_predict, iris predict by SVC);
|
||||
#endif
|
||||
|
||||
void iris_DecisonTree_predict()
|
||||
{
|
||||
#include "DecisionTreeClassifierModel.h"
|
||||
int result;
|
||||
|
||||
simple_CSV_read();
|
||||
|
||||
for (int i = 0; i < data_len; i++) {
|
||||
result = predict(data[i]);
|
||||
printf("data %d: ", i + 1);
|
||||
for (int j = 0; j < FEATURE_NUM; j++) {
|
||||
printf("%.4f ", data[i][j]);
|
||||
}
|
||||
printf("result: %d\n", result);
|
||||
}
|
||||
}
|
||||
#ifdef __RT_THREAD_H__
|
||||
MSH_CMD_EXPORT(iris_DecisonTree_predict, iris predict by decison tree classifier);
|
||||
#endif
|
||||
|
||||
void iris_LogisticRegression_predict()
|
||||
{
|
||||
#include "LogisticRegressionModel.h"
|
||||
int result;
|
||||
|
||||
simple_CSV_read();
|
||||
|
||||
for (int i = 0; i < data_len; i++) {
|
||||
result = predict(data[i]);
|
||||
printf("data %d: ", i + 1);
|
||||
for (int j = 0; j < FEATURE_NUM; j++) {
|
||||
printf("%.4f ", data[i][j]);
|
||||
}
|
||||
printf("result: %d\n", result);
|
||||
}
|
||||
}
|
||||
#ifdef __RT_THREAD_H__
|
||||
MSH_CMD_EXPORT(iris_LogisticRegression_predict, iris predict by logistic regression);
|
||||
#endif
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
config K210_DETECT_ENTRY
|
||||
bool "enable apps/k210 yolov2 detect entry"
|
||||
depends on BOARD_K210_EVB
|
||||
depends on DRV_USING_OV2640
|
||||
depends on USING_KPU_PROCESSING
|
||||
depends on USING_YOLOV2
|
||||
depends on USING_YOLOV2_JSONPARSER
|
||||
depends on USING_K210_YOLOV2_DETECT
|
||||
select LIB_USING_CJSON
|
||||
default n
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
# Face detection demo
|
||||
|
||||
### A face object detection task demo. Running MobileNet-yolo on K210-based edge devices.
|
||||
|
||||
---
|
||||
|
||||
## Training
|
||||
|
||||
kmodel from [GitHub](https://github.com/kendryte/kendryte-standalone-demo/blob/develop/face_detect/detect.kmodel).
|
||||
|
||||
## Deployment
|
||||
|
||||
### compile and burn
|
||||
|
||||
Use `(scons --)menuconfig` in bsp folder *(Ubiquitous/RT_Thread/bsp/k210)*, open:
|
||||
|
||||
- More Drivers --> ov2640 driver
|
||||
- Board Drivers Config --> Enable LCD on SPI0
|
||||
- Board Drivers Config --> Enable SDCARD (spi1(ss0))
|
||||
- Board Drivers Config --> Enable DVP(camera)
|
||||
- RT-Thread Components --> POSIX layer and C standard library --> Enable pthreads APIs
|
||||
- APP_Framework --> Framework --> support knowing framework --> kpu model postprocessing --> yolov2 region layer
|
||||
- APP_Framework --> Applications --> knowing app --> enable apps/face detect
|
||||
|
||||
`scons -j(n)` to compile and burn in by *kflash*.
|
||||
|
||||
### json config and kmodel
|
||||
|
||||
Copy json config for deployment o SD card */kmodel*. Example config file is *detect.json* in this directory. Copy final kmodel to SD card */kmodel* either.
|
||||
|
||||
---
|
||||
|
||||
## Run
|
||||
|
||||
In serial terminal, `face_detect` to start a detection thread, `face_detect_delete` to stop it. Detection results can be found in output.
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c') + Glob('*.cpp')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('Applications', src, depend = ['USING_K210_YOLOV2_DETECT'], LOCAL_CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"net_input_size": [
|
||||
240,
|
||||
320
|
||||
],
|
||||
"net_output_shape": [
|
||||
20,
|
||||
15,
|
||||
30
|
||||
],
|
||||
"sensor_output_size": [
|
||||
240,
|
||||
320
|
||||
],
|
||||
"anchors": [
|
||||
1.889,
|
||||
2.5245,
|
||||
2.9465,
|
||||
3.94056,
|
||||
3.99987,
|
||||
5.3658,
|
||||
5.155437,
|
||||
6.92275,
|
||||
6.718375,
|
||||
9.01025
|
||||
],
|
||||
"kmodel_size": 388776,
|
||||
"obj_thresh": [
|
||||
0.7
|
||||
],
|
||||
"labels": [
|
||||
"face"
|
||||
],
|
||||
"nms_thresh": 0.3
|
||||
}
|
||||
Binary file not shown.
|
|
@ -0,0 +1,37 @@
|
|||
{
|
||||
"net_input_size": [
|
||||
256,
|
||||
256
|
||||
],
|
||||
"net_output_shape": [
|
||||
8,
|
||||
8,
|
||||
35
|
||||
],
|
||||
"sensor_output_size": [
|
||||
256,
|
||||
256
|
||||
],
|
||||
"anchors": [
|
||||
0.1384,
|
||||
0.276,
|
||||
0.308,
|
||||
0.504,
|
||||
0.5792,
|
||||
0.8952,
|
||||
1.072,
|
||||
1.6184,
|
||||
2.1128,
|
||||
3.184
|
||||
],
|
||||
"kmodel_size": 2714044,
|
||||
"obj_thresh": [
|
||||
0.7,
|
||||
0.99
|
||||
],
|
||||
"labels": [
|
||||
"head",
|
||||
"helmet"
|
||||
],
|
||||
"nms_thresh": 0.45
|
||||
}
|
||||
Binary file not shown.
|
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"net_input_size": [
|
||||
224,
|
||||
320
|
||||
],
|
||||
"net_output_shape": [
|
||||
10,
|
||||
7,
|
||||
30
|
||||
],
|
||||
"sensor_output_size": [
|
||||
240,
|
||||
320
|
||||
],
|
||||
"anchors": [
|
||||
1.043,
|
||||
1.092,
|
||||
0.839,
|
||||
2.1252,
|
||||
1.109,
|
||||
2.7461,
|
||||
1.378,
|
||||
3.6708,
|
||||
2.049,
|
||||
4.6711
|
||||
],
|
||||
"kmodel_size": 2713236,
|
||||
"obj_thresh": [
|
||||
0.7
|
||||
],
|
||||
"labels": [
|
||||
"human"
|
||||
],
|
||||
"nms_thresh": 0.35
|
||||
}
|
||||
Binary file not shown.
|
|
@ -0,0 +1,16 @@
|
|||
#include "k210_yolov2_detect.h"
|
||||
static void detect_app(int argc, char *argv[])
|
||||
{
|
||||
if (2 != argc) {
|
||||
printf("Usage: detect_app <ABSOLUTE_CONFIG_JSON_PATH>");
|
||||
} else {
|
||||
k210_detect(argv[1]);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
// clang-format off
|
||||
#ifdef __RT_THREAD_H__
|
||||
MSH_CMD_EXPORT(detect_app, k210 detect app usage: detect_app <ABSOLUTE_CONFIG_JSON_PATH>);
|
||||
#endif
|
||||
// clang-format on
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
config K210_FFT_TEST
|
||||
bool "enable apps/k210 fft test"
|
||||
default n
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
############################################################################
|
||||
# APP_Framework/Applications/knowing_app/k210_fft_test/Make.defs
|
||||
############################################################################
|
||||
ifneq ($(CONFIG_K210_FFT_TEST),)
|
||||
CONFIGURED_APPS += $(APPDIR)/../../../APP_Framework/Applications/knowing_app/k210_fft_test
|
||||
endif
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
include $(KERNEL_ROOT)/.config
|
||||
|
||||
ifeq ($(CONFIG_ADD_NUTTX_FETURES),y)
|
||||
include $(APPDIR)/Make.defs
|
||||
|
||||
ifeq ($(CONFIG_K210_FFT_TEST), y)
|
||||
CSRCS += fft_soft.c fft_test.c
|
||||
endif
|
||||
|
||||
include $(APPDIR)/Application.mk
|
||||
|
||||
endif
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
from building import *
|
||||
|
||||
cwd = GetCurrentDir()
|
||||
src = Glob('*.c') + Glob('*.cpp')
|
||||
CPPPATH = [cwd]
|
||||
|
||||
group = DefineGroup('Applications', src, depend = ['K210_FFT_TEST'], LOCAL_CPPPATH = CPPPATH)
|
||||
|
||||
Return('group')
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue