SDK updated

This commit is contained in:
Th3maz1ng 2022-11-01 18:22:10 +01:00
commit c10dc0352f
2306 changed files with 963467 additions and 0 deletions

91
.gitignore vendored Normal file
View File

@ -0,0 +1,91 @@
# ---> C
# Prerequisites
*.d
# Object files
*.o
*.ko
*.obj
*.elf
# Linker output
*.ilk
*.map
*.exp
# Precompiled Headers
*.gch
*.pch
# Libraries
*.lib
*.a
*.la
*.lo
# Shared objects (inc. Windows DLLs)
*.dll
*.so
*.so.*
*.dylib
# Executables
*.exe
*.out
*.app
*.i*86
*.x86_64
*.hex
# Debug files
*.dSYM/
*.su
*.idb
*.pdb
# Kernel Module Compile Results
*.mod*
*.cmd
.tmp_versions/
modules.order
Module.symvers
Mkfile.old
dkms.conf
# ---> C++
# Prerequisites
*.d
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
# Executables
*.exe
*.out
*.app
#Exceptions
bin/w800
!bin/build/w800/lib/

8
.vscode/settings.json vendored Normal file
View File

@ -0,0 +1,8 @@
{
"files.associations": {
"nano_shell_interface.h": "c",
"wm_include.h": "c",
"wm_osal.h": "c",
"wm_os_config.h": "c"
}
}

19
LICENSE Normal file
View File

@ -0,0 +1,19 @@
MIT License Copyright (c) <year> <copyright holders>
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is furnished
to do so, subject to the following conditions:
The above copyright notice and this permission notice (including the next
paragraph) shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS
OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

108
Makefile Normal file
View File

@ -0,0 +1,108 @@
TOP_DIR := .
sinclude $(TOP_DIR)/tools/w800/conf.mk
ifndef PDIR # {
GEN_IMAGES= $(TARGET).elf
GEN_BINS = $(TARGET).bin
SUBDIRS = \
$(TOP_DIR)/app \
$(TOP_DIR)/app/app_lib \
$(TOP_DIR)/app/third_party/nano-shell-master \
$(TOP_DIR)/app/third_party/driver/NRF24L01P
endif # } PDIR
ifndef PDIR # {
ifeq ($(USE_LIB), 0)
SUBDIRS += \
$(TOP_DIR)/platform/arch \
$(TOP_DIR)/platform/common \
$(TOP_DIR)/platform/drivers \
$(TOP_DIR)/platform/sys \
$(TOP_DIR)/src/network \
$(TOP_DIR)/src/os \
$(TOP_DIR)/src/app
ifeq ($(USE_NIMBLE), 1)
SUBDIRS += \
$(TOP_DIR)/src/bt/blehost
else
SUBDIRS += \
$(TOP_DIR)/src/bt/host
endif
endif
endif
COMPONENTS_$(TARGET) = \
$(TOP_DIR)/app/libuser$(LIB_EXT) \
$(TOP_DIR)/app/app_lib/libapplib$(LIB_EXT) \
$(TOP_DIR)/app/third_party/nano-shell-master/libnanoshell$(LIB_EXT) \
$(TOP_DIR)/app/third_party/driver/NRF24L01P/libnrf24l01p$(LIB_EXT)
ifeq ($(USE_LIB), 0)
COMPONENTS_$(TARGET) += \
$(TOP_DIR)/platform/boot/libwmarch$(LIB_EXT) \
$(TOP_DIR)/platform/common/libwmcommon$(LIB_EXT) \
$(TOP_DIR)/platform/drivers/libdrivers$(LIB_EXT) \
$(TOP_DIR)/platform/sys/libwmsys$(LIB_EXT) \
$(TOP_DIR)/src/network/libnetwork$(LIB_EXT) \
$(TOP_DIR)/src/os/libos$(LIB_EXT)
ifeq ($(USE_NIMBLE), 1)
COMPONENTS_$(TARGET) += \
$(TOP_DIR)/src/bt/libblehost$(LIB_EXT) \
$(TOP_DIR)/src/app/libapp$(LIB_EXT)
else
COMPONENTS_$(TARGET) += \
$(TOP_DIR)/src/bt/libbthost_br_edr$(LIB_EXT) \
$(TOP_DIR)/src/app/libapp_br_edr$(LIB_EXT)
endif
endif
LINKLIB = \
$(TOP_DIR)/lib/$(CONFIG_ARCH_TYPE)/libwlan$(LIB_EXT) \
$(TOP_DIR)/lib/$(CONFIG_ARCH_TYPE)/libdsp$(LIB_EXT)
ifeq ($(USE_NIMBLE), 1)
LINKLIB +=$(TOP_DIR)/lib/$(CONFIG_ARCH_TYPE)/libbtcontroller$(LIB_EXT)
else
LINKLIB +=$(TOP_DIR)/lib/$(CONFIG_ARCH_TYPE)/libbtcontroller_br_edr$(LIB_EXT)
endif
ifeq ($(USE_LIB), 1)
LINKLIB += \
$(TOP_DIR)/lib/$(CONFIG_ARCH_TYPE)/libwmarch$(LIB_EXT) \
$(TOP_DIR)/lib/$(CONFIG_ARCH_TYPE)/libwmcommon$(LIB_EXT) \
$(TOP_DIR)/lib/$(CONFIG_ARCH_TYPE)/libdrivers$(LIB_EXT) \
$(TOP_DIR)/lib/$(CONFIG_ARCH_TYPE)/libnetwork$(LIB_EXT) \
$(TOP_DIR)/lib/$(CONFIG_ARCH_TYPE)/libos$(LIB_EXT) \
$(TOP_DIR)/lib/$(CONFIG_ARCH_TYPE)/libwmsys$(LIB_EXT)
ifeq ($(USE_NIMBLE), 1)
LINKLIB += \
$(TOP_DIR)/lib/$(CONFIG_ARCH_TYPE)/libblehost$(LIB_EXT) \
$(TOP_DIR)/lib/$(CONFIG_ARCH_TYPE)/libapp$(LIB_EXT)
else
LINKLIB += \
$(TOP_DIR)/lib/$(CONFIG_ARCH_TYPE)/libbthost_br_edr$(LIB_EXT)\
$(TOP_DIR)/lib/$(CONFIG_ARCH_TYPE)/libapp_br_edr$(LIB_EXT)
endif
endif
LINKFLAGS_$(TARGET) = \
$(LINKLIB)
CONFIGURATION_DEFINES =
DEFINES += \
$(CONFIGURATION_DEFINES)
DDEFINES += \
$(CONFIGURATION_DEFINES)
INCLUDES := $(INCLUDES) -I$(PDIR)include
INCLUDES += -I ./
sinclude $(TOP_DIR)/tools/$(CONFIG_ARCH_TYPE)/rules.mk
.PHONY: FORCE
FORCE:

9
README.md Normal file
View File

@ -0,0 +1,9 @@
# W801_SDK_dev_env
## What does this repository contain ?
This repository contains a working dev environment for the W801 MCU.
It is a test platforme where I can try and learn the provided SDK API.
So the software doesn't serve a particular purpose, it's more of a playing field.
## Getting started:
TODO

15
app/Makefile Normal file
View File

@ -0,0 +1,15 @@
TOP_DIR = ..
sinclude $(TOP_DIR)/tools/w800/conf.mk
ifndef PDIR
GEN_LIBS = libuser$(LIB_EXT)
endif
#DEFINES +=
sinclude $(TOP_DIR)/tools/w800/rules.mk
INCLUDES := $(INCLUDES) -I $(PDIR)include
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile

15
app/app_lib/Makefile Normal file
View File

@ -0,0 +1,15 @@
TOP_DIR = ../..
sinclude $(TOP_DIR)/tools/w800/conf.mk
ifndef PDIR
GEN_LIBS = libapplib$(LIB_EXT)
endif
#DEFINES +=
sinclude $(TOP_DIR)/tools/w800/rules.mk
INCLUDES := $(INCLUDES) -I $(PDIR)include
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile

13
app/app_lib/app_utils.c Normal file
View File

@ -0,0 +1,13 @@
#include "app_utils.h"
static uint32_t millis_cnt = 0;
uint32_t millis(void)
{
return millis_cnt;
}
void millis_run_cb(void *arg)
{
millis_cnt++;
}

10
app/app_lib/app_utils.h Normal file
View File

@ -0,0 +1,10 @@
#ifndef APP_UTILS_H
#define APP_UTILS_H
#include "wm_include.h"
uint32_t millis(void);
void millis_run_cb(void *arg);
#endif //APP_UTILS_H

270
app/main.c Normal file
View File

@ -0,0 +1,270 @@
/*****************************************************************************
*
* File Name : main.c
*
* Description: main
*
* Copyright (c) 2014 Winner Micro Electronic Design Co., Ltd.
* All rights reserved.
*
* Author : dave
*
* Date : 2014-6-14
*****************************************************************************/
#include <string.h>
#include "nano_shell_server_task.h"
#include "wm_include.h"
#include "wm_gpio_afsel.h"
#include "nano_shell.h"
#include "nano_shell_interface.h"
#include "lwip/netif.h"
#include "FreeRTOS.h"
#include "FreeRTOSConfig.h"
#include "app_common.h"
#include "NRF24L01P.h"
#include "app_utils.h"
tls_os_task_t nano_shell_task_handle = NULL;
tls_os_task_t nano_shell_server_task_handle = NULL;
extern s16 uart0_rx_callback(u16 len, void *user_data);
extern s16 uart1_rx_callback(u16 len, void *user_data);
#define NANO_SHELL_TASK_STK_SIZE 640
#define NANO_SHELL_SERVER_TASK_STK_SIZE 640
#define PWM_STATUS_LED WM_IO_PB_25
#define FADE_DOWN 1
#define FADE_UP -1
#define FADE_LOW_THRESHOLD 255
#define FADE_HIGH_THRESHOLD 200
#define PULSE_FAST 3
#define PULSE_SLOW 12
u8 pulse_rate = PULSE_SLOW;
bool nrf_irq = false;
void tls_netif_status_event_cb(u8 status)
{
struct netif *netif = tls_get_netif();
switch(status)
{
case NETIF_WIFI_JOIN_SUCCESS:
shell_printf("Evt : NETIF_WIFI_JOIN_SUCCESS"NEW_LINE);
break;
case NETIF_WIFI_JOIN_FAILED:
shell_printf("Evt : NETIF_WIFI_JOIN_FAILED"NEW_LINE);
break;
case NETIF_WIFI_DISCONNECTED:
shell_printf("Evt : NETIF_WIFI_DISCONNECTED"NEW_LINE);
pulse_rate = PULSE_SLOW;
break;
case NETIF_IP_NET_UP:
shell_printf("Evt : NETIF_IP_NET_UP"NEW_LINE"ip addr : %v"NEW_LINE"netmask : %v"NEW_LINE"gateway : %v"NEW_LINE, netif->ip_addr.addr,
netif->netmask.addr,
netif->gw.addr);
pulse_rate = PULSE_FAST;
break;
case NETIF_WIFI_SOFTAP_SUCCESS:
shell_printf("Evt : NETIF_WIFI_SOFTAP_SUCCESS"NEW_LINE);
break;
case NETIF_WIFI_SOFTAP_FAILED:
shell_printf("Evt : NETIF_WIFI_SOFTAP_FAILED"NEW_LINE);
break;
case NETIF_WIFI_SOFTAP_CLOSED:
shell_printf("Evt : NETIF_WIFI_SOFTAP_CLOSED"NEW_LINE);
pulse_rate = PULSE_SLOW;
break;
case NETIF_IP_NET2_UP:
shell_printf("Evt : NETIF_IP_NET2_UP"NEW_LINE"ip addr : %v"NEW_LINE"netmask : %v"NEW_LINE"gateway : %v"NEW_LINE, netif->next->ip_addr.addr,
netif->next->netmask.addr,
netif->next->gw.addr);
pulse_rate = PULSE_FAST;
break;
case NETIF_IPV6_NET_UP:
shell_printf("Evt : NETIF_IPV6_NET_UP"NEW_LINE);
break;
default:
shell_printf("Evt : UNKNOWN"NEW_LINE);
break;
}
}
void touchsensor_cb(u32 status)
{
shell_printf("Touch detected : status(%u)"NEW_LINE, status);
}
void tls_gpio_irq_cb(void *arg)
{
tls_clr_gpio_irq_status(WM_IO_PB_07);
}
void tls_gpio_pb11_irq_cb(void *arg)
{
tls_clr_gpio_irq_status(WM_IO_PB_11);
nrf_irq = true;
}
void delay_ms(uint32_t ms)
{
tls_os_time_delay(pdMS_TO_TICKS(ms));
}
uint32_t elapsed_ms(void)
{
return millis();
}
void CE_HIGH(void)
{
tls_gpio_write(WM_IO_PB_10, 1);
}
void CE_LOW(void)
{
tls_gpio_write(WM_IO_PB_10, 0);
}
void user_main(void *param)
{
u8 pwm_led_duty_cycle = 255;
s8 fading_direction = FADE_UP;
//We initialize input/output used by the app
wm_pwm3_config(PWM_STATUS_LED);
tls_pwm_init(3, 1000, 0, 0);
wm_uart1_tx_config(WM_IO_PB_06);
wm_uart1_rx_config(WM_IO_PB_07);
tls_gpio_irq_enable(WM_IO_PB_07, WM_GPIO_IRQ_TRIG_DOUBLE_EDGE);
tls_gpio_isr_register(WM_IO_PB_07, &(tls_gpio_irq_cb), NULL);
//We set a a pin as touch sensor :
wm_touch_sensor_config(WM_IO_PA_07);
tls_touchsensor_threshold_config(1, 120);
tls_touchsensor_init_config(1, 16, 16,1);
tls_touchsensor_irq_enable(1);
tls_touchsensor_irq_register(&(touchsensor_cb));
//We set the CE and IRQ pin for the NRF module
tls_gpio_cfg(WM_IO_PB_10, WM_GPIO_DIR_OUTPUT, WM_GPIO_ATTR_FLOATING); //CE pin
tls_gpio_cfg(WM_IO_PB_11, WM_GPIO_DIR_INPUT, WM_GPIO_ATTR_FLOATING); //IRQ pins
tls_gpio_irq_enable(WM_IO_PB_11, WM_GPIO_IRQ_TRIG_FALLING_EDGE);
tls_gpio_isr_register(WM_IO_PB_11, &(tls_gpio_pb11_irq_cb), NULL);
//We init the uart 1
tls_uart_port_init(TLS_UART_1, NULL, 0);
//We create and start a timer to run the millis counter
struct tls_timer_cfg tmr_millis = {0};
tmr_millis.arg = NULL;
tmr_millis.is_repeat = true;
tmr_millis.timeout = 1;
tmr_millis.unit = TLS_TIMER_UNIT_MS;
tmr_millis.callback = &(millis_run_cb);
u8 tmr_millis_id = tls_timer_create(&tmr_millis);
tls_timer_start(tmr_millis_id);
//We create a task for the nano_shell process
u8 *nano_shell_task_stack = NULL, *nano_shell_server_task_stack = NULL;
tls_uart_rx_callback_register(TLS_UART_0, &(uart0_rx_callback), NULL);
tls_uart_rx_callback_register(TLS_UART_1, &(uart1_rx_callback), NULL);
//we test the NRF lib here
/*NRF24L01P_t NRF;
shell_printf("Checking NRF setup."NEW_LINE);
shell_printf("Setting SPI to 1 Mhz : %d."NEW_LINE, tls_spi_setup(SPI_DEFAULT_MODE, SPI_CS_ACTIVE_MODE, 8000000));
shell_printf("NRF begin : %d."NEW_LINE, NRF24L01P_begin(&NRF));
shell_printf("Is NRF connected : %d."NEW_LINE, NRF24L01P_isChipConnected(&NRF));
//NRF24L01P_setChannel(&NRF, 2);
NRF24L01P_setPALevel(&NRF, RF24_PA_LOW, false);
//NRF24L01P_setDataRate(&NRF, RF24_250KBPS);
//NRF24L01P_setRetries(&NRF, 8, 15);
NRF24L01P_enableDynamicPayloads(&NRF);
NRF24L01P_enableAckPayload(&NRF);
NRF24L01P_maskIRQ(&NRF, true, true, false);
const uint8_t ADDR[5] = {0xE7, 0xE7, 0xE7, 0xE7, 0xE7};
const uint8_t ack_pl[] = "1234567";
NRF24L01P_openWritingPipe(&NRF, "1Node");
NRF24L01P_openReadingPipe(&NRF, 1, "2Node");
NRF24L01P_writeAckPayload(&NRF, 1, ack_pl, sizeof ack_pl);
NRF24L01P_startListening(&NRF);
shell_printf("NRF PA level : %d"NEW_LINE, NRF24L01P_getPALevel(&NRF));
NRF24L01P_printDetails(&NRF);*/
//uint8_t payload[32] = "Hello W801";
//shell_printf("Sending payload : %d"NEW_LINE, NRF24L01P_write(&NRF, payload, sizeof payload));
//NRF24L01P_printDetails(&NRF);
nano_shell_server_task_stack = tls_mem_alloc(sizeof(u32) * NANO_SHELL_SERVER_TASK_STK_SIZE);
if(nano_shell_server_task_stack != NULL)
{
tls_os_status_t status = tls_os_task_create(
&nano_shell_server_task_handle,
"shll_srv",
&(nano_shell_server_task),
NULL,
(void*) nano_shell_server_task_stack,
NANO_SHELL_SERVER_TASK_STK_SIZE * sizeof(u32_t),
62,
0
);
if(status != TLS_OS_SUCCESS)
shell_printf("Failed to create nano shell server task."NEW_LINE);
}
nano_shell_task_stack = tls_mem_alloc(sizeof(u32) * NANO_SHELL_TASK_STK_SIZE);
if(nano_shell_task_stack != NULL)
{
tls_os_task_create(
&nano_shell_task_handle,
"na_shell",
&(nano_shell_loop),
NULL,
(void*) nano_shell_task_stack,
NANO_SHELL_TASK_STK_SIZE * sizeof(u32),
62,
0
);
}
shell_printf("Registering netif callback."NEW_LINE);
tls_netif_add_status_event(&(tls_netif_status_event_cb));
for(;;)
{
tls_pwm_duty_set(3, pwm_led_duty_cycle);
if(pwm_led_duty_cycle == FADE_LOW_THRESHOLD)
{
fading_direction = FADE_UP;
tls_os_time_delay(pdMS_TO_TICKS(pulse_rate == PULSE_SLOW ? 500 : 100));
}
else if(pwm_led_duty_cycle == FADE_HIGH_THRESHOLD)
{
fading_direction = FADE_DOWN;
tls_os_time_delay(pdMS_TO_TICKS(pulse_rate == PULSE_SLOW ? 500 : 100));
}
pwm_led_duty_cycle+=fading_direction;
tls_os_time_delay(pdMS_TO_TICKS(pulse_rate));
/*if(nrf_irq)
{
bool tx_ok, tx_fail, rx_ready;
NRF24L01P_whatHappened(&NRF, &tx_ok, &tx_fail, &rx_ready);
shell_printf("NRF event : tx_ok %d, tx_fail %d and rx_ready : %d, rx fifo full ? %u, tx fifo full ? %u"NEW_LINE, tx_ok, tx_fail, rx_ready, NRF24L01P_rxFifoFull(&NRF), NRF24L01P_txFifoFull(&NRF));
if(NRF24L01P_available(&NRF))
{
char payload[32] = "";
NRF24L01P_read(&NRF, payload, 8);
shell_printf("Received : #%s#\r\n", payload);
NRF24L01P_writeAckPayload(&NRF, 1, ack_pl, sizeof ack_pl);
}
nrf_irq = false;
}*/
}
}

623
app/nano_shell_command.c Normal file
View File

@ -0,0 +1,623 @@
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include "command/command.h"
#include "wm_include.h"
#include "FreeRTOS.h"
#include "task.h"
#include "lwip/netif.h"
#include "app_common.h"
#include "nano_shell_interface.h"
#include "wm_gpio_afsel.h"
extern int wm_printf(const char *fmt,...);
extern u32 tls_mem_get_avail_heapsize(void);
extern bool disconnect_client(void);
extern int demo_bt_enable();
extern int demo_bt_destroy();
extern int demo_ble_server_on();
extern int demo_ble_server_off();
void tls_wifi_client_event_cb(u8 *mac, enum tls_wifi_client_event_type event)
{
struct tls_sta_info_t *mac_addr = (struct tls_sta_info_t *)mac;
shell_printf("Client event(%d), MAC : %M"NEW_LINE, event, mac_addr);
}
void wifi_scan_result_cb(void)
{
u16 buffer_size = sizeof(struct tls_scan_bss_t) + sizeof(struct tls_bss_info_t) * 20;
u8 *buf = tls_mem_alloc(buffer_size);
if(buf == NULL)
{
shell_printf("Failed to allocate result buffer"NEW_LINE);
return;
}
struct tls_scan_bss_t *scan_result = (struct tls_scan_bss_t *)buf;
struct tls_bss_info_t *station_list = scan_result->bss;
tls_wifi_get_scan_rslt(buf, buffer_size);
shell_printf("Found %u nearby station(s) - info size(%u/%u)"NEW_LINE,
scan_result->count,
scan_result->length,
buffer_size);
for(u8 i = 0; i < scan_result->count; i++)
{
station_list[i].ssid[station_list[i].ssid_len] = '\0';
shell_printf("station %u :"NEW_LINE"SSID : %s"NEW_LINE"BSSID : %02X:%02X:%02X:%02X:%02X:%02X"NEW_LINE"RSSI : %d dB"NEW_LINE"Channel : %u"NEW_LINE"Max DR : %u Mbps"NEW_LINE"Mode %u"NEW_LINE"Auth :%u"NEW_LINE"WPS supported : %u"NEW_LINE NEW_LINE,
i,
(char *)station_list[i].ssid,
station_list[i].bssid[0], station_list[i].bssid[1], station_list[i].bssid[2], station_list[i].bssid[3], station_list[i].bssid[4], station_list[i].bssid[5],
(s8)station_list[i].rssi,
station_list[i].channel,
station_list[i].max_data_rate,
station_list[i].mode,
station_list[i].privacy,
station_list[i].wps_support);
}
tls_mem_free(buf);
}
void tls_wifi_data_ext_recv_cb(u8* data, u32 data_len, struct tls_wifi_ext_t *ext)
{
shell_printf("recv packet :"NEW_LINE"rssi : %d\nrate : %u"NEW_LINE, (s8)ext->rssi, ext->rx_rate);
for(u32 i = 0; i < data_len; i++)
{
shell_printf("%02X", data[i]);
if(i % 30 == 0)
shell_printf(NEW_LINE);
}
shell_printf(NEW_LINE);
}
void tls_rtc_irq_cb(void *arg)
{
struct tm rtc_time;
tls_get_rtc(&rtc_time);
shell_printf("rtc isr called"NEW_LINE"time is :"NEW_LINE"%d:%d:%d %d/%d/%d"NEW_LINE,
rtc_time.tm_hour,
rtc_time.tm_min,
rtc_time.tm_sec,
rtc_time.tm_mday,
rtc_time.tm_mon,
rtc_time.tm_year);
tls_rtc_timer_stop();
}
int _system(const shell_cmd_t *pcmd, int argc, char *const argv[])
{
if(argc > 1)
{
if(strcmp(argv[1], "list_task") == 0)
{
char *buf = NULL;
buf = tls_mem_alloc(1024);
if(NULL == buf)
return 0;
#if configUSE_TRACE_FACILITY
vTaskList(buf);
#endif
shell_printf(NEW_LINE"%s"NEW_LINE"buf_len : %d"NEW_LINE, buf, strlen(buf));
tls_mem_free(buf);
buf = NULL;
}
else if(strcmp(argv[1], "ram_usage") == 0)
{
shell_printf("Free OS heap : %u/%u byte(s)"NEW_LINE"tls heap size : %u"NEW_LINE, xPortGetFreeHeapSize(), configTOTAL_HEAP_SIZE, tls_mem_get_avail_heapsize());
}
else
{
shell_printf("Unknown %s action"NEW_LINE, argv[0]);
}
}
else
{
shell_printf("List of system actions :"NEW_LINE"list_task"NEW_LINE"ram_usage"NEW_LINE);
}
return 0;
}
int _reset(const shell_cmd_t *pcmd, int argc, char *const argv[])
{
tls_sys_reset();
return 0;
}
int _bus(const shell_cmd_t *pcmd, int argc, char *const argv[])
{
char spi_recv_buff[32] = "";
u32 fclk = SPI_DEFAULT_SPEED;
if(argc > 1)
{
if(strcmp(argv[1], "spi_init") == 0)
{
if(argc == 3)
{
fclk = strtoul(argv[2], NULL, 10);
if(!fclk) fclk = SPI_DEFAULT_SPEED;
}
shell_printf("SPI init : %d, clk -> %u Hz"NEW_LINE, tls_spi_setup(SPI_DEFAULT_MODE, SPI_CS_ACTIVE_MODE, fclk), fclk);
}
else if(strcmp(argv[1], "spi_w") == 0)
{
shell_printf("Writing [%s](len : %d) to SPI"NEW_LINE, argv[2], strlen(argv[2]));
if(tls_spi_write((u8*)argv[2], strlen(argv[2])) != TLS_SPI_STATUS_OK)
{
shell_printf("Failed to write to SPI"NEW_LINE);
return 0;
}
}
else if(strcmp(argv[1], "spi_r") == 0)
{
if(tls_spi_read((u8*)spi_recv_buff, sizeof(spi_recv_buff) - 1) != TLS_SPI_STATUS_OK)
{
shell_printf("Failed to read from SPI"NEW_LINE);
return 0;
}
shell_printf("Received [%s](len : %d) from SPI"NEW_LINE, spi_recv_buff, strlen(spi_recv_buff));
}
else if(strcmp(argv[1], "spi_wr") == 0)
{
if(tls_spi_read_with_cmd((u8 *) argv[2], strlen(argv[2]), (u8 *) spi_recv_buff, sizeof(spi_recv_buff) - 1) != TLS_SPI_STATUS_OK)
{
shell_printf("Failed to write & read combo using SPI"NEW_LINE);
return 0;
}
shell_printf("Writing [%s](len : %d) to SPI"NEW_LINE, argv[2], strlen(argv[2]));
shell_printf("Received [%s](len : %d) from SPI"NEW_LINE, spi_recv_buff, strlen(spi_recv_buff));
}
else
{
shell_printf("Unknown %s action"NEW_LINE, argv[0]);
}
}
else
{
shell_printf("List of %s actions :"NEW_LINE"spi_init"NEW_LINE"spi_w"NEW_LINE"spi_r"NEW_LINE"spi_wr"NEW_LINE, argv[0]);
}
return 0;
}
int _soft_ap(const shell_cmd_t *pcmd, int argc, char *const argv[])
{
if(argc > 1)
{
if(strcmp(argv[1], "state") == 0)
{
shell_printf("SOFT AP state : %u"NEW_LINE, tls_wifi_softap_get_state());
}
else if(strcmp(argv[1], "create") == 0)
{
struct tls_softap_info_t ap_info;
struct tls_ip_info_t ip_info;
tls_wifi_set_oneshot_flag(0);
tls_wifi_softap_destroy();
shell_printf("Registering client event callback"NEW_LINE);
tls_wifi_softap_client_event_register(&(tls_wifi_client_event_cb));
strncpy((char *)ap_info.ssid, argv[2], 32);
ap_info.ssid[32] = '\0';
ap_info.encrypt = IEEE80211_ENCRYT_TKIP_WPA2;
ap_info.channel = 5;
ap_info.keyinfo.format = 1;
ap_info.keyinfo.index = 1;
ap_info.keyinfo.key_len = strlen(argv[3]);
strncpy((char *)ap_info.keyinfo.key, argv[3], 63);
ip_info.ip_addr[0] = 192;
ip_info.ip_addr[1] = 168;
ip_info.ip_addr[2] = 1;
ip_info.ip_addr[3] = 1;
ip_info.netmask[0] = 255;
ip_info.netmask[1] = 255;
ip_info.netmask[2] = 255;
ip_info.netmask[3] = 0;
ip_info.dnsname[0] = '\0';
int result = tls_wifi_softap_create(&ap_info, &ip_info);
shell_printf("Create AP with SSID : %s, key(%d) : %s -> %d"NEW_LINE, ap_info.ssid, ap_info.keyinfo.key_len, ap_info.keyinfo.key, result);
}
else if(strcmp(argv[1], "destroy") == 0)
{
tls_wifi_softap_client_event_register(NULL);
tls_wifi_set_oneshot_flag(0);
tls_wifi_softap_destroy();
shell_printf("Stopping SOFT AP"NEW_LINE);
}
else
{
shell_printf("Unknown %s action"NEW_LINE, argv[0]);
}
}
else
{
shell_printf("List of soft_ap actions :"NEW_LINE"state"NEW_LINE"create <SSID> <PWD>"NEW_LINE"destroy"NEW_LINE);
}
return 0;
}
int _station(const shell_cmd_t *pcmd, int argc, char *const argv[])
{
if(argc > 1)
{
if(strcmp(argv[1], "scan") == 0)
{
tls_wifi_scan_result_cb_register(&(wifi_scan_result_cb));
if(tls_wifi_scan() == WM_SUCCESS)
{
shell_printf("Scanning nearby stations..."NEW_LINE);
}
else
{
shell_printf("Failed to start wifi scan"NEW_LINE);
}
}
else if(strcmp(argv[1], "state") == 0)
{
shell_printf("Station state : %u"NEW_LINE, tls_wifi_get_state());
}
else if(strcmp(argv[1], "connect") == 0)
{
shell_printf("Connecting to %s with pwd : %s"NEW_LINE, argv[2], argv[3]);
if(tls_wifi_connect((u8 *)argv[2], strlen(argv[2]), (u8 *)argv[3], strlen(argv[3])) == WM_SUCCESS)
{
shell_printf("Connecting..."NEW_LINE);
}
else
{
shell_printf("Failed to connect !"NEW_LINE);
}
}
else if(strcmp(argv[1], "disconnect") == 0)
{
shell_printf("Disconnecting from current station"NEW_LINE);
tls_wifi_set_oneshot_flag(0);
tls_wifi_disconnect();
}
else
{
shell_printf("Unknown %s action"NEW_LINE, argv[0]);
}
}
else
{
shell_printf("List of station actions :"NEW_LINE"scan"NEW_LINE"state"NEW_LINE"connect <SSID> <PWD>"NEW_LINE"disconnect"NEW_LINE);
}
return 0;
}
int _cpu_temp(const shell_cmd_t *pcmd, int argc, char *const argv[])
{
int temperature = adc_temp();
shell_printf("CPU temp is %d.%03d"NEW_LINE, temperature/1000, temperature%1000);
return 0;
}
int _wifi(const shell_cmd_t *pcmd, int argc, char *const argv[])
{
if(argc > 1)
{
if(strcmp(argv[1], "off") == 0)
{
tls_wifi_softap_destroy();
tls_wifi_disconnect();
shell_printf("set one shot flg : %d"NEW_LINE,tls_wifi_set_oneshot_flag(0));
shell_printf("Stopping WIFI interface"NEW_LINE);
}
else if(strcmp(argv[1], "error") == 0)
{
shell_printf("Error : %s"NEW_LINE, tls_wifi_get_errinfo(tls_wifi_get_errno()));
}
else if(strcmp(argv[1], "promiscuous_on") == 0)
{
shell_printf("WiFi promiscuous on"NEW_LINE);
tls_wifi_data_ext_recv_cb_register(&(tls_wifi_data_ext_recv_cb));
}
else if(strcmp(argv[1], "promiscuous_off") == 0)
{
shell_printf("WiFi promiscuous off"NEW_LINE);
tls_wifi_data_ext_recv_cb_register(NULL);
}
else if(strcmp(argv[1], "mode") == 0)
{
shell_printf("Mode is : %d"NEW_LINE, tls_wifi_get_oneshot_flag());
}
else if(strcmp(argv[1], "get_ip") == 0)
{
struct netif *netif = tls_get_netif();
if(netif)
{
shell_printf("netif 1"NEW_LINE"ip addr : %v"NEW_LINE"netmask : %v"NEW_LINE"gateway : %v"NEW_LINE, netif->ip_addr.addr,
netif->netmask.addr,
netif->gw.addr);
if(netif->next)
{
shell_printf("netif 2"NEW_LINE"ip addr : %v"NEW_LINE"netmask : %v"NEW_LINE"gateway : %v"NEW_LINE, netif->next->ip_addr.addr,
netif->next->netmask.addr,
netif->next->gw.addr);
}
}
else
{
shell_printf("No netif yet, connect to sta or create soft_ap !"NEW_LINE);
}
}
else
{
shell_printf("Unknown %s action"NEW_LINE, argv[0]);
}
}
else
{
shell_printf("List of wifi actions :"NEW_LINE"off"NEW_LINE"error"NEW_LINE"promiscuous_on"NEW_LINE"promiscuous_off"NEW_LINE"mode"NEW_LINE"get_ip"NEW_LINE);
}
return 0;
}
int _wifi_sleep(const shell_cmd_t *pcmd, int argc, char *const argv[])
{
if(argc > 1)
{
if(strcmp(argv[1], "query") == 0)
{
shell_printf("power saving : 0x%X, psm chip sleep : 0x%X"NEW_LINE,
tls_wifi_get_psflag(),
tls_wifi_get_psm_chipsleep_flag());
}
else if(strcmp(argv[1], "set") == 0)
{
}
else
{
shell_printf("Unknown %s action"NEW_LINE, argv[0]);
}
}
else
{
shell_printf("List of wifi_sleep actions :"NEW_LINE"query"NEW_LINE"set"NEW_LINE);
}
return 0;
}
int _pmu(const shell_cmd_t *pcmd, int argc, char *const argv[])
{
if(argc > 1)
{
if(strcmp(argv[1], "sleep") == 0)
{
u32 duration = strtoul(argv[2], NULL, 10);
shell_printf("Going to sleep mode for %u s"NEW_LINE, duration);
tls_pmu_timer0_start(duration);
tls_pmu_sleep_start();
shell_printf("Waking up out of sleep mode"NEW_LINE);
tls_pmu_timer0_stop();
}
else if(strcmp(argv[1], "standby") == 0)
{
u32 duration = strtoul(argv[2], NULL, 10);
shell_printf("Going to standby mode for %u s"NEW_LINE, duration);
tls_pmu_timer0_start(duration);
tls_pmu_standby_start();
shell_printf("Waking up out of standby mode"NEW_LINE);
tls_pmu_timer0_stop();
}
else
{
shell_printf("Unknown %s action"NEW_LINE, argv[0]);
}
}
else
{
shell_printf("List of pmu actions :"NEW_LINE"sleep <duration(s)>"NEW_LINE"standby <duration(s)>"NEW_LINE);
}
return 0;
}
int _rtc(const shell_cmd_t *pcmd, int argc, char *const argv[])
{
if(argc > 1)
{
if(strcmp(argv[1], "get") == 0)
{
struct tm rtc_time;
tls_get_rtc(&rtc_time);
shell_printf("rtc time is :"NEW_LINE"%d:%d:%d %d/%d/%d"NEW_LINE,
rtc_time.tm_hour,
rtc_time.tm_min,
rtc_time.tm_sec,
rtc_time.tm_mday,
rtc_time.tm_mon,
rtc_time.tm_year);
}
else if(strcmp(argv[1], "set") == 0)
{
struct tm rtc_time;
rtc_time.tm_hour = strtoul(argv[2], NULL, 10);
rtc_time.tm_min = strtoul(argv[3], NULL, 10);
rtc_time.tm_sec = strtoul(argv[4], NULL, 10);
rtc_time.tm_mday = strtoul(argv[5], NULL, 10);
rtc_time.tm_mon = strtoul(argv[6], NULL, 10);
rtc_time.tm_year = strtoul(argv[7], NULL, 10);
shell_printf("Setting rtc to :"NEW_LINE"%d:%d:%d %d/%d/%d"NEW_LINE"isr callback registered !"NEW_LINE,
rtc_time.tm_hour,
rtc_time.tm_min,
rtc_time.tm_sec,
rtc_time.tm_mday,
rtc_time.tm_mon,
rtc_time.tm_year);
tls_set_rtc(&rtc_time);
tls_rtc_isr_register(&(tls_rtc_irq_cb), NULL);
}
else if(strcmp(argv[1], "alarm") == 0)
{
struct tm rtc_time;
rtc_time.tm_hour = strtoul(argv[2], NULL, 10);
rtc_time.tm_min = strtoul(argv[3], NULL, 10);
rtc_time.tm_sec = strtoul(argv[4], NULL, 10);
rtc_time.tm_mday = strtoul(argv[5], NULL, 10);
rtc_time.tm_mon = strtoul(argv[6], NULL, 10);
rtc_time.tm_year = strtoul(argv[7], NULL, 10);
shell_printf("Setting rtc alarm to :"NEW_LINE"%d:%d:%d %d/%d/%d"NEW_LINE,
rtc_time.tm_hour,
rtc_time.tm_min,
rtc_time.tm_sec,
rtc_time.tm_mday,
rtc_time.tm_mon,
rtc_time.tm_year);
tls_rtc_timer_start(&(rtc_time));
}
else
{
shell_printf("Unknown %s action"NEW_LINE, argv[0]);
}
}
else
{
shell_printf("List of rtc actions :"NEW_LINE"get"NEW_LINE"set <h> <m> <s> <d> <m> <y>"NEW_LINE"alarm <h> <m> <s> <d> <m> <y>"NEW_LINE);
}
return 0;
}
int _bluetooth(const shell_cmd_t *pcmd, int argc, char *const argv[])
{
if(argc > 1)
{
if(strcmp(argv[1], "enable") == 0)
{
shell_printf("Enabling bluetooth : %d"NEW_LINE, demo_bt_enable());
//shell_printf("Enabling bluetooth test"NEW_LINE);
}
else if(strcmp(argv[1], "disable") == 0)
{
shell_printf("Disabling bluetooth : %d"NEW_LINE, demo_bt_destroy());
//shell_printf("Disabling bluetooth test"NEW_LINE);
}
else if(strcmp(argv[1], "start_demo") == 0)
{
shell_printf("Starting demo : %d"NEW_LINE"Use a BLE app to find the device"NEW_LINE, demo_ble_server_on());
}
else if(strcmp(argv[1], "stop_demo") == 0)
{
shell_printf("Stopping demo : %d"NEW_LINE, demo_ble_server_off());
}
else
{
shell_printf("Unknown %s action"NEW_LINE, argv[0]);
}
}
else
{
shell_printf("List of bluetooth actions :"NEW_LINE"enable"NEW_LINE"disable"NEW_LINE"start_demo"NEW_LINE"stop_demo"NEW_LINE);
}
return 0;
}
int _telnet(const shell_cmd_t *pcmd, int argc, char *const argv[])
{
if(argc > 1)
{
if(strcmp(argv[1], "dont_echo") == 0)
{
shell_printf("Disabling client echo"NEW_LINE"%c%c%c"NEW_LINE, 0xFF, 0xFB, 0x01);
}
else
{
shell_printf("Unknown %s action"NEW_LINE, argv[0]);
}
}
else
{
shell_printf("List of %s actions :"NEW_LINE"dont_echo"NEW_LINE, argv[0]);
}
return 0;
}
int _exit_remote_access(const shell_cmd_t *pcmd, int argc, char *const argv[])
{
if(disconnect_client())
{
shell_printf("Disconnected !"NEW_LINE);
}
else
{
shell_printf("Not using remote access !"NEW_LINE);
}
return 0;
}
NANO_SHELL_ADD_CMD(bus,
_bus,
"Command to interact with the SPI bus",
" Use this command to send/receive data from the SPI bus"NEW_LINE);
NANO_SHELL_ADD_CMD(system,
_system,
"Query system information",
" Use this command to get system information"NEW_LINE);
NANO_SHELL_ADD_CMD(reset,
_reset,
"Reset the system",
" Use this command reset the system"NEW_LINE);
NANO_SHELL_ADD_CMD(soft_ap,
_soft_ap,
"Command to control SOFT AP",
" Use this command to control the SOFT AP subsystem"NEW_LINE);
NANO_SHELL_ADD_CMD(station,
_station,
"Command to control STATION mode",
" Use this command to connect to a WiFi access point"NEW_LINE);
NANO_SHELL_ADD_CMD(wifi,
_wifi,
"Command to control WIFI interface",
" Use this command to control the WIFI interface"NEW_LINE);
NANO_SHELL_ADD_CMD(cpu_temp,
_cpu_temp,
"Command to read the CPU temperature",
" Use this command to read the CPU temperature"NEW_LINE);
NANO_SHELL_ADD_CMD(wifi_sleep,
_wifi_sleep,
"Command to control WiFi sleep",
" Use this command to control WiFi sleep feature"NEW_LINE);
NANO_SHELL_ADD_CMD(pmu,
_pmu,
"Command to control the power management unit",
" Use this command to control power management unit feature"NEW_LINE);
NANO_SHELL_ADD_CMD(rtc,
_rtc,
"Command to query and set up the rtc",
" Use this command to interact with the rtc module"NEW_LINE);
NANO_SHELL_ADD_CMD(bluetooth,
_bluetooth,
"Command to control bluetooth functionality",
" Use this command to interact use bluetooth"NEW_LINE);
NANO_SHELL_ADD_CMD(telnet,
_telnet,
"Command to set the telnet session up",
" Use this command to set telnet session parameters"NEW_LINE);
NANO_SHELL_ADD_CMD(exit,
_exit_remote_access,
"Disconnect from Nano-Shell remote access",
" Use this command to disconnect from Nano-Shell remote access"NEW_LINE);

101
app/nano_shell_port.c Normal file
View File

@ -0,0 +1,101 @@
#include "wm_include.h"
#include "shell_config.h"
#include "shell_io/static_fifo.h"
static_fifo_declare(uart_char_fifo, 256, unsigned char, char);
extern int sendchar(int ch);
extern bool network_write_char(const char c);
extern bool network_write_string(const char *str, size_t size);
extern tls_os_task_t nano_shell_task_handle;
s16 uart0_rx_callback(u16 len, void *user_data)
{
(void)len;
(void)user_data;
u8 buff[256] = "";
int data_len = tls_uart_read(TLS_UART_0, (u8 *) buff, 256);
for(int i = 0; i < data_len; i++)
{
fifo_push(uart_char_fifo, buff[i]);
}
(void)tls_os_task_resume_from_isr(nano_shell_task_handle);
return 0;
}
s16 uart1_rx_callback(u16 len, void *user_data)
{
(void)len;
(void)user_data;
u8 buff[256] = "";
int data_len = tls_uart_read(TLS_UART_1, (u8 *) buff, 256);
for(int i = 0; i < data_len; i++)
{
fifo_push(uart_char_fifo, buff[i]);
}
(void)tls_os_task_resume_from_isr(nano_shell_task_handle);
return 0;
}
void network_rx_callback(u16 len, char *data)
{
if(!len)return;
for(int i = 0; i < len; i++)
{
fifo_push(uart_char_fifo, data[i]);
}
(void)tls_os_task_resume(nano_shell_task_handle);
}
int shell_getc(char *ch)
{
if(is_fifo_empty(uart_char_fifo))
{
//If the fifo is empty then we can suspend the task since
//it is only waiting for inputs to be processed
tls_os_task_suspend(NULL);
return 0;
}
*ch = fifo_pop_unsafe(uart_char_fifo);
return 1;
}
int shell_printf(const char *format, ...)
{
static char shell_printf_buffer[CONFIG_SHELL_PRINTF_BUFFER_SIZE];
int length = 0;
va_list ap;
va_start(ap, format);
length = vsnprintf(shell_printf_buffer, CONFIG_SHELL_PRINTF_BUFFER_SIZE, format, ap);
va_end(ap);
(void)tls_uart_write(TLS_UART_0, shell_printf_buffer, length);
(void)tls_uart_write(TLS_UART_1, shell_printf_buffer, length);
(void)network_write_string(shell_printf_buffer, length);
return length;
}
void shell_puts(const char *str)
{
(void)shell_printf(str);
}
void shell_putc(char ch)
{
(void)shell_printf("%c", ch);
}
void low_level_write_char(char ch)
{
(void)sendchar((int)ch);
(void)tls_uart_write(TLS_UART_1, &ch, 1);
(void)network_write_char(ch);
}

View File

@ -0,0 +1,198 @@
#include "string.h"
#include "lwip/netif.h"
#include "wm_include.h"
#include "FreeRTOS.h"
#include "FreeRTOSConfig.h"
#include "nano_shell_server_task.h"
#include "nano_shell_interface.h"
#include "app_common.h"
extern void network_rx_callback(u16 len, char *data);
tls_os_mutex_t *socket_mutex = NULL;
int nano_shell_srv_sock = 0, client_sock = 0;
const char greeting_buffer[] = "\r\n"
" _ _ ____ _ _ _\r\n"
"| \\ | | __ _ _ __ ___ / ___|| |__ ___| | |\r\n"
"| \\| |/ _` | '_ \\ / _ \\ \\___ \\| '_ \\ / _ \\ | |\r\n"
"| |\\ | (_| | | | | (_) | ___) | | | | __/ | |\r\n"
"|_| \\_|\\__,_|_| |_|\\___/ |____/|_| |_|\\___|_|_|\r\n"
"\r\n"
"Welcome to Nano-Shell remote access\r\n"
"\r\n"
" * Source: https://github.com/lebinlv/nano-shell\r\n"
" * Copyright: (c) Liber 2020\r\n"
"\r\n";
char identity_buffer[250] = "";
bool network_write_char(const char c)
{
bool toReturn = false;
tls_os_mutex_acquire(socket_mutex, 0);
if(client_sock > 0)
{
if(send(client_sock, &c, 1, 0) < 0)
{
// Failed to send data to client because he probably disconnected
// or the connection broke
client_sock = 0;
}
else
{
toReturn = true;
}
}
tls_os_mutex_release(socket_mutex);
return toReturn;
}
bool network_write_string(const char *str, size_t size)
{
bool toReturn = false;
if(client_sock > 0)
{
tls_os_mutex_acquire(socket_mutex, 0);
if(send(client_sock, str, size, 0) < 0)
{
// Failed to send data to client because he probably disconnected
// or the connection broke
client_sock = 0;
}
else
{
toReturn = true;
}
tls_os_mutex_release(socket_mutex);
}
return toReturn;
}
bool disconnect_client(void)
{
bool toReturn = false;
if(client_sock > 0)
{
if(shutdown(client_sock, SHUT_WR) < 0)
{
}
else
{
toReturn = true;
}
client_sock = 0;
}
return toReturn;
}
void nano_shell_server_task(void* param)
{
(void)param;
bool setup_error = false;
char recv_buffer[256] = "";
struct sockaddr_in nano_shell_srv_addr = { .sin_family = AF_INET, .sin_addr.s_addr = INADDR_ANY, .sin_port = htons(NANO_SHELL_SERVER_PORT)}, client_addr;
socklen_t sockaddr_in_len = sizeof(struct sockaddr_in);
//We initialize the mutex
if(tls_os_mutex_create(0, &socket_mutex) != TLS_OS_SUCCESS)
{
shell_printf("Failed to create the mutex."NEW_LINE);
setup_error = true;
}
//We setup the listening socket :
if((nano_shell_srv_sock = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0)
{
shell_printf("Failed to create nano_shell listening socket."NEW_LINE);
setup_error = true;
}
if(bind(nano_shell_srv_sock, (struct sockaddr *) &nano_shell_srv_addr, sockaddr_in_len) < 0)
{
shell_printf("Failed to bind nano_shell listening socket to addr."NEW_LINE);
setup_error = true;
}
//We only wait for one connection at a time because the nano_shell is not multi user anyway
if(listen(nano_shell_srv_sock, 0) < 0)
{
shell_printf("Failed to mark nano_shell_sock as a listening socket."NEW_LINE);
setup_error = true;
}
if(setup_error)
{
for(;;)
tls_os_time_delay(portMAX_DELAY);
}
for(;;)
{
client_sock = accept(nano_shell_srv_sock, (struct sockaddr *)&client_addr, &sockaddr_in_len);
if(client_sock < 0)
{
shell_printf("Failed to accept incoming connection."NEW_LINE);
}
if(!network_write_string(greeting_buffer, sizeof greeting_buffer))
{
shell_printf("Failed to send greetings to client - errno(%d)."NEW_LINE, errno);
}
sprintf(identity_buffer, "Connected from : %u.%u.%u.%u:%u"NEW_LINE NEW_LINE,((u8 *)&client_addr.sin_addr)[0],
((u8 *)&client_addr.sin_addr)[1],
((u8 *)&client_addr.sin_addr)[2],
((u8 *)&client_addr.sin_addr)[3],
ntohs(client_addr.sin_port));
if(!network_write_string(identity_buffer, strlen(identity_buffer)))
{
shell_printf("Failed to send greetings to client - errno(%d)."NEW_LINE, errno);
}
for(;client_sock > 0;)
{
int result = recv(client_sock, recv_buffer, 255, 0);
if(result < 0)
{
shell_printf("Failed to receive data from client - errno(%d)."NEW_LINE"Closing connection."NEW_LINE, errno);
if(close(client_sock) < 0)
{
shell_printf("Failed to close socket - errno(%d)."NEW_LINE, errno);
}
client_sock = 0;
}
else if(result == 0)
{
shell_printf("Client disconnected."NEW_LINE);
if(close(client_sock) < 0)
{
shell_printf("Failed to close socket - errno(%d)."NEW_LINE, errno);
}
client_sock = 0;
}
else //We pass the received data to the nano shell process
{
//Need to remove the \n at the end
char *pos = strchr(recv_buffer, '\r');
if(pos)
{
*pos = '\n';
result = pos + 1 - recv_buffer;
}
network_rx_callback(result, recv_buffer);
}
}
}
}

View File

@ -0,0 +1,3 @@
#define NANO_SHELL_SERVER_PORT 23
void nano_shell_server_task(void* param);

View File

@ -0,0 +1,14 @@
TOP_DIR = ../../../..
sinclude $(TOP_DIR)/tools/w800/conf.mk
ifndef PDIR
GEN_LIBS = libnrf24l01p$(LIB_EXT)
endif
#DEFINES +=
sinclude $(TOP_DIR)/tools/w800/rules.mk
INCLUDES := $(INCLUDES) -I $(PDIR)include
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,192 @@
#ifndef NRF24L01P_H
#define NRF24L01P_H
#include "NRF24L01P_hw_interface.h"
/*PUBLIC API*/
typedef enum rf24_datarate
{
/** (0) represents 1 Mbps */
RF24_1MBPS = 0,
/** (1) represents 2 Mbps */
RF24_2MBPS,
/** (2) represents 250 kbps */
RF24_250KBPS
} rf24_datarate_e;
typedef enum rf24_pa_dbm
{
/**
* (0) represents:
* nRF24L01 | Si24R1 with<br>lnaEnabled = 1 | Si24R1 with<br>lnaEnabled = 0
* :-------:|:-----------------------------:|:----------------------------:
* -18 dBm | -6 dBm | -12 dBm
*/
RF24_PA_MIN = 0,
/**
* (1) represents:
* nRF24L01 | Si24R1 with<br>lnaEnabled = 1 | Si24R1 with<br>lnaEnabled = 0
* :-------:|:-----------------------------:|:----------------------------:
* -12 dBm | 0 dBm | -4 dBm
*/
RF24_PA_LOW,
/**
* (2) represents:
* nRF24L01 | Si24R1 with<br>lnaEnabled = 1 | Si24R1 with<br>lnaEnabled = 0
* :-------:|:-----------------------------:|:----------------------------:
* -6 dBm | 3 dBm | 1 dBm
*/
RF24_PA_HIGH,
/**
* (3) represents:
* nRF24L01 | Si24R1 with<br>lnaEnabled = 1 | Si24R1 with<br>lnaEnabled = 0
* :-------:|:-----------------------------:|:----------------------------:
* 0 dBm | 7 dBm | 4 dBm
*/
RF24_PA_MAX,
/**
* (4) This should not be used and remains for backward compatibility.
*/
RF24_PA_ERROR
} rf24_pa_dbm_e;
typedef enum rf24_crclength
{
/** (0) represents no CRC checksum is used */
RF24_CRC_DISABLED = 0,
/** (1) represents CRC 8 bit checksum is used */
RF24_CRC_8,
/** (2) represents CRC 16 bit checksum is used */
RF24_CRC_16
} rf24_crclength_e;
typedef struct NRF24L01P
{
uint8_t status;
uint8_t payload_size;
bool dynamic_payloads_enabled;
bool ack_payloads_enabled;
uint8_t pipe0_reading_address[5];
uint8_t addr_width;
uint8_t config_reg;
bool is_p_variant;
bool failure_detected;
} NRF24L01P_t;
bool NRF24L01P_begin(NRF24L01P_t *NRF);
bool NRF24L01P_isChipConnected(NRF24L01P_t *NRF);
void NRF24L01P_startListening(NRF24L01P_t *NRF);
void NRF24L01P_stopListening(NRF24L01P_t *NRF);
bool NRF24L01P_available(NRF24L01P_t *NRF);
void NRF24L01P_read(NRF24L01P_t *NRF, void *payload, uint8_t length);
bool NRF24L01P_write(NRF24L01P_t *NRF, const void *payload, uint8_t length);
void NRF24L01P_openWritingPipe(NRF24L01P_t *NRF, const uint8_t* address);
void NRF24L01P_openReadingPipe(NRF24L01P_t *NRF, uint8_t pipe, const uint8_t *address);
void NRF24L01P_printDetails(NRF24L01P_t *NRF);
bool NRF24L01P_availablePipe(NRF24L01P_t *NRF, uint8_t *pipe);
bool NRF24L01P_rxFifoFull(NRF24L01P_t *NRF);
bool NRF24L01P_txFifoFull(NRF24L01P_t *NRF);
void NRF24L01P_powerDown(NRF24L01P_t *NRF);
void NRF24L01P_powerUp(NRF24L01P_t *NRF);
bool NRF24L01P_writeMulticast(NRF24L01P_t *NRF, const void *payload, uint8_t length, const bool multicast);
bool NRF24L01P_writeFast(NRF24L01P_t *NRF, const void *payload, uint8_t length);
bool NRF24L01P_writeFastMulticast(NRF24L01P_t *NRF, const void *payload, uint8_t length, const bool multicast);
bool NRF24L01P_writeBlocking(NRF24L01P_t *NRF, const void *payload, uint8_t length, uint32_t timeout);
bool NRF24L01P_txStandBy(NRF24L01P_t *NRF);
bool NRF24L01P_txStandByTimeout(NRF24L01P_t *NRF, uint32_t timeout, bool start_tx);
bool NRF24L01P_writeAckPayload(NRF24L01P_t *NRF, uint8_t pipe, const void *payload, uint8_t length);
void NRF24L01P_whatHappened(NRF24L01P_t *NRF, bool *tx_ok, bool *tx_fail, bool *rx_ready);
void NRF24L01P_startFastWrite(NRF24L01P_t *NRF, const void *payload, uint8_t length, const bool multicast, bool start_tx);
bool NRF24L01P_startWrite(NRF24L01P_t *NRF, const void *payload, uint8_t length, const bool multicast);
void NRF24L01P_reUseTX(NRF24L01P_t *NRF);
uint8_t NRF24L01P_flush_tx(NRF24L01P_t *NRF);
uint8_t NRF24L01P_flush_rx(NRF24L01P_t *NRF);
bool NRF24L01P_testCarrier(NRF24L01P_t *NRF);
bool NRF24L01P_testRPD(NRF24L01P_t *NRF);
void NRF24L01P_closeReadingPipe(NRF24L01P_t *NRF, uint8_t pipe);
void NRF24L01P_setAddressWidth(NRF24L01P_t *NRF, uint8_t a_width);
void NRF24L01P_setRetries(NRF24L01P_t *NRF, uint8_t delay, uint8_t count);
void NRF24L01P_setChannel(NRF24L01P_t *NRF, uint8_t channel);
uint8_t NRF24L01P_getChannel(NRF24L01P_t *NRF);
void NRF24L01P_setPayloadSize(NRF24L01P_t *NRF, uint8_t size);
uint8_t NRF24L01P_getPayloadSize(NRF24L01P_t *NRF);
uint8_t NRF24L01P_getDynamicPayloadSize(NRF24L01P_t *NRF);
void NRF24L01P_enableAckPayload(NRF24L01P_t *NRF);
void NRF24L01P_disableAckPayload(NRF24L01P_t *NRF);
void NRF24L01P_enableDynamicPayloads(NRF24L01P_t *NRF);
void NRF24L01P_disableDynamicPayloads(NRF24L01P_t *NRF);
void NRF24L01P_enableDynamicAck(NRF24L01P_t *NRF);
bool NRF24L01P_isPVariant(NRF24L01P_t *NRF);
void NRF24L01P_setAutoAck(NRF24L01P_t *NRF, bool enable);
void NRF24L01P_setAutoAckPipe(NRF24L01P_t *NRF, uint8_t pipe, bool enable);
void NRF24L01P_setPALevel(NRF24L01P_t *NRF, rf24_pa_dbm_e level, bool lna_enable);
rf24_pa_dbm_e NRF24L01P_getPALevel(NRF24L01P_t *NRF);
uint8_t NRF24L01P_getARC(NRF24L01P_t *NRF);
bool NRF24L01P_setDataRate(NRF24L01P_t *NRF, rf24_datarate_e data_rate);
rf24_datarate_e NRF24L01P_getDataRate(NRF24L01P_t *NRF);
void NRF24L01P_setCRCLength(NRF24L01P_t *NRF, rf24_crclength_e length);
rf24_crclength_e NRF24L01P_getCRCLength(NRF24L01P_t *NRF);
void NRF24L01P_disableCRC(NRF24L01P_t *NRF);
void NRF24L01P_maskIRQ(NRF24L01P_t *NRF, bool tx, bool fail, bool rx);
void NRF24L01P_startConstCarrier(NRF24L01P_t *NRF, rf24_pa_dbm_e level, uint8_t channel);
void NRF24L01P_stopConstCarrier(NRF24L01P_t *NRF);
bool NRF24L01P_isAckPayloadAvailable(NRF24L01P_t *NRF);
#endif //NRF24L01P_H

View File

@ -0,0 +1,20 @@
#ifndef NRF24L01P_HW_INTERFACE_H
#define NRF24L01P_HW_INTERFACE_H
#include "wm_include.h"
#include "FreeRTOS.h"
#include "app_common.h"
#include "nano_shell_interface.h"
#include "app_utils.h"
#define debug_printf(...) shell_printf(__VA_ARGS__); shell_printf(NEW_LINE)
void delay_ms(uint32_t ms);
uint32_t elapsed_ms(void);
void CE_HIGH(void);
void CE_LOW(void);
#endif //NRF24L01P_HW_INTERFACE_H

View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2020 Liber
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -0,0 +1,18 @@
TOP_DIR = ../../..
sinclude $(TOP_DIR)/tools/w800/conf.mk
ifndef PDIR
GEN_LIBS = libnanoshell$(LIB_EXT)
COMPONENTS_libnanoshell = command/libcommand$(LIB_EXT) \
parse/libparse$(LIB_EXT) \
readline/libreadline$(LIB_EXT) \
shell_io/libshell_io$(LIB_EXT)
endif
#DEFINES +=
sinclude $(TOP_DIR)/tools/w800/rules.mk
INCLUDES := $(INCLUDES) -I $(PDIR)include
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile

View File

@ -0,0 +1,384 @@
# Nano-Shell <!-- omit in toc -->
<img src="doc/pic/nano_shell_welcome.png" width=600>
## Contents <!-- omit in toc -->
- [Hot Key Bind](#hot-key-bind)
- [Add Your Command](#add-your-command)
- [HOW:](#how)
- [Example:](#example)
- [Configuring](#configuring)
- [readline configurations:](#readline-configurations)
- [command configurations:](#command-configurations)
- [shell configurations:](#shell-configurations)
- [shell io configurations:](#shell-io-configurations)
- [Porting nano-shell to your project](#porting-nano-shell-to-your-project)
---
Nano-Shell is a light but powerful shell designed for embedded systems.
- with or without an operating system;
- `<main loop mode>` or `<react mode>`;
- highly configurable;
- powerful: command line editing, history record, multi-line input, hot key bind, etc...
- memory friendly: **NO** malloc and free;
- light (build with arm-none-eabi-gcc 7.3.1 20180622, -O3):
| | .text<sup>(1)</sup> | .rodata | .bss<sup>(2)</sup> | .data |
|:------------------------------------------:|:------:|:-------:|:-----:|:-----:|
| main loop mode,<br/>all configurations on | 2.5KB | 1.03KB | 852B | 8B |
| main loop mode,<br/>all configurations off<sup>(3)</sup> | 616B | 600B | 180B | 0B |
| react mode,<br/>all configurations on | 2.52KB | 1.03KB | 852B | 8B |
| react mode,<br/>all configurations off<sup>(3)</sup> | 608B | 600B | 180B | 0B |
> 1: include built-in `help` command.
>
> 2: include `input buffer`(default 128Bytes) and `hisroty record buffer`(defaut 650Bytes(5*(128+2)))
>
> 3: except `CONFIG_SHELL_CMD_BUILTIN_HELP`.
---
## Hot Key Bind
nano-shell has internally bound these hotkeys:
| HOT KEY | ASCII/ANSI-Escape Code<br/>(Xterm, VT100) | Function |
|---------|------------------------|----------|
| Ctrl-A | 1 | Home<br/>Move curosr to the start of line.|
| Ctrl-E | 5 | End<br/>Move curosr to the end of line.|
| Ctrl-P | 16 | Up arrow(-->)<br/>Move cursor right one char.|
| Ctrl-N | 14 | Down arrow(-->)<br/>Move cursor right one char.|
| Ctrl-B | 2 | Left arrow(<--)<br/>Move cursor left one char.|
| Ctrl-F | 6 | Right arrow(-->)<br/>Move cursor right one char.|
| Ctrl-D | 4 | Delete<br/>Delete the character under the cursor.|
| Ctrl-K | 11 | Erase forward<br/>Clears all characters from the cursor position to the end of the line.|
| Ctrl-U | 21 | Erase backword<br/>Clears all characters from the cursor position to the start of the line..|
| Ctrl-C | 3 | Kill the line.|
| Home | Esc[H | Move curosr to the beginning of line.|
| End | Esc[F | Move curosr to the end of line.|
| Up Arrow | Esc[A | Get the previous history. |
| Down Arrow | Esc[B | Get the next history. |
| Left Arrow | Esc[D | Left arrow(<--)<br/>Move cursor left one char. |
| Right Arrow | Esc[C | Right arrow(-->)<br/>Move cursor right one char.|
| Delete | Esc[3~ | Delete the character under the cursor.|
---
## Add Your Command
### HOW:
Commands are added to nano-shell by creating a new command structure.
This is done by first including `command/command.h`, then using the `NANO_SHELL_ADD_CMD()` macro to fill in a `shell_cmd_t` struct.
``` c
NANO_SHELL_ADD_CMD(_name, _func, _brief, _help)
```
`_name`: name of the command. Note: **THIS IS NOT** a string.
`_func`: function pointer: `(*cmd)(const shell_cmd_t *, int, int, char *const[])`.
`_brief`: brief summaries of the command. This is a string.
`_help`: detailed help information of the command. This is a string.
Commands with sub-commands can easily be created with a combination of `NANO_SHELL_DEFINE_SUBCMDS`,
`NANO_SHELL_SUBCMD_ENTRY` and `NANO_SHELL_ADD_CMD`. See examples for more details.
### Example 1: Simple command:
```c
int _do_demo(const shell_cmd_t *pcmd, int argc, char *const argv[])
{
for (int i=0; i<argc; i++) {
shell_printf(" [DEMO] ARGV[%d]: %s\r\n", i, argv[i]);
}
return 0;
}
NANO_SHELL_ADD_CMD(demo,
_do_demo,
"a command demo",
" It's detailed help information of demo command\r\n");
```
Run `demo` in terminal:
<img src="doc/pic/command_demo.png" width=600>
Run `help` and `help demo` in terminal:
<img src="doc/pic/help_demo.png" width=600>
### Example 2: Command with sub-commands:
It is possible to create commands with sub-commands. More nested command can also be created.
```c
/* Create a bunch of commands to be run as a demo */
int _top_command_fallback_fct(const shell_cmd_t* pCmdt, int argc, char* const argv[])
{
if(argc > 1) {
shell_printf(" '%s' is not a subcommand of %s\r\n", argv[1], argv[0]);
}
else {
shell_printf(" Hey, there is subcommands here, type '%s help' for more info\r\n", argv[0]);
}
return 0;
}
int _do_subcommand1(const shell_cmd_t* pCmdt, int argc, char* const argv[]) {
shell_puts(" This is sub-command 1\r\n");
return 0;
}
int _do_subsubcommand1(const shell_cmd_t* pCmdt, int argc, char* const argv[]) {
shell_puts(" This is sub-sub-command 1\r\n");
return 0;
}
int _do_subsubcommand2(const shell_cmd_t* pCmdt, int argc, char* const argv[]) {
shell_puts(" This is sub-sub-command 2\r\n");
return 0;
}
// Sub-Sub commands group
NANO_SHELL_DEFINE_SUBCMDS(subcommand2_group,
NULL,
NANO_SHELL_SUBCMD_ENTRY(subsubcommand1,
_do_subsubcommand1,
"first sub-sub-command",
""),
NANO_SHELL_SUBCMD_ENTRY(subsubcommand2,
_do_subsubcommand2,
"second sub-sub-command",
""));
// Sub commands group
NANO_SHELL_DEFINE_SUBCMDS(top_command_group,
_top_command_fallback_fct,
NANO_SHELL_SUBCMD_ENTRY(subcommand1,
_do_subcommand1,
"first subcommand",
""),
NANO_SHELL_SUBCMD_ENTRY(subcommand2,
NANO_SHELL_SUBCMDS_FCT(subcommand2_group),
"second subcommand with sub-sub commands",
""));
// Command with sub commands
NANO_SHELL_ADD_CMD(top_command,
NANO_SHELL_SUBCMDS_FCT(top_command_group),
"A command with subcommand",
" This command have 2 sub-commands and one sub-sub-command\r\n");
```
In a terminal, you get:
<img src="doc/pic/subcommand_demo.png" width=600>
---
## Configuring
@file: [`shell_config.h`](/shell_config.h)
### readline configurations:
- CONFIG_SHELL_INPUT_BUFFSIZE (127U)
- default: `(127U)`
- config the command line input buffer size (in byte).
- CONFIG_SHELL_LINE_EDITING
- default: `1(enabled)`
- set this to `0` will disable command line editing.
- CONFIG_SHELL_KEY_SEQ_BIND
- default: `1(enabled)`
- set this to `0` will disable ANSI-Escape-Sequence. nano-shell will not be able to detect Home/End/Delete/Arrow keys. Doesn't affect Ctrl-P, Ctrl-N, etc...
- CONFIG_SHELL_MULTI_LINE
- default: `1(enabled)`
- use Backslash('\\') for line continuation when enabled, set this to `0` will disable line continuation.
- line continuation example:<br/><img src="doc/pic/line_continuation.png" width=600> <br/>
- CONFIG_SHELL_HIST_MIN_RECORD
- default: `(5U)`
- set this to `0` will disable history record.
- nano-shell will take `CONFIG_SHELL_HIST_MIN_RECORD*(2+CONFIG_SHELL_INPUT_BUFFSIZE)` bytes to record **At Least** `CONFIG_SHELL_HIST_MIN_RECORD` histroys. The max history records depends on the average length of the input.
### command configurations:
- CONFIG_SHELL_CMD_BRIEF_USAGE
- default: `1(enabled)`
- command structure `shell_cmd_t` has a pointer point to "brief usage information of the command", set this to `0` will remove it.
- CONFIG_SHELL_CMD_LONG_HELP
- default: `1(enabled)`
- command structure `shell_cmd_t` has a pointer point to "detailed help information of the command", set this to `0` will remove it.
- CONFIG_SHELL_CMD_BUILTIN_HELP
- default: `1(enabled)`
- nano-shell provides a built-in `help` command, set this to `0` will remove the deault `help` command.
- CONFIG_SHELL_CMD_MAX_ARGC
- default: `(10U)`
- config the max number of arguments, must be no less than 1.
### shell configurations:
- CONFIG_SHELL_PROMPT
- default: `"Nano-Shell >> "`
- config the shell promot that will displayed at the start of line. If you don't need it, set this to `NULL` or `""`.
### shell io configurations:
- CONFIG_SHELL_PRINTF_BUFFER_SIZE
- default: `(128U)`
- config the buffer size of `shell_printf()`.
---
## Porting nano-shell to your project
### 1. add nano-shell root path to your project include path. <!-- omit in toc -->
### 2. implement these functions([`@file shell_io.h`](/shell_io/shell_io.h)) in your project: <!-- omit in toc -->
this file may help: [`/shell_io/shell_io.c`](/shell_io/shell_io.c).
```c
/**
* @brief send a chararcter...
*
*/
extern void shell_putc(char ch);
/**
* @brief send string...
*
*/
extern void shell_puts(const char *str);
/**
* @brief printf() for nano-shell
*
*/
extern int shell_printf(const char *format, ...) __attribute__((format(printf, 1, 2)));
/**
* @brief: Get next character available from stream.
*
* @param ch: Return the character in `ch` if there was...
* @return: Result is non-zero if there was a character, or 0 if there wasn't.
*
*/
extern int shell_getc(char *ch);
```
Note:
- `int shell_getc(char *ch)` is **NOT USED** in `<react mode>`
- If you run nano-shell in `<main loop mode>`, to avoid losing characters, you'd better use a low layer receive fifo.
Take uart for example, you can detect incoming data using interrupts and then store each received character in a first-in-first-out (FIFO) buffer:
```c
void your_uart_interrupt_handler(void)
{
/* your uart receive code */
char ch = uart_get_char();
/* store character in fifo */
fifo_push(ch);
}
```
then `shell_getc(char *ch)` may be:
```c
int shell_getc(char *ch)
{
if (fifo_empty()) { // if no character in fifo,
return 0; // return false
}
*ch = fifo_pop(); // fifo is not empty, get a character from fifo.
return 1; // return true
}
```
I write a simple and lock free fifo based on ring buffer in [`@file: /shell_io/static_fifo.h`](/shell_io/static_fifo.h), maybe helpful...
### 3. then modify the configuration file: [`shell_config.h`](/shell_config.h) <!-- omit in toc -->
### 4. according to your system, you can: <!-- omit in toc -->
#### 4.1 without os, main loop mode: <!-- omit in toc -->
```c
#include "nano_shell.h"
int main(void)
{
/* system init code... */
/* nano-shell infinite loop. */
nano_shell_loop(NULL);
}
```
#### 4.2 without os, react mode(non-block): <!-- omit in toc -->
you can use it in interrupt, take UART for example:
```c
void your_uart_interrupt_handler (void)
{
/* your uart receive code */
char ch = uart_get_char();
/* nano-shell isr interface */
nano_shell_react(ch);
}
```
Note:
- `nano_shell_react()` is non-blocked (unless there was an infinite loop in your command function), you can call it when get a new character.
- ~~It is recommended to disable some configurations in `shell_config.h` if it was called in interrupt.~~
#### 4.3 with os, take freertos for example: <!-- omit in toc -->
```c
#include "nano_shell.h"
int main(void)
{
/* system init code... */
/* create nano_shell task */
TaskHandle_t shellTaskHandle = NULL;
xTaskCreate(nano_shell_loop, "shellTask", <stack_size>, NULL,
<task_priority>, &shellTaskHandle);
/* start rtos task scheduler */
vTaskStartScheduler();
}
```
Note:
- When determining the stack size for nano-shell, you should consider the memory occupied by commands added in nano-shell.
### 5. define nano_shell section in your linker script file: <!-- omit in toc -->
add these 5 lines to your linker script file:
```ld
.nano_shell : {
. = ALIGN(4);
KEEP (*(SORT(.nano_shell*)))
. = ALIGN(4);
} >FLASH
```
### 6. build, flash and try it. <!-- omit in toc -->

View File

@ -0,0 +1,13 @@
TOP_DIR = ../../../..
sinclude $(TOP_DIR)/tools/w800/conf.mk
ifndef PDIR
GEN_LIBS = libcommand$(LIB_EXT)
endif
#DEFINES +=
sinclude $(TOP_DIR)/tools/w800/rules.mk
INCLUDES := $(INCLUDES) -I $(PDIR)include
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile

View File

@ -0,0 +1,102 @@
/**
* @file cmd_help.c
* @author Liber (lvlebin@outlook.com), Cédric CARRÉE (beg0@free.fr)
* @brief nano-shell build in command: help
* @version 1.0
* @date 2020-03-25
*
* @copyright Copyright (c) Liber 2020
*
*/
#include "command.h"
#include "shell_io/shell_io.h"
#include "shell_config.h"
/****************************** build in command: help ******************************/
#if CONFIG_SHELL_CMD_BUILTIN_HELP
static void shell_print_cmd_list(const shell_cmd_t* start, unsigned int count)
{
const shell_cmd_t* tmp = start;
while (count) {
#if CONFIG_SHELL_CMD_BRIEF_USAGE
shell_printf(" %s: %s\r\n", tmp->name, tmp->brief_usage);
#else
shell_printf(" %s\r\n", tmp->name);
#endif
count--;
tmp++;
}
}
static void shell_print_cmd_help(const char *cmd_name,
const shell_cmd_t* start, unsigned int count)
{
#if CONFIG_SHELL_CMD_LONG_HELP
const shell_cmd_t *tmp = shell_find_cmd(cmd_name, start, count);
if (tmp) {
#if CONFIG_SHELL_CMD_BRIEF_USAGE
shell_printf("%s: %s\r\n", cmd_name, tmp->brief_usage);
#else
shell_printf("%s:\r\n", cmd_name);
#endif
// use puts() instead of printf() to avoid printf buffer overflow
shell_puts(tmp->help);
} else {
shell_printf("%s: command not found.\r\n", cmd_name);
}
#endif /* CONFIG_SHELL_CMD_LONG_HELP */
}
int shell_cmd_help(const shell_cmd_t *pcmd, int argc, char *const argv[])
{
const shell_cmd_t *start = _shell_entry_start(shell_cmd_t);
unsigned int count = _shell_entry_count(shell_cmd_t);
return shell_help_generic(argc, argv,
"nano-shell, version 1.0.0.",
start, count);
}
int shell_help_generic(int argc, char *const argv[],
const char* preamble,
const shell_cmd_t* start, unsigned int count)
{
if (argc == 1) {
shell_puts(preamble);
shell_puts("\r\n"
#if CONFIG_SHELL_CMD_LONG_HELP
"Type `help name' to find out more about the function `name'.\r\n"
#endif
"\r\n");
shell_print_cmd_list(start, count);
shell_puts("\r\n");
}
#if CONFIG_SHELL_CMD_LONG_HELP
else {
for (int i = 1; i < argc; i++) {
shell_print_cmd_help(argv[i], start, count);
}
}
#endif /* CONFIG_SHELL_CMD_LONG_HELP */
return 0;
}
NANO_SHELL_ADD_CMD(help,
shell_cmd_help,
"help [pattern ...]",
" Print information about builtin commands.\r\n"
"\r\n"
" If PATTERN is specified, gives detailed help on all commands\r\n"
" matching PATTERN, otherwise print the list of all available commands.\r\n"
"\r\n"
" Arguments:\r\n"
" PATTERN: specifiying the help topic\r\n");
#endif /* CONFIG_SHELL_CMD_BUILTIN_HELP */

View File

@ -0,0 +1,80 @@
/**
* @file command.c
* @author Liber (lvlebin@outlook.com), Cédric CARRÉE (beg0@free.fr)
* @brief
* @version 1.0
* @date 2020-03-24
*
* @copyright Copyright (c) Liber 2020
*
*/
#include <string.h>
#include "shell_io/shell_io.h"
#include "command.h"
const shell_cmd_t *shell_find_top_cmd(const char *cmd_name)
{
const shell_cmd_t *start = _shell_entry_start(shell_cmd_t);
unsigned int count = _shell_entry_count(shell_cmd_t);
return shell_find_cmd(cmd_name, start, count);
}
const shell_cmd_t *shell_find_cmd(const char *cmd_name, const shell_cmd_t* start, unsigned int count)
{
const shell_cmd_t *tmp = start;
if (cmd_name == NULL || start == NULL) {
return NULL;
}
while (count) {
if (strcmp(cmd_name, tmp->name) == 0) {
return tmp;
}
count--;
tmp++;
}
return NULL;
}
int shell_run_cmd(int argc, char *const argv[])
{
if (argc > 0) {
const shell_cmd_t *pCmdt = shell_find_top_cmd(argv[0]);
if (pCmdt) {
return pCmdt->cmd(pCmdt, argc, argv);
}
shell_printf(" %s: command not found.\r\n", argv[0]);
}
return -1;
}
int shell_run_subcmd_implem(const shell_cmd_t* pCmdt,
int argc, char* const argv[],
shell_cmd_cb_t fallback_fct,
const shell_cmd_t* subcommands, unsigned int subcommands_count)
{
if (argc > 1) {
const shell_cmd_t* pSubCmdt = shell_find_cmd(argv[1], subcommands, subcommands_count);
if (pSubCmdt) {
return pSubCmdt->cmd(pSubCmdt, argc - 1, argv + 1);
}
else if(fallback_fct) {
return fallback_fct(pCmdt, argc, argv);
}
else {
shell_printf(" %s: sub-command not found.\r\n", argv[1]);
}
}
else if(fallback_fct) {
return fallback_fct(pCmdt, argc, argv);
}
return -1;
}

View File

@ -0,0 +1,249 @@
/**
* @file command.h
* @author Liber (lvlebin@outlook.com), Cédric CARRÉE (beg0@free.fr)
* @brief
* @version 1.0
* @date 2020-03-23
*
* @copyright Copyright (c) Liber 2020
*
*/
#ifndef __NANO_SHELL_COMMAND_H
#define __NANO_SHELL_COMMAND_H
#include "shell_linker.h"
#include "shell_config.h"
// Forward delecation of shell command structure
struct _shell_cmd_s;
/**
* @brief this is the implementation function of the command.
*
* @param pCmdt: pointer of the structure.
* @param argc: the count of arguments.
* @param argv: argument vector.
* @return 0 if succeed, else non-zero. (return value is not used in ver1.0)
*
* @note the command name is the first argument, argv[0], so argc is always at least 1.
*/
typedef int (*shell_cmd_cb_t)(const struct _shell_cmd_s *pCmdt, int argc, char *const argv[]);
// shell command structure
typedef struct _shell_cmd_s {
const char *name; // command name
shell_cmd_cb_t cmd; // Callback function to run the shell command
#if CONFIG_SHELL_CMD_BRIEF_USAGE
const char *brief_usage; // brief usage of the command.
#endif
#if CONFIG_SHELL_CMD_LONG_HELP
const char *help; // detailed help information of the command.
#endif
} shell_cmd_t;
// shell function structure
typedef struct {
const char *name; // function name
const int param_n; // number of parameters
int (*func)(); // function pointr.
#if CONFIG_SHELL_FUNC_BRIEF_USAGE
const char *brief; // brief summaries of the command.
#endif
} shell_func_t;
#if CONFIG_SHELL_CMD_BRIEF_USAGE
#define _CMD_BRIEF(x) x,
#else
#define _CMD_BRIEF(x)
#endif /* CONFIG_SHELL_CMD_BRIEF_USAGE */
#if CONFIG_SHELL_CMD_LONG_HELP
#define _CMD_HELP(x) x,
#else
#define _CMD_HELP(x)
#endif /* CONFIG_SHELL_CMD_LONG_HELP */
#if CONFIG_SHELL_FUNC_BRIEF_USAGE
#define _FUNC_BRIEF(x) x,
#else
#define _FUNC_BRIEF(x)
#endif /* CONFIG_SHELL_FUNC_BRIEF_USAGE */
#define _shell_cmd_complete(_name, _func, _brief, _help) \
{ #_name, _func, _CMD_BRIEF(_brief) _CMD_HELP(_help) }
#define _shell_func_complete(_name, _nparam, _func, _brief) \
{ #_name, _nparam, _func, _FUNC_BRIEF(_brief) }
/**
* @brief add a command to nano-shell
*
* @_name: name of the command. Note: THIS IS NOT a string.
* @_func: function pointer: (*cmd)(const shell_cmd_t *, int, int, char *const[]).
* @_brief: brief summaries of the command. This is a string.
* @_help: detailed help information of the command. This is a string.
*/
#define NANO_SHELL_ADD_CMD(_name, _func, _brief, _help) \
_shell_entry_declare(shell_cmd_t, _name) = _shell_cmd_complete(_name, _func, _brief, _help)
/**
* @brief add a function to nano-shell.
*
* @_name: name of the function. Note: THIS IS NOT a string.
* @_nparam: param num of the function.
* @_func: pointer of the function.
* @_brief: brief summaries of the function. This is a string.
*/
#define NANO_SHELL_ADD_FUNC(_name, _nparam, _func, _brief) \
_shell_entry_declare(shell_func_t, _name) = _shell_func_complete(_name, _nparam, _func, _brief)
#if CONFIG_SHELL_CMD_BUILTIN_HELP
#define _shell_help_subcmd_entry(_name) \
NANO_SHELL_SUBCMD_ENTRY(help, _name ## _subcmd_help, \
"help [pattern ...]", \
" Print information about subcommands of " # _name ".\r\n" \
"\r\n" \
" If PATTERN is specified, gives detailed help on all commands\r\n" \
" matching PATTERN, otherwise print the list of all available commands.\r\n" \
"\r\n" \
" Arguments:\r\n" \
" PATTERN: specifiying the help topic\r\n"),
#define _shell_help_subcmd_declare(_name) \
static int _name ## _subcmd_help(const shell_cmd_t* pCmd, int argc, char* const argv[]);
#define _shell_help_subcmd_define(_name) \
static int _name ## _subcmd_help(const shell_cmd_t* pCmd, int argc, char* const argv[]) \
{ \
const unsigned int subcommands_count = sizeof(_name ## _subcommands)/sizeof(shell_cmd_t); \
return shell_help_generic( \
argc, argv, \
"Help for " #_name, \
_name ## _subcommands, subcommands_count); \
}
#else
#define _shell_help_subcmd_entry(_name)
#define _shell_help_subcmd_declare(_name)
#define _shell_help_subcmd_define(_name)
#endif /* CONFIG_SHELL_CMD_BUILTIN_HELP */
/**
* @brief Add a sub command in a group of sub-command
*
* To be used as the last arguments of @ref NANO_SHELL_DEFINE_SUBCMDS()
* The syntax is similar to @ref NANO_SHELL_ADD_CMD()
*
* @param _name: name of the command. Note: THIS IS NOT a string.
* @param _func: function pointer: (*cmd)(const shell_cmd_t *, int, int, char *const[]).
* @param _brief: brief summaries of the command. This is a string.
* @param _help: detailed help information of the command. This is a string.
*/
#define NANO_SHELL_SUBCMD_ENTRY(_name, _func, _brief, _help) _shell_cmd_complete(_name, _func, _brief, _help)
/**
* @brief Get the name of the function implementing a sub-command group in nano-shell
*
* @param _name name of the group of sub-commands
*
* @note this macro is to be used for the @c _func parameter of @ref NANO_SHELL_ADD_CMD() or @c _func parameter of @ref NANO_SHELL_SUBCMD_ENTRY()
*/
#define NANO_SHELL_SUBCMDS_FCT(_name) _name ## _shell_cmd
/**
* @brief Define a group of sub-commands in nano-shell
*
* @param _name name of the group of sub-commands
* @param fallback_fct: function that will be run if no subcommand can be found (either @c argc is 1 or argv[1] is not found in @c subcommand)
* @param ... A list of @ref NANO_SHELL_SUBCMD_ENTRY() that define the list of sub-commands
*/
#define NANO_SHELL_DEFINE_SUBCMDS(_name, fallback_fct, ...) \
_shell_help_subcmd_declare(_name) \
static const shell_cmd_t _name ## _subcommands[] = { \
_shell_help_subcmd_entry(_name) \
__VA_ARGS__ }; \
_shell_help_subcmd_define(_name) \
int NANO_SHELL_SUBCMDS_FCT(_name)(const shell_cmd_t* pCmd, int argc, char* const argv[]) \
{ \
const unsigned int subcommands_count = sizeof(_name ## _subcommands)/sizeof(shell_cmd_t); \
return shell_run_subcmd_implem(pCmd, argc, argv, \
fallback_fct, _name ## _subcommands, subcommands_count); \
}
/**
* @brief Find a shell command by name
*
* Find in the list of commandes registred by @ref NANO_SHELL_ADD_CMD().
*
* @param cmd_name name of the shell command to search
* @return const shell_cmd_t*
*/
const shell_cmd_t *shell_find_top_cmd(const char *cmd_name);
/**
* @brief Find a shell command by name in a specific list of commands
*
* @param cmd_name name of the shell command to search
* @param cmds list of commands to search
* @count number of entries in @c cmds
* @return const shell_cmd_t*
*/
const shell_cmd_t *shell_find_cmd(const char *cmd_name, const shell_cmd_t* cmds, unsigned int count);
/**
* @brief Run a shell command from a parsed line
*
* @param argc
* @param argv
* @return int
*/
int shell_run_cmd(int argc, char *const argv[]);
/**
* @brief Implementation function for @ref NANO_SHELL_ADD_CMD_WITH_SUB
*
* @param pCmdt: pointer of the structure.
* @param argc: the count of arguments.
* @param argv: argument vector.
* @param fallback_fct: function that will be run if no subcommand can be found (either @c argc is 1 or argv[1] is not found in @c subcommand)
* @param subcommands: a list of sub-commands
* @param subcommands_count: number of entries in @c subcommands
*
* @return 0 if succeed, else non-zero. (return value is not used in ver1.0)
*/
int shell_run_subcmd_implem(const shell_cmd_t* pCmdt,
int argc, char* const argv[],
shell_cmd_cb_t fallback_fct,
const shell_cmd_t* subcommands, unsigned int subcommands_count);
/**
* @brief Implementation function for 'help' command (or sub-command)
*
* @param argc: the count of arguments.
* @param argv: argument vector.
* @param preamble: text that will appears before the list of commands
* @param start first command in the list of commands that we want to display helps for
* @param count number of command in the list of command
*
* @return 0 if succeed, else non-zero. (return value is not used in ver1.0)
*/
int shell_help_generic(int argc, char *const argv[],
const char* preamble,
const shell_cmd_t* start, unsigned int count);
#endif /* __NANO_SHELL_COMMAND_H */

View File

@ -0,0 +1,62 @@
/**
* @file command.h
* @author Liber (lvlebin@outlook.com)
* @brief
* @version 1.0
* @date 2020-03-23
*
*/
#ifndef __NANO_SHELL_LINKER_H
#define __NANO_SHELL_LINKER_H
#define __align(x) __attribute__((aligned(x)))
/**
* @brief array entry declare.
* @_type: data type of the entry.
* @_name: name of the entry.
*/
#define _shell_entry_declare(_type, _name) \
static const _type nano_shell_##_type##_##_name __align(4) \
__attribute__((used, section(".nano_shell_" #_type "_1_" #_name)))
/**
* @brief: get the pointer of first entry.
* @_type: data type of the entry.
*/
#define _shell_entry_start(_type) \
({ \
static char start[0] __align(4) \
__attribute__((unused, section(".nano_shell_" #_type "_0"))); \
(_type *)&start; \
})
/**
* @brief: get the pointer after last entry.
* @_type: data type of the entry.
*/
#define _shell_entry_end(_type) \
({ \
static char end[0] __align(4) \
__attribute__((unused, section(".nano_shell_" #_type "_2"))); \
(_type *)&end; \
})
/**
* @brief: get the number of elements.
* @_type: data type of the entry.
*/
#define _shell_entry_count(_type) \
({ \
_type *start = _shell_entry_start(_type); \
_type *end = _shell_entry_end(_type); \
unsigned int count = end - start; \
count; \
})
#endif /* __NANO_SHELL_LINKER_H */

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

View File

@ -0,0 +1,120 @@
/**
* @file nano_shell.c
* @author Liber (lvlebin@outlook.com), Cédric CARRÉE (beg0@free.fr)
* @brief nano-shell: a light but powerful shell designed for embedded systems.
* @version 1.0
* @date 2020-03-27
*
* @copyright Copyright (c) Liber 2020
*
*/
#include <string.h>
#include "nano_shell.h"
#include "shell_io/shell_io.h"
#include "command/command.h"
#include "readline/readline.h"
#include "parse/text_parse.h"
#include "shell_config.h"
#define NANO_SHELL_BUILD_VERDION "1.0"
/**
* @brief
*
* @param argc: MUST be larger than 0
* @param argv:
* @return int
*/
int nano_shell_run_cmd(int argc, char *const argv[])
{
const shell_cmd_t *pCmdt = shell_find_top_cmd(argv[0]);
if (pCmdt) {
return pCmdt->cmd(pCmdt, argc, argv);
}
shell_printf(" %s: command not found.\r\n", argv[0]);
return -1;
}
#if (CONFIG_SHELL_CMD_MAX_ARGC < 1)
#error "CONFIG_SHELL_CMD_MAX_ARGC must be no less than 1."
#endif
void nano_shell_loop(void *argument)
{
static char *argv[CONFIG_SHELL_CMD_MAX_ARGC + 1];
char *line;
int argc;
shell_puts("\r\n"
" _ _ ____ _ _ _\r\n"
"| \\ | | __ _ _ __ ___ / ___|| |__ ___| | |\r\n"
"| \\| |/ _` | '_ \\ / _ \\ \\___ \\| '_ \\ / _ \\ | |\r\n"
"| |\\ | (_| | | | | (_) | ___) | | | | __/ | |\r\n"
"|_| \\_|\\__,_|_| |_|\\___/ |____/|_| |_|\\___|_|_|\r\n"
"\r\n"
"Welcome to Nano-Shell "NANO_SHELL_BUILD_VERDION"\r\n"
"\r\n"
" * Build: "__DATE__" - "__TIME__"\r\n"
" * Source: https://github.com/lebinlv/nano-shell\r\n"
" * Copyright: (c) Liber 2020\r\n"
"\r\n");
for (;;) {
line = readline(CONFIG_SHELL_PROMPT);
argc = nano_shell_parse_line(line, argv, CONFIG_SHELL_CMD_MAX_ARGC + 1);
// shell_printf("[DEBUG] argc: %d\r\n", argc);
// for (int i = 0; i < argc; i++) {
// shell_printf("[DEBUG] ARGV[%d]: %s\r\n", i, argv[i]);
// }
if (argc > CONFIG_SHELL_CMD_MAX_ARGC) {
argc--;
shell_printf("** WARNING: too many args (max: %d)! ", CONFIG_SHELL_CMD_MAX_ARGC);
shell_printf("arguments after \"%s\" will be ignored. **\r\n", argv[argc - 1]);
}
if (argc > 0) {
nano_shell_run_cmd(argc, argv);
}
}
}
void nano_shell_react(char ch)
{
static char *argv[CONFIG_SHELL_CMD_MAX_ARGC + 1];
int argc;
char *line = readline_react(ch);
if (line) {
/**
* in react mode, use if (* line) to avoid unnecessary process
* to improve speed.
*/
if (*line) {
argc = nano_shell_parse_line(line, argv, CONFIG_SHELL_CMD_MAX_ARGC + 1);
if (argc > CONFIG_SHELL_CMD_MAX_ARGC) {
argc--;
shell_printf("** WARNING: too many args (max: %d)! ", CONFIG_SHELL_CMD_MAX_ARGC);
shell_printf("arguments after \"%s\" will be ignored. **\r\n", argv[argc - 1]);
}
if (argc > 0) {
nano_shell_run_cmd(argc, argv);
}
}
if (CONFIG_SHELL_PROMPT) {
shell_puts(CONFIG_SHELL_PROMPT);
}
}
}

View File

@ -0,0 +1,34 @@
/**
* @file nano_shell.h
* @author Liber (lvlebin@outlook.com)
* @brief nano-shell interface. include this file in your project.
* @version 1.0
* @date 2020-03-27
*
* @copyright Copyright (c) Liber 2020
*
*/
#ifndef __NANO_SHELL_H
#define __NANO_SHELL_H
/**
* @brief nano-shell infinite loop
*
* @param argument not used in ver1.0
*/
void nano_shell_loop(void *argument);
/**
* @brief nano-shell non-block interface, just react to the input character.
* It is non-blocked (unless there is an infinite loop in your command function)
* you can call it when get a new character.
*
* @param ch input character
*/
void nano_shell_react(char ch);
#endif /*__NANO_SHELL_H */

View File

@ -0,0 +1,13 @@
TOP_DIR = ../../../..
sinclude $(TOP_DIR)/tools/w800/conf.mk
ifndef PDIR
GEN_LIBS = libparse$(LIB_EXT)
endif
#DEFINES +=
sinclude $(TOP_DIR)/tools/w800/rules.mk
INCLUDES := $(INCLUDES) -I $(PDIR)include
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile

View File

@ -0,0 +1,54 @@
/**
* @file text_parse.c
* @author Liber (lvlebin@outlook.com)
* @brief
* @version 1.0
* @date 2020-03-28
*
* @copyright Copyright (c) Liber 2020
*
*/
#include <stddef.h>
#include "text_parse.h"
#define isblank(c) ((c) == ' ' || (c) == '\t')
int nano_shell_parse_line(char *input, char *argv[], const int maxArgc)
{
char tmp;
int nargc = 0;
while (nargc < maxArgc) {
while (isblank(*input)) {
input++;
}
if (*input == '\0') { // end of input
argv[nargc] = NULL;
break;
}
tmp = *input;
// single quotes ('') and double quotes ("")
if (tmp == '\'' || tmp == '"') {
argv[nargc] = ++input;
while (*input && (*input != tmp)) {
input++;
}
} else { // normal character
argv[nargc] = input++;
while (*input && !isblank(*input)) {
input++;
}
}
nargc++;
if (*input) {
*input++ = '\0'; /* terminate current arg */
}
}
return nargc;
}

View File

@ -0,0 +1,27 @@
/**
* @file text_parse.h
* @author Liber (lvlebin@outlook.com)
* @brief
* @version 1.0
* @date 2020-03-28
*
* @copyright Copyright (c) Liber 2020
*
*/
#ifndef __NANO_SHELL_TEXT_PARSE_H
#define __NANO_SHELL_TEXT_PARSE_H
/**
* @brief parse the line, doesn't support backslash('\') in ver1.0
*
* @param input: the line to be parsed.
* @param argv:
* @param maxArgc: max number of arguments.
* @return int: the number of parsed arguments.
*/
int nano_shell_parse_line(char *input, char *argv[], const int maxArgc);
#endif /* __NANO_SHELL_TEXT_PARSE_H */

View File

@ -0,0 +1,13 @@
TOP_DIR = ../../../..
sinclude $(TOP_DIR)/tools/w800/conf.mk
ifndef PDIR
GEN_LIBS = libreadline$(LIB_EXT)
endif
#DEFINES +=
sinclude $(TOP_DIR)/tools/w800/rules.mk
INCLUDES := $(INCLUDES) -I $(PDIR)include
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile

View File

@ -0,0 +1,115 @@
/**
* @file history.c
* @author Liber (lvlebin@outlook.com)
* @brief history manager
* @version 1.0
* @date 2020-03-18
*
* @copyright Copyright (c) Liber 2020
*
*/
#include <string.h>
#include "history.h"
#include "shell_config.h"
#if CONFIG_SHELL_HIST_MIN_RECORD > 0
typedef unsigned char len_t;
/**
memory view of the history buffer:
-------------------------------------------------------------------------------------------
|length| string |length| *** |length| string |length| |
|<---- 1st record ---->| *** |<---- record ---->| |
^ ^ ^ ^
&buffer[0] cursor tail buffer end
(new record will be saved here)
-------------------------------------------------------------------------------------------
Let the data type of `length` be `len_t`,
then the value of length: length = strlen(string) + 1 + 2*sizeof(len_t)
*/
#define TOTAL_BUFFER_SIZE \
(CONFIG_SHELL_HIST_MIN_RECORD * (CONFIG_SHELL_INPUT_BUFFSIZE + 1 + 2 * sizeof(len_t)))
static char historyBuffer[TOTAL_BUFFER_SIZE]; // history buffer
#define HISTORY_BUFFER_BEGIN() (&historyBuffer[0])
#define HISTORY_BUFFER_END() (&historyBuffer[TOTAL_BUFFER_SIZE])
#define GET_RECORD_SIZE(pRecord) ((len_t)(*((len_t *)(pRecord))))
static char *historyCursor = HISTORY_BUFFER_BEGIN();
static char *historyTail = HISTORY_BUFFER_BEGIN(); // new record will be saved here
char *rl_history_next(void)
{
if (historyCursor >= historyTail || // cursor point to the tail
historyCursor + GET_RECORD_SIZE(historyCursor) >= historyTail // cursor point to the last one
) {
return NULL;
}
historyCursor += GET_RECORD_SIZE(historyCursor);
return historyCursor + sizeof(len_t);
}
char *rl_history_prev(void)
{
if (historyTail != HISTORY_BUFFER_BEGIN() && // buffer is not empty
historyCursor > HISTORY_BUFFER_BEGIN() // cursor does not point to the first
) {
historyCursor -= GET_RECORD_SIZE(historyCursor - sizeof(len_t));
return historyCursor + sizeof(len_t);
}
return NULL;
}
void rl_history_add(char *input)
{
size_t freeSpace = HISTORY_BUFFER_END() - historyTail;
len_t inputLength = strlen(input) + 1;
len_t newRecordLength = inputLength + 2 * sizeof(len_t);
if (freeSpace < newRecordLength) {
len_t tmpLength;
char *tmpRecord = HISTORY_BUFFER_BEGIN();
do {
tmpLength = GET_RECORD_SIZE(tmpRecord);
freeSpace += tmpLength;
tmpRecord += tmpLength;
} while (freeSpace < newRecordLength);
memmove(HISTORY_BUFFER_BEGIN(), tmpRecord, historyTail - tmpRecord);
historyTail -= (tmpRecord - HISTORY_BUFFER_BEGIN());
}
/* put the new record in the history buffer */
*((len_t *)historyTail) = newRecordLength;
memcpy(historyTail + sizeof(len_t), input, inputLength);
historyTail += newRecordLength; // move tail to the end of the new record
*((len_t *)(historyTail - sizeof(len_t))) = newRecordLength;
/* set cursor point to the end */
historyCursor = historyTail;
}
void rl_history_rm_last(void)
{
if (historyTail > HISTORY_BUFFER_BEGIN()) {
historyTail -= GET_RECORD_SIZE(historyTail - sizeof(len_t));
historyCursor = historyTail;
}
}
#endif /* CONFIG_SHELL_HIST_MIN_RECORD > 0 */

View File

@ -0,0 +1,46 @@
/**
* @file history.h
* @author Liber (lvlebin@outlook.com)
* @brief history manage interface
* @version 1.0
* @date 2020-03-20
*
* @copyright Copyright (c) Liber 2020
*
*/
#ifndef __NANO_SHELL_HISTORY_H
#define __NANO_SHELL_HISTORY_H
/**
* @brief add a new record
*
* @param input
*/
void rl_history_add(char *input);
/**
* @brief Get next record
*
* @return char*
*/
char *rl_history_next(void);
/**
* @brief Get previous record
*
* @return char*
*/
char *rl_history_prev(void);
/**
* @brief Remove last record
*
*/
void rl_history_rm_last(void);
#endif /* __NANO_SHELL_HISTORY_H */

View File

@ -0,0 +1,98 @@
/**
* @file key_seq.c
* @author Liber (lvlebin@outlook.com)
* @brief ESC Control Sequence recognize and key-sequence-map.
* @version 1.0
* @date 2020-03-21
*
* @copyright Copyright (c) Liber 2020
*
*/
#ifndef __NANO_SEHLL_KEY_SEQ_MAP_H
#define __NANO_SHELL_KEY_SEQ_MAP_H
#include "key_seq.h"
#include "shell_io/shell_io.h"
#include "shell_config.h"
extern void rl_get_pre_history(void); // `up arrow` or `Ctrl P`
extern void rl_get_next_history(void); // `down arrow` or `Ctrl N`
extern void rl_backward_cursor(void); // `right arrow` or `Ctrl F`
extern void rl_forward_cursor(void); // `left arrow` or `Ctrl B`
extern void rl_line_home(void); // `Home`
extern void rl_line_end(void); // `End`
extern void rl_delete(void); // `Delete`
#if CONFIG_SHELL_KEY_SEQ_BIND
const static key_seq_t key_seq_map[] = {
#if CONFIG_SHELL_HIST_MIN_RECORD > 0
{CONVERT_KEY_SEQ('\033', '[', 'A', 0), rl_get_pre_history}, // up arrow
{CONVERT_KEY_SEQ('\033', '[', 'B', 0), rl_get_next_history}, // down arrow
// {CONVERT_KEY_SEQ('\033', 'O', 'A', 0), rl_get_pre_history},
// {CONVERT_KEY_SEQ('\033', 'O', 'B', 0), rl_get_next_history},
#endif /* CONFIG_SHELL_HIST_MIN_RECORD */
#if CONFIG_SHELL_LINE_EDITING
{CONVERT_KEY_SEQ('\033', '[', 'C', 0), rl_backward_cursor}, // right arrow
{CONVERT_KEY_SEQ('\033', '[', 'D', 0), rl_forward_cursor}, // left arrow
{CONVERT_KEY_SEQ('\033', '[', 'H', 0), rl_line_home}, // home
{CONVERT_KEY_SEQ('\033', '[', 'F', 0), rl_line_end}, // end
// {CONVERT_KEY_SEQ('\033', 'O', 'C', 0), rl_forward_cursor},
// {CONVERT_KEY_SEQ('\033', 'O', 'D', 0), rl_backward_cursor},
// {CONVERT_KEY_SEQ('\033', 'O', 'H', 0), rl_line_home},
// {CONVERT_KEY_SEQ('\033', 'O', 'F', 0), rl_line_end},
{CONVERT_KEY_SEQ('\033', '[', '3', '~'), rl_delete}, // delete
#endif /* CONFIG_SHELL_LINE_EDITING */
};
#define KEY_SEQ_MAP_SIZE (sizeof(key_seq_map) / sizeof(key_seq_t))
extern int _rl_key_seq_len;
void rl_dispatch_seq(char ch)
{
static uint32_t key_seq_val, key_seq_mask;
uint32_t offset, miss_match, tmp_val;
_rl_key_seq_len++;
offset = ((uint32_t)(sizeof(uint32_t) - _rl_key_seq_len)) << 3; // (4-_rl_key_seq_len)*8
key_seq_val |= (((uint32_t)ch) << offset);
key_seq_mask |= (0xFF << offset);
miss_match = 1;
for (int i = 0; i < KEY_SEQ_MAP_SIZE; i++) {
tmp_val = key_seq_map[i].key_seq_val;
if ((tmp_val & key_seq_mask) == key_seq_val) { // partial match
if (key_seq_val == tmp_val) { // full match
key_seq_val = 0;
key_seq_mask = 0;
_rl_key_seq_len = 0;
key_seq_map[i].key_func();
return;
}
miss_match = 0;
}
}
if (miss_match) {
key_seq_val = 0;
key_seq_mask = 0;
_rl_key_seq_len = 0;
shell_putc('\a');
}
}
#endif /* CONFIG_SHELL_KEY_SEQ_BIND */
#endif /* __NANO_SHELL_KEY_SEQ_MAP_H */

View File

@ -0,0 +1,33 @@
/**
* @file key_seq.h
* @author Liber (lvlebin@outlook.com)
* @brief
* @version 1.0
* @date 2020-03-21
*
* @copyright Copyright (c) Liber 2020
*
*/
#ifndef __NANO_SHELL_KEY_SEQ_H
#define __NANO_SHELL_KEY_SEQ_H
#include <stdint.h>
typedef uint32_t u32;
typedef uint8_t u8;
#define CONVERT_KEY_SEQ(c1, c2, c3, c4) \
((u32)((((u8)(c1)) << 24) | (((u8)(c2)) << 16) | (((u8)(c3)) << 8) | (((u8)(c4)) << 0)))
typedef struct {
u32 key_seq_val;
void (*key_func)(void);
} key_seq_t;
void rl_dispatch_seq(char ch);
#endif /* __NANO_SHELL_KEY_SEQ_H */

View File

@ -0,0 +1,419 @@
/**
* @file readline.c
* @author Liber (lvlebin@outlook.com)
* @brief readline component of nano-shell
* @version 1.0
* @date 2020-03-21
*
* @copyright Copyright (c) Liber 2020
*
*/
#include <string.h>
#include "readline.h"
#include "shell_io/shell_io.h"
#include "history.h"
#include "key_seq.h"
#include "shell_config.h"
#define CTL_CH(ch) ((ch) - 'A' + 1)
#define U_SHELL_ALERT() shell_putc('\a')
// erase sequence, used to erase one character on screen.
static const char _erase_seq[] = "\b \b";
// console input buffer
static char _rl_line_buffer[CONFIG_SHELL_INPUT_BUFFSIZE + 1];
// non-zero means readline completed.
static int _rl_done;
/**
* The number of characters present in `_rl_line_buffer`.
* 0 <= `_rl_end` <= `CONFIG_SHELL_INPUT_BUFFSIZE`
* When `_rl_cursor` is at the end of the line, `_rl_cursor` and `_rl_end` are equal.
* Note that the value of `_rl_line_buffer[_rl_end]` should be `\0` in any case.
*/
static int _rl_end;
#if CONFIG_SHELL_LINE_EDITING
// The offset of the current cursor position in `_rl_line_buffer`
// 0 <= `_rl_cursor` <= `_rl_end`
static int _rl_cursor;
#endif /* CONFIG_SHELL_LINE_EDITING */
#if CONFIG_SHELL_KEY_SEQ_BIND
/* uesed by @file{key_seq.c} to recognize key sequences */
int _rl_key_seq_len = 0;
#endif
void rl_end_input(void);
#if CONFIG_SHELL_MULTI_LINE
static int _rl_home;
/**
* @brief Judge whether the line should be continued
*
* @return int 1: continue.
* 0: no continue, start a new line.
*/
int rl_should_continue()
{
// in version 1.0, only judged whether the last character is '\' or not
return (_rl_end > _rl_home && _rl_line_buffer[_rl_end-1] == '\\');
}
void rl_new_line()
{
if (rl_should_continue()) {
_rl_line_buffer[--_rl_end] = '\0'; // overwrite the backslash('\')
_rl_home = _rl_end;
#if CONFIG_SHELL_LINE_EDITING
_rl_cursor = _rl_end; // update _rl_cursor if LINE_EDITING is enabled.
#endif /* CONFIG_SHELL_LINE_EDITING */
shell_puts("\r\n> ");
} else {
rl_end_input();
}
}
#else
#define _rl_home 0
#define rl_new_line() rl_end_input()
#endif /* CONFIG_SHELL_MULTI_LINE */
void rl_end_input(void)
{
#if CONFIG_SHELL_HIST_MIN_RECORD > 0
if (*_rl_line_buffer) {
rl_history_add(_rl_line_buffer);
}
#endif /*CONFIG_SHELL_HIST_MIN_RECORD */
#if CONFIG_SHELL_MULTI_LINE
_rl_home = 0;
#endif /* CONFIG_SHELL_MULTI_LINE */
#if CONFIG_SHELL_LINE_EDITING
_rl_cursor = 0;
#endif /* CONFIG_SHELL_LINE_EDITING */
_rl_end = 0;
_rl_done = 1;
shell_puts("\r\n");
}
// add one character to the buffer
void rl_add_char(char ch)
{
if (_rl_end < CONFIG_SHELL_INPUT_BUFFSIZE && ch >= ' ') {
#if CONFIG_SHELL_LINE_EDITING
int len = _rl_end - _rl_cursor;
_rl_end++;
_rl_line_buffer[_rl_end] = '\0';
memmove(&_rl_line_buffer[_rl_cursor + 1], &_rl_line_buffer[_rl_cursor], len);
_rl_line_buffer[_rl_cursor] = ch;
shell_puts(&_rl_line_buffer[_rl_cursor++]);
while (len > 0) {
shell_putc('\b');
len--;
}
#else
shell_putc(ch);
_rl_line_buffer[_rl_end++] = ch;
_rl_line_buffer[_rl_end] = '\0';
#endif /* CONFIG_SHELL_LINE_EDITING */
} else {
U_SHELL_ALERT();
}
}
// Rubout the character behind `_rl_cursor`(Backspace).
void rl_rubout(void)
{
#if CONFIG_SHELL_LINE_EDITING
if (_rl_cursor > _rl_home) {
int len = _rl_end - (--_rl_cursor);
_rl_end--;
memmove(&_rl_line_buffer[_rl_cursor], &_rl_line_buffer[_rl_cursor + 1], len);
shell_putc('\b');
shell_puts(&_rl_line_buffer[_rl_cursor]);
shell_putc(' ');
do {
shell_putc('\b');
len--;
} while (len > 0);
#else
if (_rl_end > _rl_home) {
_rl_end--;
_rl_line_buffer[_rl_end] = '\0';
shell_puts(_erase_seq);
#endif /* CONFIG_SHELL_LINE_EDITING */
} else {
U_SHELL_ALERT();
}
}
#if CONFIG_SHELL_HIST_MIN_RECORD > 0
void rl_process_history(const char *history)
{
if (history) {
#if CONFIG_SHELL_LINE_EDITING
shell_puts(&_rl_line_buffer[_rl_cursor]); // move cursor to the end on screen.
#endif
while (_rl_end > _rl_home) { // erase all on the screen.
shell_puts(_erase_seq);
_rl_end--;
}
_rl_end = strlen(history) + _rl_home; // update _rl_end.
#if CONFIG_SHELL_LINE_EDITING
_rl_cursor = _rl_end; // update _rl_cursor if LINE_EDITING is enabled.
#endif
memcpy(_rl_line_buffer + _rl_home, history, _rl_end -_rl_home + 1);
shell_puts(_rl_line_buffer + _rl_home); // display new text and move cursor to the end on screen.
} else {
U_SHELL_ALERT();
}
}
void rl_get_pre_history(void)
{
rl_process_history(rl_history_prev());
}
void rl_get_next_history(void)
{
rl_process_history(rl_history_next());
}
#endif /* CONFIG_SHELL_HIST_MIN_RECORD > 0 */
#if CONFIG_SHELL_LINE_EDITING
// Delete the character under the cursor (Delete).
void rl_delete(void)
{
if (_rl_cursor < _rl_end) {
int len = _rl_end - _rl_cursor;
_rl_end--;
memmove(&_rl_line_buffer[_rl_cursor], &_rl_line_buffer[_rl_cursor + 1], len);
shell_puts(&_rl_line_buffer[_rl_cursor]);
shell_putc(' ');
do {
shell_putc('\b');
len--;
} while (len > 0);
}
}
// Move curosr to the beginning of line.
void rl_line_home(void)
{
while (_rl_cursor > _rl_home) {
shell_putc('\b');
_rl_cursor--;
}
}
// Move cursor to the end of line.
void rl_line_end(void)
{
shell_puts(_rl_line_buffer + _rl_cursor);
_rl_cursor = _rl_end;
}
// Move forward (left).
void rl_forward_cursor(void)
{
if (_rl_cursor > _rl_home) {
shell_putc('\b');
_rl_cursor--;
} else {
U_SHELL_ALERT();
}
}
// Move backward (right).
void rl_backward_cursor(void)
{
if (_rl_cursor < _rl_end) {
shell_putc(_rl_line_buffer[_rl_cursor]);
_rl_cursor++;
} else {
U_SHELL_ALERT();
}
}
// Erase from beginning of line to cursor.
void rl_erase_all_backward(void)
{
if (_rl_cursor > _rl_home) {
int len = _rl_end - _rl_cursor + 1;
shell_puts(&_rl_line_buffer[_rl_cursor]); // move cursor to the end on screen.
while (_rl_end > _rl_home) { // erase all on the screen
shell_puts(_erase_seq);
_rl_end--;
}
memmove(_rl_line_buffer + _rl_home, &_rl_line_buffer[_rl_cursor], len--); // new text.
shell_puts(_rl_line_buffer + _rl_home); // display new text and move cursor to the end on screen.
_rl_cursor = _rl_home;
_rl_end = len + _rl_home;
while (len > 0) { // move cursor to the begin on the screen.
shell_putc('\b');
len--;
}
}
}
// Erase from cursor to end of line.
void rl_erase_all_forward(void)
{
shell_puts(&_rl_line_buffer[_rl_cursor]); // move cursor to the end on screen.
while (_rl_end > _rl_cursor) {
shell_puts(_erase_seq); // erase all right to _rl_cursor, and move screen cursor to _rl_cursor.
_rl_end--;
}
_rl_line_buffer[_rl_end] = '\0';
}
#endif /* CONFIG_SHELL_LINE_EDITING */
void rl_dispatch(char ch)
{
#if CONFIG_SHELL_KEY_SEQ_BIND
if (_rl_key_seq_len) {
rl_dispatch_seq(ch);
return;
}
#endif /* CONFIG_SHELL_KEY_SEQ_BIND */
switch (ch) {
case '\r': // CTL_CH('M')
case '\n': // CTL_CH('J')
rl_new_line();
break;
case CTL_CH('C'):
shell_puts("^C\r\n");
*_rl_line_buffer = '\0';
rl_end_input();
break;
case 255:
case 127:
case 8: // backspace, CTL_CH('H')
rl_rubout();
break;
#if CONFIG_SHELL_KEY_SEQ_BIND
case '\033': // ESC(\033)
rl_dispatch_seq(ch);
break;
#endif /* CONFIG_SHELL_KEY_SEQ_BIND */
#if CONFIG_SHELL_LINE_EDITING
case CTL_CH('A'): // HOME
rl_line_home();
break;
case CTL_CH('E'): // END
rl_line_end();
break;
case CTL_CH('B'): // <-- (left arrow)
rl_forward_cursor();
break;
case CTL_CH('F'): // --> (right arrow)
rl_backward_cursor();
break;
case CTL_CH('K'): // Delete all characters on the right side.
rl_erase_all_forward();
break;
case CTL_CH('U'): // Delete all characters one the left side.
rl_erase_all_backward();
break;
case CTL_CH('D'): // DELETE
rl_delete();
break;
// case CTL_CH('X'):
// case CTL_CH('O'):
// break;
#endif /* CONFIG_SHELL_LINE_EDITING */
#if CONFIG_SHELL_HIST_MIN_RECORD > 0
case CTL_CH('P'): // up arrow
rl_get_pre_history();
break;
case CTL_CH('N'): // down arrow
rl_get_next_history();
break;
#endif /* CONFIG_SHELL_HIST_MIN_RECORD > 0 */
default: // add current character to the buffer
rl_add_char(ch);
break;
}
}
char *readline(const char *promot)
{
char input;
if (promot) {
shell_puts(promot);
}
// clean last line.
_rl_done = 0;
*_rl_line_buffer = '\0';
// start read the new line.
while (_rl_done == 0) {
while (!shell_getc(&input)) {
}
rl_dispatch(input);
}
return _rl_line_buffer;
}
char *readline_react(char ch)
{
if (_rl_done) { // clean last line.
_rl_done = 0;
*_rl_line_buffer = '\0';
}
rl_dispatch(ch);
return (_rl_done ? _rl_line_buffer : NULL);
}

View File

@ -0,0 +1,30 @@
/**
* @file readline.h
* @author Liber (lvlebin@outlook.com)
* @brief readline interface
* @version 1.0
* @date 2020-03-21
*
* @copyright Copyright (c) Liber 2020
*
*/
#ifndef __NANO_SHELL_READLINE_H
#define __NANO_SHELL_READLINE_H
// read a line of input. Prompt with PROMPT. A NULL PROMPT means none.
char *readline(const char *promot);
/**
* @brief react to the input character `ch`.
*
* @param[in] ch: input character.
* @return: NULL means the current line has not been completed (need more input).
*
*/
char *readline_react(char ch);
#endif /* __NANO_SHELL_READLINE_H */

View File

@ -0,0 +1,64 @@
/**
* @file shell_config.h
* @author Liber (lvlebin@outlook.com)
* @brief nano-shell configurations.
* @version 1.0
* @date 2020-03-18
*
* @copyright Copyright (c) Liber 2020
*
*/
#ifndef __NANO_SHELL_CONFIG_H
#define __NANO_SHELL_CONFIG_H
/******************************* readline configuration ****************************/
/* command line input buffer size(byte) */
#define CONFIG_SHELL_INPUT_BUFFSIZE (256U)
/* set 1 to enable command line edit */
#define CONFIG_SHELL_LINE_EDITING 1
/* ESC Control Sequence detect, such as Home, Delete, Arrow, etc. */
#define CONFIG_SHELL_KEY_SEQ_BIND 1
/* set 1 to enable Backslash('\') for line continuation */
#define CONFIG_SHELL_MULTI_LINE 1
/**
* set 0 to disable history record.
*
* nano-shell will take `CONFIG_SHELL_HIST_MIN_RECORD*(2+CONFIG_SHELL_INPUT_BUFFSIZE)` bytes to
* record **at least** `CONFIG_SHELL_HIST_MIN_RECORD` histroys.
* the maximum number of history records depends on the average length of the input.
*/
#define CONFIG_SHELL_HIST_MIN_RECORD (10U)
/******************************* command configuration ****************************/
#define CONFIG_SHELL_FUNC_BRIEF_USAGE 1
#define CONFIG_SHELL_CMD_BRIEF_USAGE 1
#define CONFIG_SHELL_CMD_LONG_HELP 1
/* nano-shell provides a built-in help command, set 0 to disable it */
#define CONFIG_SHELL_CMD_BUILTIN_HELP 1
/* config the max number of arguments, must be no less than 1. */
#define CONFIG_SHELL_CMD_MAX_ARGC (10U)
/******************************* shell io configuration ****************************/
/* config the buffer size (shell_printf()) */
#define CONFIG_SHELL_PRINTF_BUFFER_SIZE 1024U
/******************************* shell configuration ****************************/
#define CONFIG_SHELL_PROMPT "Nano-Shell >> "
#endif /* __NANO_SHELL_CONFIG_H */

View File

@ -0,0 +1,13 @@
TOP_DIR = ../../../..
sinclude $(TOP_DIR)/tools/w800/conf.mk
ifndef PDIR
GEN_LIBS = libshell_io$(LIB_EXT)
endif
#DEFINES +=
sinclude $(TOP_DIR)/tools/w800/rules.mk
INCLUDES := $(INCLUDES) -I $(PDIR)include
PDIR := ../$(PDIR)
sinclude $(PDIR)Makefile

View File

@ -0,0 +1,80 @@
/**
* @file shell_io.c
* @author Liber (lvlebin@outlook.com)
* @brief Example implementation of some functions in file "shell_io.h".
* @version 1.0
* @date 2020-03-24
*
* @copyright Copyright (c) Liber 2020
*
*/
#include <stdio.h>
#include <stdarg.h>
#include "shell_io.h"
#include "shell_config.h"
/**
* @brief This function should do the actual transmission of the character.
* It can also be implemented by macro definition, for example:
* ```
* #define low_level_write_char(ch) \
* do { \
* uart_send_char(ch); \
* } while(0)
* ```
*
* @param ch the character to be transmitted.
*/
extern void low_level_write_char(char ch);
#if defined(__GNUC__)
#ifndef __weak
#define __weak __attribute__((weak))
#endif /* __weak */
#endif /* __GNUC__ */
/****************************************************************/
#if !(CONFIG_SHELL_PRINTF_BUFFER_SIZE > 0)
#error "the value of CONFIG_SHELL_PRINTF_BUFFER_SIZE must be greater than 0!"
#endif
__weak int shell_printf(const char *format, ...)
{
static char shell_printf_buffer[CONFIG_SHELL_PRINTF_BUFFER_SIZE];
int length = 0;
va_list ap;
va_start(ap, format);
length = vsnprintf(shell_printf_buffer, CONFIG_SHELL_PRINTF_BUFFER_SIZE, format, ap);
va_end(ap);
for (int i = 0; i < length; i++) {
low_level_write_char(shell_printf_buffer[i]);
}
return length;
}
__weak void shell_puts(const char *str)
{
while (*str) {
low_level_write_char(*str);
str++;
}
}
__weak void shell_putc(char ch)
{
low_level_write_char(ch);
}

View File

@ -0,0 +1,69 @@
/**
* @file shell_io.h
* @author Liber (lvlebin@outlook.com)
* @brief I/O interface
* @version 1.0
* @date 2020-03-17
*
* @copyright Copyright (c) Liber 2020
*
*/
#ifndef __NANO_SHELL_IO_H
#define __NANO_SHELL_IO_H
/*********************************************************************
nano-shell uses these functions to get/send character from/to stream.
You should implement these functions in your project.
*********************************************************************/
/**
* @brief send a chararcter...
*
*/
extern void shell_putc(char ch);
/**
* @brief send string...
*
*/
extern void shell_puts(const char *str);
/**
* @brief printf() for nano-shell
*
*/
extern int shell_printf(const char *format, ...) __attribute__((format(printf, 1, 2)));
/**
* @brief Get next character available from stream.
* not used in <interrupt mode>.
*
* @param ch Return the character in `ch` if there was...
* @return Result is non-zero if there was a character, or 0 if there wasn't.
*
* @note if you run nano-shell in <main loop mode>, to avoid losing characters, you'd better use a
* low layer receive fifo. Take uart for example, you can detect incoming data using interrupts and
* then store each received character in a first-in-first out (FIFO) buffer.
*
* then `shell_getc(char *ch)` may be like this:
*
* int shell_getc(char *ch)
* {
* if (fifo_empty()) { // if no character in fifo,
* return 0; // return false
* }
*
* *ch = fifo_pop(); // fifo is not empty, get it.
* return 1; // return true
* }
*
*/
extern int shell_getc(char *ch);
#endif /* __NANO_SHELL_IO_H */

View File

@ -0,0 +1,104 @@
/**
* @file fifo.h
* @author Liber (lvlebin@outlook.com)
* @brief simple fifo based on ring buffer
* @version 1.0
* @date 2020-03-24
*
* @copyright Copyright (c) Liber 2020
*
*/
#ifndef __NANO_SHELL_FIFO_H
#define __NANO_SHELL_FIFO_H
/**
* @brief: declare a STATIC fifo
*
* @name: name of the fifo, THIS IS NOT a string.
* @size: MUST be a CONSTANT, and MUST be a POWER OF 2!!! such as 64, 128, 256, 512, etc ...
* @size_type: data type of size, MUST be unsigned!!! such as, uint8_t, uint16_t, uint32_t, etc...
* and max_value(size_type) >= size-1
* @data_type: data type of element.
*
* @example:
* 1). declare a char type fifo: static_fifo_declare(my_fifo, 256, unsigned char, char);
* 2). add a char to the fifo: fifo_push(my_fifo, ch);
* 3). get and remove a char: char ch = fifo_pop(my_fifo);
*
* 4). check manually and then get and remove a char:
* char ch = 0;
* if (is_fifo_empty(my_fifo)) {
* ch = fifo_pop_unsafe(my_fifo);
* }
*
* 5). get a char without remove: char ch = fifo_peek(my_fifo);
* 6). get capacity of the fifo: size_t capacity = get_fifo_capacity(my_fifo);
* 7). get size of the fifo: size_t size = get_fifo_size(my_fifo);
*
* @note: All operations on the same FIFO declared by `static_fifo_declare` must be in the same scope.
*
*/
#define static_fifo_declare(name, size, size_type, data_type) \
static struct { \
size_type head; \
size_type tail; \
data_type buff[size]; \
} _fifo_##name = { 0, 0, {0, } }; \
static const size_type _fifo_size_##name = ((size)-1); // the actual available size is (size-1). use const type for gcc optimization
#define get_fifo_capacity(name) (_fifo_size_##name)
#define get_fifo_size(name) ((unsigned int)(_fifo_##name.head - _fifo_##name.tail))
#define is_fifo_empty(name) (_fifo_##name.head == _fifo_##name.tail)
#define is_fifo_full(name) (_fifo_##name.head - _fifo_##name.tail >= _fifo_size_##name)
/**
* @brief: add a new element to the fifo. if the fifo is full, do nothing.
*
* @name: name of the fifo.
* @data: the new element to be added.
*/
#define fifo_push(name, data) \
do { \
if (!is_fifo_full(name)) { \
_fifo_##name.buff[_fifo_##name.head++ & _fifo_size_##name] = (data); \
} \
} while (0)
/**
* @brief: Returns the last element in the fifo, without remove it.
* If the fifo is empty, return 0.
*
* @name: name of the fifo.
*
*/
#define fifo_peek(name) \
(is_fifo_empty(name) ? 0 : _fifo_##name.buff[_fifo_##name.tail & _fifo_size_##name])
/**
* @brief: remove and return last element without checking if the fifo is empty.
*
* @name: name of the fifo
*/
#define fifo_pop_unsafe(name) \
(_fifo_##name.buff[_fifo_##name.tail++ & _fifo_size_##name])
/**
* @brief: Remove and return last element in the fifo.
* If the fifo is empty, return 0.
*
* @name: name of the fifo.
*/
#define fifo_pop(name) \
(is_fifo_empty(name) ? 0 : _fifo_##name.buff[_fifo_##name.tail++ & _fifo_size_##name])
#endif

6
app_include/app_common.h Normal file
View File

@ -0,0 +1,6 @@
#ifndef APP_COMMON_H
#define APP_COMMON_H
#define NEW_LINE "\r\n"
#endif //APP_COMMON_H

View File

@ -0,0 +1,6 @@
#ifndef NANO_SHELL_INTERFACE_H
#define NANO_SHELL_INTERFACE_H
extern int shell_printf(const char *format, ...);
#endif //NANO_SHELL_INTERFACE_H

Binary file not shown.

Binary file not shown.

BIN
bin/build/w800/lib/libadc.a Normal file

Binary file not shown.

BIN
bin/build/w800/lib/libag.a Normal file

Binary file not shown.

BIN
bin/build/w800/lib/libapi.a Normal file

Binary file not shown.

BIN
bin/build/w800/lib/libapp.a Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
bin/build/w800/lib/libar.a Normal file

Binary file not shown.

BIN
bin/build/w800/lib/libav.a Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
bin/build/w800/lib/libbta.a Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
bin/build/w800/lib/libbtm.a Normal file

Binary file not shown.

BIN
bin/build/w800/lib/libbtu.a Normal file

Binary file not shown.

Binary file not shown.

BIN
bin/build/w800/lib/libco.a Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
bin/build/w800/lib/libcpu.a Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
bin/build/w800/lib/libdm.a Normal file

Binary file not shown.

BIN
bin/build/w800/lib/libdma.a Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
bin/build/w800/lib/libext.a Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More