新建项目
This commit is contained in:
1 parent
5e2e890cfc
commit
633d9b872b
1351 files changed
+730564
No files matched your search
@@ -0,0 +1,17 @@
|
||||
# cpp suport
|
||||
|
||||

|
||||

|
||||

|
||||
|
||||
`letter shell`cpp支持
|
||||
|
||||
## 简介
|
||||
|
||||
`cpp support`是用于扩展`letter shell`,使其可以在cpp环境中生效的组件,`cpp support`仅仅包含一个头文件
|
||||
|
||||
## 使用
|
||||
|
||||
`cpp support`仅仅提供了一个`shell_cpp.h`的头文件,用于在cpp文件中使用`letter shell`的命令导出,在使用时,需要在`.cpp`文件中包含`shell_cpp.h`,而不是`shell.h`,如果一个工程同时包含`.c`和`.cpp`文件,只需要分别包含对应的头文件即可
|
||||
|
||||
注意,对于cpp,`letter shell`也仅支持函数的导出,不适用于类的成员函数
|
||||
@@ -0,0 +1,155 @@
|
||||
/**
|
||||
* @file shell_cpp.h
|
||||
* @author Letter (nevermindzzt@gmail.com)
|
||||
* @brief shell cpp support
|
||||
* @version 1.0.0
|
||||
* @date 2021-01-09
|
||||
*
|
||||
* @copyright (c) 2021 Letter
|
||||
*
|
||||
*/
|
||||
#ifndef __SHELL_CPP_H__
|
||||
#define __SHELL_CPP_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
/**
|
||||
* @brief shell command cpp 支持 cmd 定义
|
||||
*/
|
||||
typedef struct shell_command_cpp_cmd
|
||||
{
|
||||
int attr; /**< 属性 */
|
||||
const char *name; /**< 命令名 */
|
||||
int (*function)(); /**< 命令执行函数 */
|
||||
const char *desc; /**< 命令描述 */
|
||||
} ShellCommandCppCmd;
|
||||
|
||||
/**
|
||||
* @brief shell command cpp 支持 var 定义
|
||||
*/
|
||||
typedef struct shell_command_cpp_var
|
||||
{
|
||||
int attr; /**< 属性 */
|
||||
const char *name; /**< 变量名 */
|
||||
void *value; /**< 变量值 */
|
||||
const char *desc; /**< 变量描述 */
|
||||
} ShellCommandCppVar;
|
||||
|
||||
/**
|
||||
* @brief shell command cpp 支持 user 定义
|
||||
*/
|
||||
typedef struct shell_command_cpp_user
|
||||
{
|
||||
int attr; /**< 属性 */
|
||||
const char *name; /**< 用户名 */
|
||||
const char *password; /**< 用户密码 */
|
||||
const char *desc; /**< 用户描述 */
|
||||
} ShellCommandCppUser;
|
||||
|
||||
/**
|
||||
* @brief shell command cpp 支持 key 定义
|
||||
*/
|
||||
typedef struct shell_command_cpp_key
|
||||
{
|
||||
int attr; /**< 属性 */
|
||||
int value; /**< 按键键值 */
|
||||
void (*function)(Shell *); /**< 按键执行函数 */
|
||||
const char *desc; /**< 按键描述 */
|
||||
} ShellCommandCppKey;
|
||||
|
||||
#if SHELL_USING_CMD_EXPORT == 1
|
||||
|
||||
#undef SHELL_EXPORT_CMD
|
||||
/**
|
||||
* @brief shell 命令定义
|
||||
*
|
||||
* @param _attr 命令属性
|
||||
* @param _name 命令名
|
||||
* @param _func 命令函数
|
||||
* @param _desc 命令描述
|
||||
*/
|
||||
#define SHELL_EXPORT_CMD(_attr, _name, _func, _desc) \
|
||||
const char shellCmd##_name[] = #_name; \
|
||||
const char shellDesc##_name[] = #_desc; \
|
||||
extern "C" SHELL_USED const ShellCommandCppCmd \
|
||||
shellCommand##_name SHELL_SECTION("shellCommand") = \
|
||||
{ \
|
||||
_attr, \
|
||||
shellCmd##_name, \
|
||||
(int (*)())_func, \
|
||||
shellDesc##_name \
|
||||
}
|
||||
|
||||
#undef SHELL_EXPORT_VAR
|
||||
/**
|
||||
* @brief shell 变量定义
|
||||
*
|
||||
* @param _attr 变量属性
|
||||
* @param _name 变量名
|
||||
* @param _value 变量值
|
||||
* @param _desc 变量描述
|
||||
*/
|
||||
#define SHELL_EXPORT_VAR(_attr, _name, _value, _desc) \
|
||||
const char shellCmd##_name[] = #_name; \
|
||||
const char shellDesc##_name[] = #_desc; \
|
||||
extern "C" SHELL_USED const ShellCommandCppVar \
|
||||
shellVar##_name SHELL_SECTION("shellCommand") = \
|
||||
{ \
|
||||
_attr, \
|
||||
shellCmd##_name, \
|
||||
(void *)_value, \
|
||||
shellDesc##_name \
|
||||
}
|
||||
|
||||
#undef SHELL_EXPORT_USER
|
||||
/**
|
||||
* @brief shell 用户定义
|
||||
*
|
||||
* @param _attr 用户属性
|
||||
* @param _name 用户名
|
||||
* @param _password 用户密码
|
||||
* @param _desc 用户描述
|
||||
*/
|
||||
#define SHELL_EXPORT_USER(_attr, _name, _password, _desc) \
|
||||
const char shellCmd##_name[] = #_name; \
|
||||
const char shellPassword##_name[] = #_password; \
|
||||
const char shellDesc##_name[] = #_desc; \
|
||||
extern "C" SHELL_USED const ShellCommandCppUser \
|
||||
shellUser##_name SHELL_SECTION("shellCommand") = \
|
||||
{ \
|
||||
_attr|SHELL_CMD_TYPE(SHELL_TYPE_USER), \
|
||||
shellCmd##_name, \
|
||||
shellPassword##_name, \
|
||||
shellDesc##_name \
|
||||
}
|
||||
|
||||
#undef SHELL_EXPORT_KEY
|
||||
/**
|
||||
* @brief shell 按键定义
|
||||
*
|
||||
* @param _attr 按键属性
|
||||
* @param _value 按键键值
|
||||
* @param _func 按键函数
|
||||
* @param _desc 按键描述
|
||||
*/
|
||||
#define SHELL_EXPORT_KEY(_attr, _value, _func, _desc) \
|
||||
const char shellDesc##_value[] = #_desc; \
|
||||
extern "C" SHELL_USED const ShellCommandCppKey \
|
||||
shellKey##_value SHELL_SECTION("shellCommand") = \
|
||||
{ \
|
||||
_attr|SHELL_CMD_TYPE(SHELL_TYPE_KEY), \
|
||||
_value, \
|
||||
(void (*)(Shell *))_func, \
|
||||
shellDesc##_value \
|
||||
}
|
||||
#endif /** SHELL_USING_CMD_EXPORT == 1 */
|
||||
|
||||
}
|
||||
#endif /**< defined __cplusplus */
|
||||
|
||||
#endif /**< __SHELL_CPP_H__ */
|
||||
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
# letter shell file system support
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
letter shell文件系统支持
|
||||
|
||||

|
||||
|
||||
- [letter shell file system support](#letter-shell-file-system-support)
|
||||
- [简介](#简介)
|
||||
- [使用](#使用)
|
||||
|
||||
## 简介
|
||||
|
||||
fs_support作为letter shell的插件,用于实现letter shell对常见文件系统操作的支持,比如说cd,ls等命令,fs_support依赖于letter shell的伴生对象功能,并且使用到了内存分配和内存释放,所以请确认已经配置好了letter shell
|
||||
|
||||
fs_support并非一个完全实现的letter shell插件,由于文件系统的接口和操作系统以及具体使用的文件系统相关,所以fs_support仅仅通过接入几个基本的接口以实现`cd`,`ls`命令,具体使用时,可能需要根据使用的文件系统接口修改fs_support,letter shell的[demo/x86-gcc](demo/x86-gcc)下有针对linux平台的移植,可以及进行参考
|
||||
|
||||
## 使用
|
||||
|
||||
1. 声明`ShellFs`对象并申请当前路径数据缓冲区
|
||||
|
||||
```c
|
||||
ShellFs shellFs;
|
||||
char shellPathBuffer[512] = "/";
|
||||
```
|
||||
|
||||
2. 实现`getcwd`,`chdir`,`listdir`函数
|
||||
|
||||
根据文件系统不同,这些函数会有不同的实现,请根据具体使用的环境进行修改
|
||||
|
||||
3. 初始化`ShellFs`对象
|
||||
|
||||
```c
|
||||
shellFs.getcwd = getcwd;
|
||||
shellFs.chdir = chdir;
|
||||
shellFs.listdir = userShellListDir;
|
||||
shellFsInit(&shellFs, shellPathBuffer, 512);
|
||||
```
|
||||
|
||||
4. 初始化`Shell`对象
|
||||
|
||||
设置shell当前路径缓冲,初始化shell,并添加伴生对象
|
||||
|
||||
```C
|
||||
shellSetPath(&shell, shellPathBuffer);
|
||||
shellInit(&shell, shellBuffer, 512);
|
||||
shellCompanionAdd(&shell, SHELL_COMPANION_ID_FS, &shellFs);
|
||||
```
|
||||
@@ -0,0 +1,74 @@
|
||||
/**
|
||||
* @file shell_fs.c
|
||||
* @author Letter (nevermindzzt@gmail.com)
|
||||
* @brief shell file system support
|
||||
* @version 0.1
|
||||
* @date 2020-07-22
|
||||
*
|
||||
* @copyright (c) 2020 Letter
|
||||
*
|
||||
*/
|
||||
#include "shell_fs.h"
|
||||
#include "shell.h"
|
||||
#include "stdio.h"
|
||||
|
||||
/**
|
||||
* @brief 改变当前路径(shell调用)
|
||||
*
|
||||
* @param dir 路径
|
||||
*/
|
||||
void shellCD(char *dir)
|
||||
{
|
||||
Shell *shell = shellGetCurrent();
|
||||
ShellFs *shellFs = shellCompanionGet(shell, SHELL_COMPANION_ID_FS);
|
||||
SHELL_ASSERT(shellFs, return);
|
||||
if (shellFs->chdir(dir) != 0)
|
||||
{
|
||||
shellWriteString(shell, "error: ");
|
||||
shellWriteString(shell, dir);
|
||||
shellWriteString(shell, " is not a directory\r\n");
|
||||
}
|
||||
shellFs->getcwd(shellFs->info.path, shellFs->info.pathLen);
|
||||
}
|
||||
SHELL_EXPORT_CMD(
|
||||
SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
|
||||
cd, shellCD, change dir);
|
||||
|
||||
/**
|
||||
* @brief 列出文件(shell调用)
|
||||
*
|
||||
*/
|
||||
void shellLS(void)
|
||||
{
|
||||
size_t count;
|
||||
char *buffer;
|
||||
|
||||
Shell *shell = shellGetCurrent();
|
||||
ShellFs *shellFs = shellCompanionGet(shell, SHELL_COMPANION_ID_FS);
|
||||
SHELL_ASSERT(shellFs, return);
|
||||
|
||||
buffer = SHELL_MALLOC(SHELL_FS_LIST_FILE_BUFFER_MAX);
|
||||
SHELL_ASSERT(buffer, return);
|
||||
count = shellFs->listdir(shellGetPath(shell), buffer, SHELL_FS_LIST_FILE_BUFFER_MAX);
|
||||
|
||||
shellWriteString(shell, buffer);
|
||||
|
||||
SHELL_FREE(buffer);
|
||||
}
|
||||
SHELL_EXPORT_CMD(
|
||||
SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
|
||||
ls, shellLS, list all files);
|
||||
|
||||
/**
|
||||
* @brief 初始化shell文件系统支持
|
||||
*
|
||||
* @param shellFs shell文件系统对象
|
||||
* @param pathBuffer shell路径缓冲
|
||||
* @param pathLen 路径缓冲区大小
|
||||
*/
|
||||
void shellFsInit(ShellFs *shellFs, char *pathBuffer, size_t pathLen)
|
||||
{
|
||||
shellFs->info.path = pathBuffer;
|
||||
shellFs->info.pathLen = pathLen;
|
||||
shellFs->getcwd(shellFs->info.path, pathLen);
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* @file shell_fs.h
|
||||
* @author Letter (nevermindzzt@gmail.com)
|
||||
* @brief shell file system support
|
||||
* @version 0.1
|
||||
* @date 2020-07-22
|
||||
*
|
||||
* @copyright (c) 2020 Letter
|
||||
*
|
||||
*/
|
||||
#ifndef __SHELL_FS_H__
|
||||
#define __SHELL_FS_H__
|
||||
|
||||
#include "stddef.h"
|
||||
#include "shell.h"
|
||||
|
||||
#define SHELL_FS_VERSION "1.0.0"
|
||||
|
||||
#define SHELL_COMPANION_ID_FS -1
|
||||
|
||||
#define SHELL_FS_LIST_FILE_BUFFER_MAX 4096
|
||||
|
||||
/**
|
||||
* @brief shell文件系统支持结构体
|
||||
*
|
||||
*/
|
||||
typedef struct shell_fs
|
||||
{
|
||||
size_t (*getcwd)(char *, size_t);
|
||||
size_t (*chdir)(char *);
|
||||
size_t (*listdir)(char *dir, char *buffer, size_t maxLen);
|
||||
|
||||
struct {
|
||||
char *path;
|
||||
size_t pathLen;
|
||||
} info;
|
||||
} ShellFs;
|
||||
|
||||
void shellFsInit(ShellFs *shellFs, char *pathBuffer, size_t pathLen);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,423 @@
|
||||
/*
|
||||
============================================================================
|
||||
Name : 2048.c
|
||||
Author : Maurits van der Schee
|
||||
Description : Console version of the game "2048" for GNU/Linux
|
||||
============================================================================
|
||||
*/
|
||||
|
||||
#define _XOPEN_SOURCE 500
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include "shell.h"
|
||||
|
||||
#define printf(...) shellPrint(shell2048, ##__VA_ARGS__)
|
||||
#define getchar() shellGetChar(shell2048)
|
||||
|
||||
#define SIZE 4
|
||||
uint32_t score=0;
|
||||
uint8_t scheme=0;
|
||||
|
||||
Shell *shell2048 = NULL;
|
||||
|
||||
char shellGetChar(Shell *shell) {
|
||||
char data;
|
||||
if (shell->read && shell->read(&data, 1) == 1) {
|
||||
return data;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
void sleep(int ms) {
|
||||
int time = SHELL_GET_TICK();
|
||||
while (SHELL_GET_TICK() - time < ms) ;
|
||||
}
|
||||
|
||||
void getColor(uint8_t value, char *color, size_t length) {
|
||||
uint8_t original[] = {8,255,1,255,2,255,3,255,4,255,5,255,6,255,7,255,9,0,10,0,11,0,12,0,13,0,14,0,255,0,255,0};
|
||||
uint8_t blackwhite[] = {232,255,234,255,236,255,238,255,240,255,242,255,244,255,246,0,248,0,249,0,250,0,251,0,252,0,253,0,254,0,255,0};
|
||||
uint8_t bluered[] = {235,255,63,255,57,255,93,255,129,255,165,255,201,255,200,255,199,255,198,255,197,255,196,255,196,255,196,255,196,255,196,255};
|
||||
uint8_t *schemes[] = {original,blackwhite,bluered};
|
||||
uint8_t *background = schemes[scheme]+0;
|
||||
uint8_t *foreground = schemes[scheme]+1;
|
||||
if (value > 0) while (value--) {
|
||||
if (background+2<schemes[scheme]+sizeof(original)) {
|
||||
background+=2;
|
||||
foreground+=2;
|
||||
}
|
||||
}
|
||||
snprintf(color,length,"\033[38;5;%d;48;5;%dm",*foreground,*background);
|
||||
}
|
||||
|
||||
void drawBoard(uint8_t board[SIZE][SIZE]) {
|
||||
uint8_t x,y;
|
||||
char color[40], reset[] = "\033[m";
|
||||
printf("\033[H");
|
||||
|
||||
printf("2048.c %17d pts\n\n",score);
|
||||
|
||||
for (y=0;y<SIZE;y++) {
|
||||
for (x=0;x<SIZE;x++) {
|
||||
getColor(board[x][y],color,40);
|
||||
printf("%s",color);
|
||||
printf(" ");
|
||||
printf("%s",reset);
|
||||
}
|
||||
printf("\n");
|
||||
for (x=0;x<SIZE;x++) {
|
||||
getColor(board[x][y],color,40);
|
||||
printf("%s",color);
|
||||
if (board[x][y]!=0) {
|
||||
char s[8];
|
||||
snprintf(s,8,"%u",(uint32_t)1<<board[x][y]);
|
||||
uint8_t t = 7-strlen(s);
|
||||
printf("%*s%s%*s",t-t/2,"",s,t/2,"");
|
||||
} else {
|
||||
printf(" · ");
|
||||
}
|
||||
printf("%s",reset);
|
||||
}
|
||||
printf("\n");
|
||||
for (x=0;x<SIZE;x++) {
|
||||
getColor(board[x][y],color,40);
|
||||
printf("%s",color);
|
||||
printf(" ");
|
||||
printf("%s",reset);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
printf("\n");
|
||||
printf(" ←,↑,→,↓ or q \n");
|
||||
printf("\033[A"); // one line up
|
||||
}
|
||||
|
||||
uint8_t findTarget(uint8_t array[SIZE],uint8_t x,uint8_t stop) {
|
||||
uint8_t t;
|
||||
// if the position is already on the first, don't evaluate
|
||||
if (x==0) {
|
||||
return x;
|
||||
}
|
||||
for(t=x-1;;t--) {
|
||||
if (array[t]!=0) {
|
||||
if (array[t]!=array[x]) {
|
||||
// merge is not possible, take next position
|
||||
return t+1;
|
||||
}
|
||||
return t;
|
||||
} else {
|
||||
// we should not slide further, return this one
|
||||
if (t==stop) {
|
||||
return t;
|
||||
}
|
||||
}
|
||||
}
|
||||
// we did not find a
|
||||
return x;
|
||||
}
|
||||
|
||||
bool slideArray(uint8_t array[SIZE]) {
|
||||
bool success = false;
|
||||
uint8_t x,t,stop=0;
|
||||
|
||||
for (x=0;x<SIZE;x++) {
|
||||
if (array[x]!=0) {
|
||||
t = findTarget(array,x,stop);
|
||||
// if target is not original position, then move or merge
|
||||
if (t!=x) {
|
||||
// if target is zero, this is a move
|
||||
if (array[t]==0) {
|
||||
array[t]=array[x];
|
||||
} else if (array[t]==array[x]) {
|
||||
// merge (increase power of two)
|
||||
array[t]++;
|
||||
// increase score
|
||||
score+=(uint32_t)1<<array[t];
|
||||
// set stop to avoid double merge
|
||||
stop = t+1;
|
||||
}
|
||||
array[x]=0;
|
||||
success = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
void rotateBoard(uint8_t board[SIZE][SIZE]) {
|
||||
uint8_t i,j,n=SIZE;
|
||||
uint8_t tmp;
|
||||
for (i=0; i<n/2; i++) {
|
||||
for (j=i; j<n-i-1; j++) {
|
||||
tmp = board[i][j];
|
||||
board[i][j] = board[j][n-i-1];
|
||||
board[j][n-i-1] = board[n-i-1][n-j-1];
|
||||
board[n-i-1][n-j-1] = board[n-j-1][i];
|
||||
board[n-j-1][i] = tmp;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool moveUp(uint8_t board[SIZE][SIZE]) {
|
||||
bool success = false;
|
||||
uint8_t x;
|
||||
for (x=0;x<SIZE;x++) {
|
||||
success |= slideArray(board[x]);
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
bool moveLeft(uint8_t board[SIZE][SIZE]) {
|
||||
bool success;
|
||||
rotateBoard(board);
|
||||
success = moveUp(board);
|
||||
rotateBoard(board);
|
||||
rotateBoard(board);
|
||||
rotateBoard(board);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool moveDown(uint8_t board[SIZE][SIZE]) {
|
||||
bool success;
|
||||
rotateBoard(board);
|
||||
rotateBoard(board);
|
||||
success = moveUp(board);
|
||||
rotateBoard(board);
|
||||
rotateBoard(board);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool moveRight(uint8_t board[SIZE][SIZE]) {
|
||||
bool success;
|
||||
rotateBoard(board);
|
||||
rotateBoard(board);
|
||||
rotateBoard(board);
|
||||
success = moveUp(board);
|
||||
rotateBoard(board);
|
||||
return success;
|
||||
}
|
||||
|
||||
bool findPairDown(uint8_t board[SIZE][SIZE]) {
|
||||
bool success = false;
|
||||
uint8_t x,y;
|
||||
for (x=0;x<SIZE;x++) {
|
||||
for (y=0;y<SIZE-1;y++) {
|
||||
if (board[x][y]==board[x][y+1]) return true;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
uint8_t countEmpty(uint8_t board[SIZE][SIZE]) {
|
||||
uint8_t x,y;
|
||||
uint8_t count=0;
|
||||
for (x=0;x<SIZE;x++) {
|
||||
for (y=0;y<SIZE;y++) {
|
||||
if (board[x][y]==0) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
|
||||
bool gameEnded(uint8_t board[SIZE][SIZE]) {
|
||||
bool ended = true;
|
||||
if (countEmpty(board)>0) return false;
|
||||
if (findPairDown(board)) return false;
|
||||
rotateBoard(board);
|
||||
if (findPairDown(board)) ended = false;
|
||||
rotateBoard(board);
|
||||
rotateBoard(board);
|
||||
rotateBoard(board);
|
||||
return ended;
|
||||
}
|
||||
|
||||
void addRandom(uint8_t board[SIZE][SIZE]) {
|
||||
static bool initialized = false;
|
||||
uint8_t x,y;
|
||||
uint8_t r,len=0;
|
||||
uint8_t n,list[SIZE*SIZE][2];
|
||||
|
||||
if (!initialized) {
|
||||
srand(SHELL_GET_TICK());
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
for (x=0;x<SIZE;x++) {
|
||||
for (y=0;y<SIZE;y++) {
|
||||
if (board[x][y]==0) {
|
||||
list[len][0]=x;
|
||||
list[len][1]=y;
|
||||
len++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (len>0) {
|
||||
r = rand()%len;
|
||||
x = list[r][0];
|
||||
y = list[r][1];
|
||||
n = (rand()%10)/9+1;
|
||||
board[x][y]=n;
|
||||
}
|
||||
}
|
||||
|
||||
void initBoard(uint8_t board[SIZE][SIZE]) {
|
||||
uint8_t x,y;
|
||||
for (x=0;x<SIZE;x++) {
|
||||
for (y=0;y<SIZE;y++) {
|
||||
board[x][y]=0;
|
||||
}
|
||||
}
|
||||
addRandom(board);
|
||||
addRandom(board);
|
||||
drawBoard(board);
|
||||
score = 0;
|
||||
}
|
||||
|
||||
// int test() {
|
||||
// uint8_t array[SIZE];
|
||||
// // these are exponents with base 2 (1=2 2=4 3=8)
|
||||
// uint8_t data[] = {
|
||||
// 0,0,0,1, 1,0,0,0,
|
||||
// 0,0,1,1, 2,0,0,0,
|
||||
// 0,1,0,1, 2,0,0,0,
|
||||
// 1,0,0,1, 2,0,0,0,
|
||||
// 1,0,1,0, 2,0,0,0,
|
||||
// 1,1,1,0, 2,1,0,0,
|
||||
// 1,0,1,1, 2,1,0,0,
|
||||
// 1,1,0,1, 2,1,0,0,
|
||||
// 1,1,1,1, 2,2,0,0,
|
||||
// 2,2,1,1, 3,2,0,0,
|
||||
// 1,1,2,2, 2,3,0,0,
|
||||
// 3,0,1,1, 3,2,0,0,
|
||||
// 2,0,1,1, 2,2,0,0
|
||||
// };
|
||||
// uint8_t *in,*out;
|
||||
// uint8_t t,tests;
|
||||
// uint8_t i;
|
||||
// bool success = true;
|
||||
|
||||
// tests = (sizeof(data)/sizeof(data[0]))/(2*SIZE);
|
||||
// for (t=0;t<tests;t++) {
|
||||
// in = data+t*2*SIZE;
|
||||
// out = in + SIZE;
|
||||
// for (i=0;i<SIZE;i++) {
|
||||
// array[i] = in[i];
|
||||
// }
|
||||
// slideArray(array);
|
||||
// for (i=0;i<SIZE;i++) {
|
||||
// if (array[i] != out[i]) {
|
||||
// success = false;
|
||||
// }
|
||||
// }
|
||||
// if (success==false) {
|
||||
// for (i=0;i<SIZE;i++) {
|
||||
// printf("%d ",in[i]);
|
||||
// }
|
||||
// printf("=> ");
|
||||
// for (i=0;i<SIZE;i++) {
|
||||
// printf("%d ",array[i]);
|
||||
// }
|
||||
// printf("expected ");
|
||||
// for (i=0;i<SIZE;i++) {
|
||||
// printf("%d ",in[i]);
|
||||
// }
|
||||
// printf("=> ");
|
||||
// for (i=0;i<SIZE;i++) {
|
||||
// printf("%d ",out[i]);
|
||||
// }
|
||||
// printf("\n");
|
||||
// break;
|
||||
// }
|
||||
// }
|
||||
// if (success) {
|
||||
// printf("All %u tests executed successfully\n",tests);
|
||||
// }
|
||||
// return !success;
|
||||
// }
|
||||
|
||||
|
||||
int main_2048(int argc, char *argv[]) {
|
||||
uint8_t board[SIZE][SIZE];
|
||||
char c;
|
||||
bool success;
|
||||
|
||||
shell2048 = shellGetCurrent();
|
||||
if (!shell2048) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
// if (argc == 2 && strcmp(argv[1],"test")==0) {
|
||||
// return test();
|
||||
// }
|
||||
if (argc == 2 && strcmp(argv[1],"blackwhite")==0) {
|
||||
scheme = 1;
|
||||
}
|
||||
if (argc == 2 && strcmp(argv[1],"bluered")==0) {
|
||||
scheme = 2;
|
||||
}
|
||||
|
||||
printf("\033[?25l\033[2J");
|
||||
|
||||
initBoard(board);
|
||||
while (true) {
|
||||
c=getchar();
|
||||
if (c == -1){
|
||||
printf("\nError! Cannot read keyboard input!");
|
||||
break;
|
||||
}
|
||||
switch(c) {
|
||||
case 97: // 'a' key
|
||||
case 104: // 'h' key
|
||||
case 68: // left arrow
|
||||
success = moveLeft(board); break;
|
||||
case 100: // 'd' key
|
||||
case 108: // 'l' key
|
||||
case 67: // right arrow
|
||||
success = moveRight(board); break;
|
||||
case 119: // 'w' key
|
||||
case 107: // 'k' key
|
||||
case 65: // up arrow
|
||||
success = moveUp(board); break;
|
||||
case 115: // 's' key
|
||||
case 106: // 'j' key
|
||||
case 66: // down arrow
|
||||
success = moveDown(board); break;
|
||||
default: success = false;
|
||||
}
|
||||
if (success) {
|
||||
drawBoard(board);
|
||||
sleep(150);
|
||||
addRandom(board);
|
||||
drawBoard(board);
|
||||
if (gameEnded(board)) {
|
||||
printf(" GAME OVER \n");
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (c=='q') {
|
||||
printf(" QUIT? (y/n) \n");
|
||||
c=getchar();
|
||||
if (c=='y') {
|
||||
break;
|
||||
}
|
||||
drawBoard(board);
|
||||
}
|
||||
if (c=='r') {
|
||||
printf(" RESTART? (y/n) \n");
|
||||
c=getchar();
|
||||
if (c=='y') {
|
||||
initBoard(board);
|
||||
}
|
||||
drawBoard(board);
|
||||
}
|
||||
}
|
||||
|
||||
printf("\033[?25h\033[m");
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* @file game.c
|
||||
* @author Letter
|
||||
* @brief game
|
||||
* @version 0.1
|
||||
* @date 2021-07-18
|
||||
*
|
||||
* @copyright (c) 2021 Letter
|
||||
*
|
||||
*/
|
||||
#include "shell_cmd_group.h"
|
||||
|
||||
extern int main_2048(int argc, char *argv[]);
|
||||
extern int main_pushbox(int argc, char* argv[]);
|
||||
|
||||
|
||||
ShellCommand gameGroup[] =
|
||||
{
|
||||
SHELL_CMD_GROUP_ITEM(SHELL_TYPE_CMD_MAIN, 2048, main_2048,
|
||||
game 2048\n2048 [param]\nParam: blackwhite bluered or null),
|
||||
SHELL_CMD_GROUP_ITEM(SHELL_TYPE_CMD_MAIN,
|
||||
pushbox, main_pushbox, game pushbox),
|
||||
SHELL_CMD_GROUP_END()
|
||||
};
|
||||
SHELL_EXPORT_CMD_GROUP(
|
||||
SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN,
|
||||
game, gameGroup, games);
|
||||
@@ -0,0 +1,183 @@
|
||||
|
||||
#include "shell.h"
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
|
||||
#define printf(...) shellPrint(shellPushbox, ##__VA_ARGS__)
|
||||
#define getchar() shellGetChar(shellPushbox)
|
||||
|
||||
Shell *shellPushbox = NULL;
|
||||
|
||||
static char shellGetChar(Shell *shell) {
|
||||
char data;
|
||||
if (shell->read && shell->read(&data, 1) == 1) {
|
||||
return data;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
//地图7行8列 行[0-6] 列[0-7]
|
||||
//0 路
|
||||
//1 墙
|
||||
//2 箱子
|
||||
//3 终点
|
||||
//4 小老鼠
|
||||
//7 小老鼠站在终止上
|
||||
//5 箱子到达终点上
|
||||
|
||||
int g_boards[7][8] = {
|
||||
{ 0, 1, 1, 1, 1, 1, 1, 0 },
|
||||
{ 0, 1, 0, 0, 0, 0, 1, 1 },
|
||||
{ 1, 3, 0, 1, 1, 2, 0, 1 },
|
||||
{ 1, 0, 3, 3, 2, 0, 0, 1 },
|
||||
{ 1, 0, 0, 1, 2, 0, 0, 1 },
|
||||
{ 1, 0, 0, 4, 0, 1, 1, 1 },
|
||||
{ 1, 1, 1, 1, 1, 0, 0, 0 }
|
||||
},
|
||||
boards[7][8] = {};
|
||||
|
||||
//记录小老鼠在移动中的位置
|
||||
int row = 0;
|
||||
int col = 0;
|
||||
int cnt = 0; //箱子个数,用来判断游戏是否结束。
|
||||
|
||||
//初始化地图
|
||||
void pushbox_init()
|
||||
{
|
||||
for (int i = 0; i < 7 * 8; i++) { //这里是为了当你按下enter键时,能够重置游戏,重置游戏时需要重新初始化地图
|
||||
boards[i / 8][i % 8] = g_boards[i / 8][i % 8];
|
||||
if (4 == boards[i / 8][i % 8]) //这里还需要记录老鼠的位置
|
||||
{
|
||||
row = i / 8;
|
||||
col = i % 8;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//打印地图
|
||||
void pushbox_print_map()
|
||||
{
|
||||
printf( "\r\n LetterShell PushBox!\r\n");
|
||||
for (int i = 0; i < 7; i++) {
|
||||
printf( " ");
|
||||
for (int j = 0; j < 8; j++) {
|
||||
switch (boards[i][j]) {
|
||||
case 0:
|
||||
printf( " ");
|
||||
break; //空格代表路径
|
||||
case 1:
|
||||
printf( "■");
|
||||
break; //打印墙
|
||||
case 2:
|
||||
case 5:
|
||||
printf( "●");
|
||||
break; //打印箱子
|
||||
case 3:
|
||||
printf( "★");
|
||||
break; //打印终点
|
||||
case 4:
|
||||
case 7:
|
||||
printf( "♀");
|
||||
break; //打印小老鼠
|
||||
}
|
||||
}
|
||||
printf( "\r\n");
|
||||
}
|
||||
printf("w,a,s,d or q\n");
|
||||
}
|
||||
|
||||
//推箱子
|
||||
int pushbox_print_move(int nrow, int ncol, int nnrow, int nncol)
|
||||
{
|
||||
printf( "\033[H");
|
||||
if (0 == boards[nrow][ncol] || 3 == boards[nrow][ncol]) //如果小老鼠前面是路或者终点,说明可以移动
|
||||
{
|
||||
boards[nrow][ncol] += 4; //小老鼠进入这个位置了
|
||||
boards[row][col] -= 4; //小老鼠离开这个位置了
|
||||
//移动过后小老鼠的位置也改变了
|
||||
row = nrow;
|
||||
col = ncol;
|
||||
} else if (2 == boards[nrow][ncol] || 5 == boards[nrow][ncol]) //如果小老鼠前面是箱子
|
||||
{
|
||||
if (0 == boards[nnrow][nncol] || 3 == boards[nnrow][nncol]) //如果箱子前面是路或者终点则可以移动
|
||||
{
|
||||
boards[nnrow][nncol] += 2;
|
||||
boards[nrow][ncol] -= 2 - 4;
|
||||
//这里其实是boards[nrow][ncol]=boards[nrow][ncol]-2+4
|
||||
//减去2是因为箱子移走了,加上4是因为小老鼠进入了
|
||||
boards[row][col] -= 4;
|
||||
row = nrow;
|
||||
col = ncol;
|
||||
}
|
||||
}
|
||||
for (int i = 0; i < 7; i++) //统计游戏是否结束,当箱子都在终点上时就结束了
|
||||
{
|
||||
for (int j = 0; j < 8; j++) {
|
||||
if (5 == boards[i][j]) {
|
||||
cnt++;
|
||||
}
|
||||
if (3 == cnt) {
|
||||
printf( "通关!\r\n");
|
||||
return 1; //通关退出游戏
|
||||
}
|
||||
}
|
||||
}
|
||||
cnt = 0; //如果游戏没有结束,下次还是需要从0统计
|
||||
pushbox_print_map();
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
int main_pushbox(int argc, char* argv[])
|
||||
{
|
||||
char c;
|
||||
int res = 0;
|
||||
|
||||
shellPushbox = shellGetCurrent();
|
||||
if (!shellPushbox) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
printf( "\033[?25l\033[2J");
|
||||
printf( "\033[H");
|
||||
pushbox_init();//游戏初始化
|
||||
pushbox_print_map();
|
||||
while (1) {
|
||||
c = getchar();;
|
||||
if (c < 0) {
|
||||
printf("\nError! Cannot read keyboard input!");
|
||||
break;
|
||||
}
|
||||
switch (c) //每次都需要判断小老鼠前面和前面的前面的坐标的状态,这样可以在move()
|
||||
{ //函数中统一各个方向的写法
|
||||
case 'w':
|
||||
res = pushbox_print_move(row - 1, col, row - 2, col);
|
||||
break;
|
||||
case 's':
|
||||
res = pushbox_print_move(row + 1, col, row + 2, col);
|
||||
break;
|
||||
case 'a':
|
||||
res = pushbox_print_move(row, col - 1, row, col - 2);
|
||||
break;
|
||||
case 'd':
|
||||
res = pushbox_print_move(row, col + 1, row, col + 2);
|
||||
break;
|
||||
case 'r':
|
||||
pushbox_init();
|
||||
break; //按enter则从新开始游戏
|
||||
case 'q':
|
||||
res = 1; //如果按q则退出游戏
|
||||
}
|
||||
if(res){
|
||||
break;
|
||||
}
|
||||
}
|
||||
printf( "\033[?25l\033[2J");
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
# game
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## 简介
|
||||
|
||||
这是一个仅供娱乐的组件,移植了几个命令行的游戏
|
||||
|
||||
| 游戏 | 来源 |
|
||||
| ---- | ------------------------------------------------ |
|
||||
| 2048 | [mevdschee/2048](https://github.com/mevdschee/2048.c) |
|
||||
@@ -0,0 +1,309 @@
|
||||
/**
|
||||
* @file log.c
|
||||
* @author Letter (nevermindzzt@gmail.com)
|
||||
* @brief log
|
||||
* @version 1.0.0
|
||||
* @date 2020-07-30
|
||||
*
|
||||
* @copyright (c) 2020 Letter
|
||||
*
|
||||
*/
|
||||
#include "log.h"
|
||||
#include "stdio.h"
|
||||
#include "stdarg.h"
|
||||
#include "shell.h"
|
||||
|
||||
#if LOG_USING_COLOR == 1
|
||||
#define memPrintHead CSI(31) \
|
||||
" Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F" \
|
||||
CSI(39) \
|
||||
"\r\n"
|
||||
#define memPrintAddr CSI(31)"0x%08x: "CSI(39)
|
||||
#else
|
||||
#define memPrintHead " Offset: 00 01 02 03 04 05 06 07 08 09 0A 0B 0C 0D 0E 0F\r\n"
|
||||
#define memPrintAddr "0x%08x: "
|
||||
#endif
|
||||
|
||||
Log *logList[LOG_MAX_NUMBER] = {0};
|
||||
static char logBuffer[LOG_BUFFER_SIZE];
|
||||
|
||||
#if LOG_USING_LOCK == 1
|
||||
/**
|
||||
* @brief 上锁log对象
|
||||
* @param log log对象
|
||||
*/
|
||||
static void logLock(Log *log)
|
||||
{
|
||||
if (log == LOG_ALL_OBJ)
|
||||
{
|
||||
for (short i = 0; i < LOG_MAX_NUMBER; i++)
|
||||
{
|
||||
if (logList[i] && logList[i]->active)
|
||||
{
|
||||
if (logList[i]->lock)
|
||||
{
|
||||
LOG_LOCK(logList[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (log->lock)
|
||||
{
|
||||
LOG_LOCK(log);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 解锁log对象
|
||||
* @param log log对象
|
||||
*/
|
||||
static void logUnlock(Log *log)
|
||||
{
|
||||
if (log == LOG_ALL_OBJ)
|
||||
{
|
||||
for (short i = 0; i < LOG_MAX_NUMBER; i++)
|
||||
{
|
||||
if (logList[i] && logList[i]->active)
|
||||
{
|
||||
if (logList[i]->unlock)
|
||||
{
|
||||
LOG_UNLOCK(logList[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (log->unlock)
|
||||
{
|
||||
LOG_UNLOCK(log);
|
||||
}
|
||||
}
|
||||
#endif /* LOG_USING_LOCK == 1 */
|
||||
|
||||
/**
|
||||
* @brief 注册log对象
|
||||
*
|
||||
* @param log log对象
|
||||
*/
|
||||
void logRegister(Log *log, Shell *shell)
|
||||
{
|
||||
if (shell)
|
||||
{
|
||||
log->shell = shell;
|
||||
#if SHELL_USING_COMPANION == 1
|
||||
shellCompanionAdd(shell, SHELL_COMPANION_ID_LOG, log);
|
||||
#endif
|
||||
}
|
||||
for (short i = 0; i < LOG_MAX_NUMBER; i++)
|
||||
{
|
||||
if (logList[i] == 0)
|
||||
{
|
||||
logList[i] = log;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 注销log对象
|
||||
*
|
||||
* @param log log对象
|
||||
*/
|
||||
void logUnRegister(Log *log)
|
||||
{
|
||||
for (short i = 0; i < LOG_MAX_NUMBER; i++)
|
||||
{
|
||||
if (logList[i] == log)
|
||||
{
|
||||
logList[i] = 0;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 设置log日志级别
|
||||
*
|
||||
* @param log log对象
|
||||
* @param level 日志级别
|
||||
*/
|
||||
void logSetLevel(Log *log, LogLevel level)
|
||||
{
|
||||
logAssert(log, return);
|
||||
log->level = level;
|
||||
}
|
||||
#if SHELL_USING_COMPANION == 1
|
||||
SHELL_EXPORT_CMD_AGENCY(
|
||||
SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
|
||||
logSetLevel, logSetLevel, set log level\r\n logSetLevel [level],
|
||||
(void *)shellCompanionGet(shellGetCurrent(), SHELL_COMPANION_ID_LOG), p1);
|
||||
#else
|
||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC),
|
||||
logSetLevel, logSetLevel, set log level\r\n logSetLevel [log] [level]);
|
||||
#endif /** SHELL_USING_COMPANION == 1 */
|
||||
|
||||
|
||||
/**
|
||||
* @brief log写buffer
|
||||
*
|
||||
* @param log log对象
|
||||
* @param level 日志级别
|
||||
* @param buffer buffer
|
||||
* @param len buffer长度
|
||||
*/
|
||||
static void logWriteBuffer(Log *log, LogLevel level, char *buffer, short len)
|
||||
{
|
||||
#if LOG_USING_LOCK == 1
|
||||
logLock(log);
|
||||
#endif /* LOG_USING_LOCK == 1 */
|
||||
if (log == LOG_ALL_OBJ)
|
||||
{
|
||||
for (short i = 0; i < LOG_MAX_NUMBER; i++)
|
||||
{
|
||||
if (logList[i]
|
||||
&& logList[i]->active
|
||||
&& logList[i]->level >= level)
|
||||
{
|
||||
logList[i]->write(logBuffer, len);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (log && log->active && log->level >= level)
|
||||
{
|
||||
log->write(logBuffer, len);
|
||||
}
|
||||
#if LOG_USING_LOCK == 1
|
||||
logUnlock(log);
|
||||
#endif /* LOG_USING_LOCK == 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief log格式化写入数据
|
||||
*
|
||||
* @param log log对象
|
||||
* @param level log级别
|
||||
* @param fmt 格式
|
||||
* @param ... 参数
|
||||
*/
|
||||
void logWrite(Log *log, LogLevel level, const char *fmt, ...)
|
||||
{
|
||||
va_list vargs;
|
||||
short len;
|
||||
|
||||
#if LOG_USING_LOCK == 1
|
||||
logLock(log);
|
||||
#endif /* LOG_USING_LOCK == 1 */
|
||||
va_start(vargs, fmt);
|
||||
len = vsnprintf(logBuffer, LOG_BUFFER_SIZE - 1, fmt, vargs);
|
||||
va_end(vargs);
|
||||
|
||||
logWriteBuffer(log, level, logBuffer, len);
|
||||
#if LOG_USING_LOCK == 1
|
||||
logUnlock(log);
|
||||
#endif /* LOG_USING_LOCK == 1 */
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 16进制输出
|
||||
*
|
||||
* @param log log对象
|
||||
* @param level 日志级别
|
||||
* @param base 内存基址
|
||||
* @param length 长度
|
||||
*/
|
||||
void logHexDump(Log *log, LogLevel level, void *base, unsigned int length)
|
||||
{
|
||||
unsigned char *address;
|
||||
unsigned int len;
|
||||
unsigned int printLen = 0;
|
||||
|
||||
if (length == 0 || (log != LOG_ALL_OBJ && log->level < level))
|
||||
{
|
||||
return;
|
||||
}
|
||||
#if LOG_USING_LOCK == 1
|
||||
logLock(log);
|
||||
#endif /* LOG_USING_LOCK == 1 */
|
||||
len = snprintf(logBuffer, LOG_BUFFER_SIZE - 1, "memory of 0x%08x, size: %d:\r\n%s",
|
||||
(unsigned int)base, length, memPrintHead);
|
||||
logWriteBuffer(log, level, logBuffer, len);
|
||||
|
||||
len = length;
|
||||
|
||||
address = (unsigned char *)((unsigned int)base & (~0x0000000F));
|
||||
length += (unsigned int)base - (unsigned int)address;
|
||||
length = (length + 15) & (~0x0000000F);
|
||||
|
||||
while (length)
|
||||
{
|
||||
printLen += sprintf(logBuffer + printLen, memPrintAddr, (unsigned int)address);
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if ((unsigned int)(address + i) < (unsigned int)base
|
||||
|| (unsigned int)(address + i) >= (unsigned int)base + len)
|
||||
{
|
||||
logBuffer[printLen ++] = ' ';
|
||||
logBuffer[printLen ++] = ' ';
|
||||
logBuffer[printLen ++] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
printLen += sprintf(logBuffer + printLen, "%02x ", *(address + i));
|
||||
}
|
||||
}
|
||||
logBuffer[printLen ++] = '|';
|
||||
logBuffer[printLen ++] = ' ';
|
||||
for (int i = 0; i < 16; i++)
|
||||
{
|
||||
if ((unsigned int)(address + i) < (unsigned int)base
|
||||
|| (unsigned int)(address + i) >= (unsigned int)base + len)
|
||||
{
|
||||
logBuffer[printLen ++] = ' ';
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*(address + i) >= 32 && *(address + i) <= 126)
|
||||
{
|
||||
printLen += sprintf(logBuffer + printLen, "%c", *(address + i));
|
||||
}
|
||||
else
|
||||
{
|
||||
logBuffer[printLen ++] = '.';
|
||||
}
|
||||
}
|
||||
}
|
||||
logBuffer[printLen ++] = ' ';
|
||||
logBuffer[printLen ++] = '|';
|
||||
logBuffer[printLen ++] = '\r';
|
||||
logBuffer[printLen ++] = '\n';
|
||||
logWriteBuffer(log, level, logBuffer, printLen);
|
||||
address += 16;
|
||||
length -= 16;
|
||||
printLen = 0;
|
||||
}
|
||||
#if LOG_USING_LOCK == 1
|
||||
logUnlock(log);
|
||||
#endif /* LOG_USING_LOCK == 1 */
|
||||
}
|
||||
#if SHELL_USING_COMPANION == 1
|
||||
SHELL_EXPORT_CMD_AGENCY(
|
||||
SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
|
||||
hexdump, logHexDump, hex dump\r\n hexdump [base] [len],
|
||||
(void *)shellCompanionGet(shellGetCurrent(), SHELL_COMPANION_ID_LOG), LOG_NONE, (void *)p1, (unsigned int)p2);
|
||||
#else
|
||||
SHELL_EXPORT_CMD(
|
||||
SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_FUNC)|SHELL_CMD_DISABLE_RETURN,
|
||||
hexdump, logHexDump, hex dump\r\n hexdump [log] [level] [base] [len]);
|
||||
#endif /** SHELL_USING_COMPANION == 1 */
|
||||
|
||||
#if SHELL_USING_COMPANION == 1
|
||||
void logSwitchLevel(Shell *shell)
|
||||
{
|
||||
Log *log = shellCompanionGet(shell, SHELL_COMPANION_ID_LOG);
|
||||
SHELL_ASSERT(log, return);
|
||||
log->level = (LogLevel)(log->level >= LOG_ALL ? LOG_NONE : (log->level + 1));
|
||||
logPrintln("set log level: %d", log->level);
|
||||
}
|
||||
SHELL_EXPORT_KEY(SHELL_CMD_PERMISSION(0), 0x04000000, logSwitchLevel, switch log level);
|
||||
#endif /** SHELL_USING_COMPANION == 1 */
|
||||
@@ -0,0 +1,224 @@
|
||||
/**
|
||||
* @file log.h
|
||||
* @author Letter (nevermindzzt@gmail.com)
|
||||
* @brief log
|
||||
* @version 1.0.0
|
||||
* @date 2020-07-30
|
||||
*
|
||||
* @copyright (c) 2020 Letter
|
||||
*
|
||||
*/
|
||||
#ifndef __LOG_H__
|
||||
#define __LOG_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /**< defined __cplusplus */
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
#define LOG_VERSION "1.0.1"
|
||||
|
||||
#define SHELL_COMPANION_ID_LOG -2
|
||||
|
||||
#define LOG_USING_LOCK 0
|
||||
#define LOG_BUFFER_SIZE 256 /**< log输出缓冲大小 */
|
||||
#define LOG_USING_COLOR 1 /**< 是否使用颜色 */
|
||||
#define LOG_MAX_NUMBER 5 /**< 允许注册的最大log对象数量 */
|
||||
#define LOG_AUTO_TAG 1 /**< 是否自动添加TAG */
|
||||
#define LOG_END "\r\n" /**< log信息结尾 */
|
||||
#define LOG_TIME_STAMP 0 /**< 设置获取系统时间戳 */
|
||||
|
||||
#ifndef LOG_TAG
|
||||
#define LOG_TAG __FUNCTION__ /**< 自定添加的TAG */
|
||||
#endif
|
||||
|
||||
#ifndef LOG_ENABLE
|
||||
#define LOG_ENABLE 1 /**< 使能log */
|
||||
#endif
|
||||
|
||||
#if LOG_USING_LOCK == 1
|
||||
#define LOG_LOCK(log) log->lock(log)
|
||||
#define LOG_UNLOCK(log) log->unlock(log)
|
||||
#else
|
||||
#define LOG_LOCK(log)
|
||||
#define LOG_UNLOCK(log)
|
||||
#endif /* LOG_USING_LOCK == 1 */
|
||||
|
||||
#define LOG_ALL_OBJ ((Log *)-1) /**< 所有已注册的log对象 */
|
||||
|
||||
/**
|
||||
* 终端字体颜色代码
|
||||
*/
|
||||
#define CSI_BLACK 30 /**< 黑色 */
|
||||
#define CSI_RED 31 /**< 红色 */
|
||||
#define CSI_GREEN 32 /**< 绿色 */
|
||||
#define CSI_YELLOW 33 /**< 黄色 */
|
||||
#define CSI_BLUE 34 /**< 蓝色 */
|
||||
#define CSI_FUCHSIN 35 /**< 品红 */
|
||||
#define CSI_CYAN 36 /**< 青色 */
|
||||
#define CSI_WHITE 37 /**< 白色 */
|
||||
#define CSI_BLACK_L 90 /**< 亮黑 */
|
||||
#define CSI_RED_L 91 /**< 亮红 */
|
||||
#define CSI_GREEN_L 92 /**< 亮绿 */
|
||||
#define CSI_YELLOW_L 93 /**< 亮黄 */
|
||||
#define CSI_BLUE_L 94 /**< 亮蓝 */
|
||||
#define CSI_FUCHSIN_L 95 /**< 亮品红 */
|
||||
#define CSI_CYAN_L 96 /**< 亮青 */
|
||||
#define CSI_WHITE_L 97 /**< 亮白 */
|
||||
#define CSI_DEFAULT 39 /**< 默认 */
|
||||
|
||||
#define CSI(code) "\033[" #code "m" /**< ANSI CSI指令 */
|
||||
|
||||
/**
|
||||
* log级别字符(包含颜色)
|
||||
*/
|
||||
#if LOG_USING_COLOR == 1
|
||||
#define ERROR_TEXT CSI(31) "E(%d) %s:" CSI(39) /**< 错误标签 */
|
||||
#define WARNING_TEXT CSI(33) "W(%d) %s:" CSI(39) /**< 警告标签 */
|
||||
#define INFO_TEXT CSI(32) "I(%d) %s:" CSI(39) /**< 信息标签 */
|
||||
#define DEBUG_TEXT CSI(34) "D(%d) %s:" CSI(39) /**< 调试标签 */
|
||||
#define VERBOSE_TEXT CSI(36) "V(%d) %s:" CSI(39) /**< 冗余信息标签 */
|
||||
#else
|
||||
#define ERROR_TEXT "E(%d) %s:"
|
||||
#define WARNING_TEXT "W(%d) %s:"
|
||||
#define INFO_TEXT "I(%d) %s:"
|
||||
#define DEBUG_TEXT "D(%d) %s:"
|
||||
#define VERBOSE_TEXT "V(%d) %s:"
|
||||
#endif
|
||||
|
||||
|
||||
/**
|
||||
* @brief 日志级别定义
|
||||
*
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
LOG_NONE = 0, /**< 无级别 */
|
||||
LOG_ERROR = 1, /**< 错误 */
|
||||
LOG_WRANING = 2, /**< 警告 */
|
||||
LOG_INFO = 3, /**< 消息 */
|
||||
LOG_DEBUG = 4, /**< 调试 */
|
||||
LOG_VERBOSE = 5, /**< 冗余 */
|
||||
LOG_ALL = 6, /**< 所有日志 */
|
||||
} LogLevel;
|
||||
|
||||
|
||||
/**
|
||||
* @brief log对象定义
|
||||
*
|
||||
*/
|
||||
typedef struct log_def
|
||||
{
|
||||
void (*write)(char *, short); /**< 写buffer */
|
||||
char active; /**< 是否激活 */
|
||||
LogLevel level; /**< 日志级别 */
|
||||
#if LOG_USING_LOCK == 1
|
||||
int (*lock)(struct log_def *); /**< log 加锁 */
|
||||
int (*unlock)(struct log_def *); /**< log 解锁 */
|
||||
#endif /** LOG_USING_LOCK == 1 */
|
||||
Shell *shell; /**< 关联shell对象 */
|
||||
} Log;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief log打印(自动换行)
|
||||
*
|
||||
* @param fmt 格式
|
||||
* @param ... 参数
|
||||
*/
|
||||
#define logPrintln(format, ...) \
|
||||
logWrite(LOG_ALL_OBJ, LOG_NONE, format "\r\n", ##__VA_ARGS__)
|
||||
|
||||
|
||||
/**
|
||||
* @brief 日志格式化输出
|
||||
*
|
||||
* @param text 消息文本
|
||||
* @param level 日志级别
|
||||
* @param fmt 格式
|
||||
* @param ... 参数
|
||||
*/
|
||||
#define logFormat(text, level, fmt, ...) \
|
||||
if (LOG_ENABLE) {\
|
||||
logWrite(LOG_ALL_OBJ, level, text " " fmt "" LOG_END, \
|
||||
LOG_TIME_STAMP, LOG_TAG, ##__VA_ARGS__); }
|
||||
|
||||
/**
|
||||
* @brief 错误log输出
|
||||
*
|
||||
* @param fmt 格式
|
||||
* @param ... 参数
|
||||
*/
|
||||
#define logError(fmt, ...) \
|
||||
logFormat(ERROR_TEXT, LOG_ERROR, fmt, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief 警告log输出
|
||||
*
|
||||
* @param fmt 格式
|
||||
* @param ... 参数
|
||||
*/
|
||||
#define logWarning(fmt, ...) \
|
||||
logFormat(WARNING_TEXT, LOG_WRANING, fmt, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief 信息log输出
|
||||
*
|
||||
* @param fmt 格式
|
||||
* @param ... 参数
|
||||
*/
|
||||
#define logInfo(fmt, ...) \
|
||||
logFormat(INFO_TEXT, LOG_INFO, fmt, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief 调试log输出
|
||||
*
|
||||
* @param fmt 格式
|
||||
* @param ... 参数
|
||||
*/
|
||||
#define logDebug(fmt, ...) \
|
||||
logFormat(DEBUG_TEXT, LOG_DEBUG, fmt, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief 冗余log输出
|
||||
*
|
||||
* @param fmt 格式
|
||||
* @param ... 参数
|
||||
*/
|
||||
#define logVerbose(fmt, ...) \
|
||||
logFormat(VERBOSE_TEXT, LOG_VERBOSE, fmt, ##__VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief 断言
|
||||
*
|
||||
* @param expr 表达式
|
||||
* @param action 断言失败操作
|
||||
*/
|
||||
#define logAssert(expr, action) \
|
||||
if (!(expr)) { \
|
||||
logError("\"" #expr "\" assert failed at file: %s, line: %d", __FILE__, __LINE__); \
|
||||
action; \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 16进制输出到所有终端
|
||||
*
|
||||
* @param base 内存基址
|
||||
* @param length 长度
|
||||
*/
|
||||
#define logHexDumpAll(base, length) \
|
||||
logHexDump(LOG_ALL_OBJ, LOG_ALL, base, length)
|
||||
|
||||
void logRegister(Log *log, Shell *shell);
|
||||
void logUnRegister(Log *log);
|
||||
void logSetLevel(Log *log, LogLevel level);
|
||||
void logWrite(Log *log, LogLevel level, const char *fmt, ...);
|
||||
void logHexDump(Log *log, LogLevel level, void *base, unsigned int length);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /**< defined __cplusplus */
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,215 @@
|
||||
# log
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
嵌入式日志打印工具
|
||||
|
||||

|
||||
|
||||
- [log](#log)
|
||||
- [简介](#简介)
|
||||
- [使用](#使用)
|
||||
- [配置](#配置)
|
||||
- [API](#api)
|
||||
- [logPrintln](#logprintln)
|
||||
- [logError](#logerror)
|
||||
- [logWarning](#logwarning)
|
||||
- [logInfo](#loginfo)
|
||||
- [logDebug](#logdebug)
|
||||
- [logVerbose](#logverbose)
|
||||
- [logAssert](#logassert)
|
||||
- [logRegister](#logregister)
|
||||
- [logSetLevel](#logsetlevel)
|
||||
- [logHexDump](#loghexdump)
|
||||
- [结合letter shell尾行模式](#结合letter-shell尾行模式)
|
||||
- [其他用法](#其他用法)
|
||||
- [单独控制某个文件日志](#单独控制某个文件日志)
|
||||
|
||||
## 简介
|
||||
|
||||
log是一个用于嵌入式系统的日志打印工具,可以为日志定义不同的级别,然后设置日志工具的打印级别,可以进行日志打印的控制
|
||||
|
||||
此外,log通过letter shell的伴生对象功能,可以和letter shell结合,实现log和shell的绑定等功能
|
||||
|
||||
## 使用
|
||||
|
||||
1. 实现log写buffer函数
|
||||
|
||||
```C
|
||||
void uartLogWrite(char *buffer, short len)
|
||||
{
|
||||
serialTransmit(&debugSerial, (uint8_t *)buffer, len, 0x100);
|
||||
}
|
||||
```
|
||||
|
||||
2. 定义log对象
|
||||
|
||||
```C
|
||||
Log uartLog = {
|
||||
.write = uartLogWrite,
|
||||
.active = true,
|
||||
.level = LOG_DEBUG
|
||||
};
|
||||
```
|
||||
|
||||
3. 注册log对象
|
||||
|
||||
```C
|
||||
logRegister(&uartLog, NULL);
|
||||
```
|
||||
|
||||
## 配置
|
||||
|
||||
通过修改log.h文件中的宏,可以对log工具进行配置
|
||||
|
||||
| 宏 | 意义 |
|
||||
| --------------- | ------------------------- |
|
||||
| LOG_BUFFER_SIZE | log输出缓冲大小 |
|
||||
| LOG_USING_COLOR | 是否使用颜色 |
|
||||
| LOG_MAX_NUMBER | 允许注册的最大log对象数量 |
|
||||
| LOG_AUTO_TAG | 是否自动添加TAG |
|
||||
| LOG_END | log信息结尾 |
|
||||
| LOG_TAG | 自定添加的TAG |
|
||||
| LOG_TIME_STAMP | 设置获取系统时间戳 |
|
||||
|
||||
## API
|
||||
|
||||
以下是log工具部分API的说明
|
||||
|
||||
### logPrintln
|
||||
|
||||
宏声明,用于一般的打印输出
|
||||
|
||||
```C
|
||||
#define logPrintln(format, ...)
|
||||
```
|
||||
|
||||
- 参数
|
||||
- `format` 输出格式
|
||||
- `...` 可变参数
|
||||
|
||||
### logError
|
||||
|
||||
宏声明,错误日志级别输出
|
||||
|
||||
```C
|
||||
#define logError(fmt, ...)
|
||||
```
|
||||
|
||||
- 参数
|
||||
- `fmt` 输出格式
|
||||
- `...` 可变参数
|
||||
|
||||
### logWarning
|
||||
|
||||
宏声明,警告日志级别输出,函数原型及参数说明参考`logError`
|
||||
|
||||
### logInfo
|
||||
|
||||
宏声明,信息日志级别输出,函数原型及参数说明参考`logError`
|
||||
|
||||
### logDebug
|
||||
|
||||
宏声明,调试日志级别输出,函数原型及参数说明参考`logError`
|
||||
|
||||
### logVerbose
|
||||
|
||||
宏声明,冗余日志级别输出,函数原型及参数说明参考`logError`
|
||||
|
||||
### logAssert
|
||||
|
||||
宏声明,断言
|
||||
|
||||
```C
|
||||
#define logAssert(expr, action)
|
||||
```
|
||||
|
||||
- 参数
|
||||
- `expr` 表达式
|
||||
- `action` 断言失败执行操作
|
||||
|
||||
### logRegister
|
||||
|
||||
注册log对象
|
||||
|
||||
```C
|
||||
void logRegister(Log *log, Shell *shell)
|
||||
```
|
||||
|
||||
- 参数
|
||||
- `log` log对象
|
||||
- `shell` 关联的shell对象
|
||||
|
||||
### logSetLevel
|
||||
|
||||
设置日志级别
|
||||
|
||||
```C
|
||||
void logSetLevel(Log *log, LogLevel level)
|
||||
```
|
||||
|
||||
- 参数
|
||||
- `log` log对象
|
||||
- `level` 日志级别
|
||||
|
||||
### logHexDump
|
||||
|
||||
数据16进制打印
|
||||
|
||||
```C
|
||||
void logHexDump(Log *log, LogLevel level, void *base, unsigned int length)
|
||||
```
|
||||
|
||||
- 参数
|
||||
- `log` log对象
|
||||
- `level` 日志级别
|
||||
- `base` 数据基址
|
||||
- `length` 数据长度
|
||||
|
||||
## 结合letter shell尾行模式
|
||||
|
||||
log工具可以结合letter shell的尾行模式,实现log和shell共用一个终端,但不影响shell交互体验
|
||||
|
||||
1. 使用`shellWriteEndLine`事项log写buffer函数
|
||||
|
||||
```C
|
||||
void uartLogWrite(char *buffer, short len)
|
||||
{
|
||||
if (uartLog.shell)
|
||||
{
|
||||
shellWriteEndLine(uartLog.shell, buffer, len);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
2. 定义log对象
|
||||
|
||||
```C
|
||||
Log uartLog = {
|
||||
.write = uartLogWrite,
|
||||
.active = true,
|
||||
.level = LOG_DEBUG
|
||||
};
|
||||
```
|
||||
|
||||
3. 注册log对象
|
||||
|
||||
```C
|
||||
logRegister(&uartLog, &shell);
|
||||
```
|
||||
|
||||
## 其他用法
|
||||
|
||||
### 单独控制某个文件日志
|
||||
|
||||
log工具可以单独对某个文件的日志进行打印控制,使用时,在对应的.c文件中加入
|
||||
|
||||
```C
|
||||
#undef LOG_ENABLE
|
||||
#define LOG_ENABLE 1
|
||||
```
|
||||
|
||||
即可单独控制某个文件的日志开关
|
||||
@@ -0,0 +1,170 @@
|
||||
# shell_enhance
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
- [shell_enhance](#shell_enhance)
|
||||
- [简介](#简介)
|
||||
- [组件](#组件)
|
||||
- [shell_cmd_group](#shell_cmd_group)
|
||||
- [shell_passthrough](#shell_passthrough)
|
||||
- [shell_secure_user](#shell_secure_user)
|
||||
|
||||
## 简介
|
||||
|
||||
`shell_enhance`是`letter shell 3.0`上用于增强shell功能的组件,`shell_enhance`分离了一些不常用的shell功能,对于需要这些功能的用户,只需要将对应的文件加入到编译系统中即可
|
||||
|
||||
## 组件
|
||||
|
||||
`shell_enhance`目前包含的组件如下:
|
||||
|
||||
| 组件 | 描述 | 依赖文件 |
|
||||
| ----------------- | -------------- | --------------------------------------- |
|
||||
| shell_cmd_group | 提供命令组功能 | shell_cmd_group.c shell_cmd_group.h |
|
||||
| shell_passthrough | 提供透传功能 | shell_passthrough.c shell_passthrough.h |
|
||||
| shell_secure_user | 安全用户功能 | shell_secure_user.c shell_secure_user.h |
|
||||
|
||||
### shell_cmd_group
|
||||
|
||||
`shell_cmd_group`提供了一个命令组的功能,用户可以将多个相关的命令打包成一个命令组,然后通过形如`cmdgroup subcmd [param]`的方式进行命令调用
|
||||
|
||||
- 定义命令数组
|
||||
|
||||
命令数组用于将多个命令关联到一个数组,这个数组就是定义命令组需要的,你需要想正常命令一样,为每个子命令对应定义一个函数,然后将他们添加到一个数组中,可以使用宏`SHELL_CMD_GROUP_ITEM`进行定义
|
||||
|
||||
```c
|
||||
int test(int a, char *b)
|
||||
{
|
||||
printf("hello world, %d, %s\r\n", a, b);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int test2(int argc, char *argv[])
|
||||
{
|
||||
printf("%d parameters\r\n", argc);
|
||||
for (short i = 0; i < argc; i++)
|
||||
{
|
||||
printf("%s\t", argv[i]);
|
||||
}
|
||||
printf("\r\n");
|
||||
}
|
||||
|
||||
ShellCommand testGroup[] =
|
||||
{
|
||||
SHELL_CMD_GROUP_ITEM(SHELL_TYPE_CMD_FUNC, test, test, command group test1),
|
||||
SHELL_CMD_GROUP_ITEM(SHELL_TYPE_CMD_MAIN, test2, test2, command group test2),
|
||||
SHELL_CMD_GROUP_END()
|
||||
};
|
||||
```
|
||||
|
||||
其中`SHELL_CMD_GROUP_END()`需要写在每个命令数组的最后
|
||||
|
||||
- 定义命令组
|
||||
|
||||
使用宏`SHELL_EXPORT_CMD_GROUP`定义命令组
|
||||
|
||||
```c
|
||||
SHELL_EXPORT_CMD_GROUP(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), gt, testGroup, command group test);
|
||||
```
|
||||
|
||||
- 调用
|
||||
|
||||
在命令行,使用`cmdgroup subcmd [param]`的形式调用命令
|
||||
|
||||
```sh
|
||||
letter:/$ gt test 666 Letter
|
||||
hello world, 666, Letter
|
||||
Return: 0, 0x00000000
|
||||
|
||||
letter:/$ gt test2 hello world
|
||||
3 parameters
|
||||
test2 hello world
|
||||
Return: 0, 0x00000000
|
||||
```
|
||||
|
||||
- 命令帮助
|
||||
|
||||
通过使用`cmdgroup -h`的方式查看完整的命令帮助信息
|
||||
|
||||
```sh
|
||||
letter:/$ gt -h
|
||||
command group help of gt
|
||||
test: command group test1
|
||||
test2: command group test2
|
||||
Return: 0, 0x00000000
|
||||
```
|
||||
|
||||
### shell_passthrough
|
||||
|
||||
`shell_passthrough`提供了一个透传模式的功能,用户可以定义一个透传命令,执行透传命令后进入对应的透传模式,此后,命令行接收到的数据将以行为单位透传到定义的`handler`中,此扩展适用于一些需要进行终端数据转发的场景,常见的场景比如说通过命令行发送AT指令
|
||||
|
||||
- 定义hanadler
|
||||
|
||||
passthrough模式需要定义一个函数,用于处理命令行传过来的数据,函数原型为`typedef int (*ShellPassthrough)(char *data, unsigned short len)`
|
||||
|
||||
```C
|
||||
void shellPassthroughTest(char *data, unsigned short len)
|
||||
{
|
||||
printf("passthrough mode test, data: %s, len: %d\r\n", data, len);
|
||||
}
|
||||
```
|
||||
|
||||
- 定义passthrough
|
||||
|
||||
使用宏`SHELL_EXPORT_PASSTROUGH`定义`passthrough`
|
||||
|
||||
```C
|
||||
SHELL_EXPORT_PASSTROUGH(SHELL_CMD_PERMISSION(0), passTest, passthrough>>, shellPassthroughTest, passthrough mode test);
|
||||
```
|
||||
|
||||
- 调用
|
||||
|
||||
直接在命令行输入定义的`passthrough`名字可进入对应的透传模式,之后在输入的数据会按照行为单位通过`handler`调用
|
||||
|
||||
```sh
|
||||
letter:/mnt/f/Github/letter shell/demo/x86-gcc$ passTest
|
||||
passthrough>>hello
|
||||
passthrough mode test, data: hello, len: 5
|
||||
```
|
||||
|
||||
- 退出
|
||||
|
||||
使用组合键`Ctrl + D`退出`passthrough`,键值可以在`shell_passthrough.h`文件中的`SHELL_PASSTHROUGH_EXIT_KEY`宏修改
|
||||
|
||||
- 单次调用
|
||||
|
||||
某些情况下,使用`passthrough`模式时,我们可能只需要单次数据的透传,此时可以不进入`passthrough`命令行,直接调用命令带上透传的数据即可
|
||||
|
||||
```sh
|
||||
letter:/mnt/f/Github/letter shell/demo/x86-gcc$ passTest "hello world"
|
||||
passthrough mode test, data: hello world, len: 11
|
||||
```
|
||||
|
||||
### shell_secure_user
|
||||
|
||||
`shell_secure_user`组件是对shell用户的一个补充,在`letter shell`中,我们可以通过定义不同的用户和分配命令权限,约束使用者可以执行的命令,可以将高权限的用户定义密码,但是,shell用户的默认实现只支持固定的密码,在编译时就已经确定,安全性不高
|
||||
|
||||
使用`shell_secure_user`组件,我们可以定义一个函数,使用这个函数得到用户的密码,一般的,我们可以根据芯片的ID,mac地址,甚至可以向服务器做请求以获取密码,提高安全性
|
||||
|
||||
- 定义获取用户密码函数(handler)
|
||||
|
||||
示例函数直接返回用户名作为密码,实际使用时可以通过任何方式计算或者获取密码,注意,此处返回的密码字符串,请自行分配内存保存
|
||||
|
||||
```c
|
||||
char *shellSecureUserHandlerTest(const char *name)
|
||||
{
|
||||
return (char *)name;
|
||||
}
|
||||
```
|
||||
|
||||
- 定义用户
|
||||
|
||||
```c
|
||||
SHELL_EXPORT_SECURE_USER(SHELL_CMD_PERMISSION(0xFF), secure, shellSecureUserHandlerTest, secure user test);
|
||||
```
|
||||
|
||||
- 调用
|
||||
|
||||
使用`shell_secure_user`定义的用户和shell默认用户调用方法完全一致,只需要在shell命令行输入用户名和密码即可
|
||||
@@ -0,0 +1,82 @@
|
||||
/**
|
||||
* @file shell_cmd_group.c
|
||||
* @author Letter(nevermindzzt@gmail.com)
|
||||
* @brief shell command group support
|
||||
* @version 0.1
|
||||
* @date 2020-10-18
|
||||
*
|
||||
* @copyright (c) 2020 Letter
|
||||
*
|
||||
*/
|
||||
#include "shell_cmd_group.h"
|
||||
#include "string.h"
|
||||
#include "stdio.h"
|
||||
|
||||
unsigned int shellRunCommand(Shell *shell, ShellCommand *command);
|
||||
|
||||
static void shellCmdGroupHelp(Shell *shell, char *name, ShellCommand *group);
|
||||
|
||||
/**
|
||||
* @brief shell命令组运行
|
||||
*
|
||||
* @param group 命令数组
|
||||
* @param argc 参数数量
|
||||
* @param argv 参数
|
||||
*
|
||||
* @return int 执行命令返回值
|
||||
*/
|
||||
int shellCmdGroupRun(ShellCommand *group, int argc, char *argv[])
|
||||
{
|
||||
ShellCommand *item = group;
|
||||
Shell *shell = shellGetCurrent();
|
||||
|
||||
SHELL_ASSERT(shell, return -1);
|
||||
|
||||
if (argc == 1 || strcmp("-h", argv[1]) == 0)
|
||||
{
|
||||
shellCmdGroupHelp(shell, argv[0], group);
|
||||
return 0;
|
||||
}
|
||||
while (item->data.cmd.name)
|
||||
{
|
||||
if (strcmp(item->data.cmd.name, argv[1]) == 0)
|
||||
{
|
||||
for (short i = 0; i < argc - 1; i++)
|
||||
{
|
||||
argv[i] = argv[i + 1];
|
||||
}
|
||||
shell->parser.paramCount--;
|
||||
return shellRunCommand(shell, item);
|
||||
}
|
||||
item++;
|
||||
}
|
||||
shellWriteString(shell, "sub command not found\r\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief shell 命令组帮助
|
||||
*
|
||||
* @param shell shell对象
|
||||
* @param name 命令组名
|
||||
* @param group 命令数组
|
||||
*/
|
||||
static void shellCmdGroupHelp(Shell *shell, char *name, ShellCommand *group)
|
||||
{
|
||||
ShellCommand *item = group;
|
||||
|
||||
shellWriteString(shell, "command group help of ");
|
||||
shellWriteString(shell, name);
|
||||
shellWriteString(shell, "\r\n");
|
||||
|
||||
while (item->data.cmd.name)
|
||||
{
|
||||
shellWriteString(shell, item->data.cmd.name);
|
||||
shellWriteString(shell, ": ");
|
||||
if (item->data.cmd.desc) {
|
||||
shellWriteString(shell, item->data.cmd.desc);
|
||||
}
|
||||
shellWriteString(shell, "\r\n");
|
||||
item++;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @file shell_cmd_group.h
|
||||
* @author Letter(nevermindzzt@gmail.com)
|
||||
* @brief shell command group support
|
||||
* @version 0.1
|
||||
* @date 2020-10-18
|
||||
*
|
||||
* @copyright (c) 2020 Letter
|
||||
*
|
||||
*/
|
||||
#include "shell.h"
|
||||
|
||||
/**
|
||||
* @brief shell 命令组函数名
|
||||
*/
|
||||
#define SHELL_CMD_GROUP_FUNC_NAME(_group) agency##_group
|
||||
|
||||
/**
|
||||
* @brief shell命令组函数定义
|
||||
*
|
||||
* @param _group 命令数组
|
||||
*/
|
||||
#define SHELL_CMD_GROUP_FUNC(_group) \
|
||||
void SHELL_CMD_GROUP_FUNC_NAME(_group)(int p1, int p2) \
|
||||
{ shellCmdGroupRun(_group, p1, (char **)p2); }
|
||||
|
||||
|
||||
/**
|
||||
* @brief shell 命令组定义
|
||||
*
|
||||
* @param _attr 属性
|
||||
* @param _name 命令组名
|
||||
* @param _group 命令数组
|
||||
* @param _desc 命令组描述
|
||||
*/
|
||||
#define SHELL_EXPORT_CMD_GROUP(_attr, _name, _group, _desc) \
|
||||
SHELL_CMD_GROUP_FUNC(_group) \
|
||||
SHELL_EXPORT_CMD(_attr, _name, SHELL_CMD_GROUP_FUNC_NAME(_group), _desc)
|
||||
|
||||
/**
|
||||
* @brief shell 命令组item定义
|
||||
*
|
||||
* @param _type 命令类型(SHELL_TYPE_CMD_MAIN or SHELL_TYPE_CMD_FUNC)
|
||||
* @param _func 命令函数
|
||||
* @param _desc 命令描述
|
||||
*/
|
||||
#define SHELL_CMD_GROUP_ITEM(_type, _name, _func, _desc) \
|
||||
{ \
|
||||
.attr.value = SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(_type)|SHELL_CMD_DISABLE_RETURN, \
|
||||
.data.cmd.name = #_name, \
|
||||
.data.cmd.function = (int (*)())_func, \
|
||||
.data.cmd.desc = #_desc \
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief shell 命令组定义结尾
|
||||
*
|
||||
* @note 需要添加在每个命令数组的最后一条
|
||||
*/
|
||||
#define SHELL_CMD_GROUP_END() {0}
|
||||
|
||||
int shellCmdGroupRun(ShellCommand *group, int argc, char *argv[]);
|
||||
@@ -0,0 +1,68 @@
|
||||
/**
|
||||
* @file shell_passthrough.c
|
||||
* @author Letter(nevermindzzt@gmail.com)
|
||||
* @brief shell passthrough mode
|
||||
* @version 0.1
|
||||
* @date 2021-05-31
|
||||
*
|
||||
* @copyright (c) 2021 Letter
|
||||
*
|
||||
*/
|
||||
#include "shell_passthrough.h"
|
||||
#include "string.h"
|
||||
|
||||
/**
|
||||
* @brief shell passthrough 模式
|
||||
*
|
||||
* @param shell shell
|
||||
* @param prompt passthrough 提示符
|
||||
* @param handler pssthrough handler
|
||||
* @param argc 命令行参数数量
|
||||
* @param argv 命令行参数
|
||||
*
|
||||
* @return unsigned int 返回值
|
||||
*/
|
||||
unsigned int shellPassthrough(Shell *shell, const char *prompt, ShellPassthrough handler, int argc, char *argv[])
|
||||
{
|
||||
char data;
|
||||
|
||||
if (argc > 1)
|
||||
{
|
||||
handler(argv[1], strlen(argv[1]));
|
||||
}
|
||||
else
|
||||
{
|
||||
shell->status.isActive = 0;
|
||||
shellWriteString(shell, prompt);
|
||||
while (1)
|
||||
{
|
||||
if (shell->read && shell->read(&data, 1) == 1)
|
||||
{
|
||||
if (data == '\r' || data == '\n')
|
||||
{
|
||||
shellWriteString(shell, "\r\n");
|
||||
if (shell->parser.length != 0)
|
||||
{
|
||||
shell->parser.buffer[shell->parser.length] = 0;
|
||||
handler(shell->parser.buffer, shell->parser.length);
|
||||
shell->parser.length = 0;
|
||||
shell->parser.cursor = 0;
|
||||
}
|
||||
shellWriteString(shell, prompt);
|
||||
}
|
||||
else if (data == SHELL_PASSTHROUGH_EXIT_KEY)
|
||||
{
|
||||
shellWriteString(shell, "\r\n");
|
||||
shell->parser.length = 0;
|
||||
shell->parser.cursor = 0;
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
{
|
||||
shellHandler(shell, data);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/**
|
||||
* @file shell_passthrough.h
|
||||
* @author Letter(nevermindzzt@gmail.com)
|
||||
* @brief shell passthrough mode
|
||||
* @version 0.1
|
||||
* @date 2021-05-31
|
||||
*
|
||||
* @copyright (c) 2021 Letter
|
||||
*
|
||||
*/
|
||||
#ifndef __SHELL_PASSTHROUGH_H__
|
||||
#define __SHELL_PASSTHROUGH_H__
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
/**
|
||||
* @brief 退出 passthrough 模式的按键键值,单字节
|
||||
*/
|
||||
#define SHELL_PASSTHROUGH_EXIT_KEY 0x04 // Ctrl + D
|
||||
|
||||
/**
|
||||
* @brief passthrough 模式 handler 函数原型
|
||||
*
|
||||
* @param data 数据
|
||||
* @param len 数据长度
|
||||
*
|
||||
* @return int 返回值
|
||||
*/
|
||||
typedef int (*ShellPassthrough)(char *data, unsigned short len);
|
||||
|
||||
/**
|
||||
* @brief shell passthrough 模式函数名
|
||||
*/
|
||||
#define SHELL_PASSTROUGH_FUNC_NAME(_name) agency##_name
|
||||
|
||||
/**
|
||||
* @brief shell passthrough 模式函数定义
|
||||
*
|
||||
* @param _name 命令名
|
||||
* @param _prompt passthrough 模式提示符
|
||||
* @param _handler passthrough 模式 handler
|
||||
*/
|
||||
#define SHELL_PASSTROUGH_FUNC(_name, _prompt, _handler) \
|
||||
void SHELL_PASSTROUGH_FUNC_NAME(_name)(int p1, int p2) \
|
||||
{ shellPassthrough(shellGetCurrent(), #_prompt, _handler, p1, (void *)p2); }
|
||||
|
||||
/**
|
||||
* @brief shell passthrouh 定义
|
||||
*
|
||||
* @param _attr 属性
|
||||
* @param _name passthrough 命令名
|
||||
* @param _prompt passthrough 提示符
|
||||
* @param _handler passthrough handler
|
||||
* @param _desc passthrough 描述
|
||||
*/
|
||||
#define SHELL_EXPORT_PASSTROUGH(_attr, _name, _prompt, _handler, _desc) \
|
||||
SHELL_PASSTROUGH_FUNC(_name, _prompt, _handler) \
|
||||
SHELL_EXPORT_CMD(_attr|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN), _name, SHELL_PASSTROUGH_FUNC_NAME(_name), _desc)
|
||||
|
||||
unsigned int shellPassthrough(Shell *shell, const char *prompt, ShellPassthrough handler, int argc, char *argv[]);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,24 @@
|
||||
/**
|
||||
* @file shell_secure_user.c
|
||||
* @author Letter (nevermindzzt@gmail.com)
|
||||
* @brief shell secure user
|
||||
* @version 0.1
|
||||
* @date 2022-03-12
|
||||
*
|
||||
* @copyright Copyright (c) 2022 Letter
|
||||
*
|
||||
*/
|
||||
#include "shell_secure_user.h"
|
||||
|
||||
extern void shellSetUser(Shell *shell, const ShellCommand *user);
|
||||
|
||||
ShellCommand secureUser;
|
||||
|
||||
int shellSecureUser(Shell *shell, const char *name, int attr, ShellSecureUserGetPassword handler)
|
||||
{
|
||||
secureUser.attr.value = attr | SHELL_CMD_TYPE(SHELL_TYPE_USER);
|
||||
secureUser.data.user.name = name;
|
||||
secureUser.data.user.password = handler(name);
|
||||
shellSetUser(shell, &secureUser);
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @file shell_secure_user.h
|
||||
* @author Letter (nevermindzzt@gmail.com)
|
||||
* @brief shell secure user
|
||||
* @version 0.1
|
||||
* @date 2022-03-12
|
||||
*
|
||||
* @copyright Copyright (c) 2022 Letter
|
||||
*
|
||||
*/
|
||||
#ifndef __SHELL_SECURE_USER_H__
|
||||
#define __SHELL_SECURE_USER_H__
|
||||
|
||||
#include "shell.h"
|
||||
|
||||
/**
|
||||
* @brief shell secure user 获取用户密码函数原型
|
||||
*
|
||||
* @param name 用户名
|
||||
*
|
||||
* @return char* 用户密码
|
||||
*/
|
||||
typedef char* (*ShellSecureUserGetPassword)(const char *name);
|
||||
|
||||
/**
|
||||
* @brief shell secure user 代理函数名
|
||||
*
|
||||
*/
|
||||
#define SHELL_SECURE_USER_FUNC_NAME(_name) agency##_name
|
||||
|
||||
/**
|
||||
* @brief shell secure user 代理函数定义
|
||||
*
|
||||
* @param _name 用户名
|
||||
* @param _attr 用户命令属性
|
||||
* @param _handler 获取用户密码函数
|
||||
*/
|
||||
#define SHELL_SECURE_USER_FUNC(_name, _attr, _handler) \
|
||||
void SHELL_SECURE_USER_FUNC_NAME(_name)(int p1, int p2) \
|
||||
{ shellSecureUser(shellGetCurrent(), #_name, _attr, _handler); }
|
||||
|
||||
/**
|
||||
* @brief shell secure user 定义
|
||||
*
|
||||
* @param _attr 属性
|
||||
* @param _name 用户名
|
||||
* @param _handler 获取用户密码函数
|
||||
* @param _desc 命令描述
|
||||
*/
|
||||
#define SHELL_EXPORT_SECURE_USER(_attr, _name, _handler, _desc) \
|
||||
SHELL_SECURE_USER_FUNC(_name, _attr, _handler) \
|
||||
SHELL_EXPORT_CMD(SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN, \
|
||||
_name, SHELL_SECURE_USER_FUNC_NAME(_name), _desc)
|
||||
|
||||
|
||||
int shellSecureUser(Shell *shell, const char *name, int attr, ShellSecureUserGetPassword handler);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,85 @@
|
||||
# telnet
|
||||
|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
基于letter shell运行的telnet
|
||||
|
||||
- [telnet](#telnet)
|
||||
- [简介](#简介)
|
||||
- [使用](#使用)
|
||||
- [其他](#其他)
|
||||
|
||||
## 简介
|
||||
|
||||
telnet是基于letter shell运行的一个telnet服务端,可以在一些具有网络能力的嵌入式环境中使用,特别适用于现场不方便接线条件下的调试工作,telnet默认运行在23端口,可以在`telnetd.h`文件中进行配置,也可以在启动服务前,调用`telnetdSetPort`进行修改,注意23端口可能会被系统占用
|
||||
|
||||
## 使用
|
||||
|
||||
1. 修改包含的头文件
|
||||
|
||||
telnet使用标准的socket接口实现,运行此telnet实现需要你的运行环境具有socket接口,使用时,需要首先确认你的运行环境中,提供标准socket的头文件,然后替换`telnetd.c`文件中包含的头文件
|
||||
|
||||
```c
|
||||
#include "sys/socket.h"
|
||||
#include "arpa/inet.h"
|
||||
#include "netinet/in.h"
|
||||
```
|
||||
|
||||
2. 实现线程接口
|
||||
|
||||
telnet的运行需要多任务支持,你选哟提供一个用于创建新线程的接口,下面是在linux环境下的示例
|
||||
|
||||
```c
|
||||
/**
|
||||
* @brief 新线程接口
|
||||
*
|
||||
* @param handler 线程函数
|
||||
* @param param 线程参数
|
||||
*
|
||||
* @return int 0 启动成功 -1 启动失败
|
||||
*/
|
||||
int userNewThread(void *handler, void *param)
|
||||
{
|
||||
pthread_t tid;
|
||||
|
||||
return pthread_create(&tid, NULL, handler, param) == 0 ? 0 : -1;
|
||||
}
|
||||
```
|
||||
|
||||
3. 初始化
|
||||
|
||||
```c
|
||||
telnetdInit(userNewThread);
|
||||
```
|
||||
|
||||
4. 启动
|
||||
|
||||
直接调用`telnetdStart`函数,或者在shell执行`telnetd start`命令,启动telent server
|
||||
|
||||
## 其他
|
||||
|
||||
- 只支持一个客户端连接
|
||||
|
||||
做telnet这个功能的时候发现,letter shell目前提供的接口,不好在telnet上做多客户端支持,遂暂时只支持一个客户端连接
|
||||
|
||||
- 部分shell功能不可用
|
||||
|
||||
目前的telent实现没有实现letter shell的`read`接口,所以部分依赖于此接口的功能,比如说`shellScan`都是不可用的
|
||||
|
||||
- 使用telent需要开启letter shell的伴生对象功能
|
||||
|
||||
- 性能优化
|
||||
|
||||
对于资源紧张的单片机,telnet频繁的网络操作可能会对系统性能产生压力,此时建议优化`telentd.c`中的`telnetdWrite`函数,可以使用环形缓冲区,每次此接口写入的数据不直接调用`send`函数,而是写入缓冲区,然后定时(100ms左右)调用`send`函数清空缓冲区
|
||||
|
||||
- x86 demo
|
||||
|
||||
x86 demo中实现了telnet的接口,可以直接运行试用
|
||||
|
||||
```sh
|
||||
letter:/$ telnetd setPort 4545
|
||||
letter:/$ telnetd start
|
||||
```
|
||||
@@ -0,0 +1,208 @@
|
||||
/**
|
||||
* @file telnetd.c
|
||||
* @author Letter
|
||||
* @brief telnet server for letter shell
|
||||
* @version 0.1
|
||||
* @date 2021-08-07
|
||||
*
|
||||
* @copyright (c) 2021 Letter
|
||||
*
|
||||
*/
|
||||
#include "telnetd.h"
|
||||
|
||||
#include "sys/socket.h"
|
||||
#include "arpa/inet.h"
|
||||
#include "netinet/in.h"
|
||||
|
||||
#include "shell.h"
|
||||
#include "shell_cmd_group.h"
|
||||
|
||||
#if SHELL_USING_COMPANION != 1
|
||||
#error telent for letter shell can not be used while shell companion is diabled
|
||||
#endif
|
||||
|
||||
/**
|
||||
* @brief 新线程接口实例
|
||||
*/
|
||||
static NewThread newThread;
|
||||
|
||||
/**
|
||||
* @brief telnet server socket
|
||||
*/
|
||||
static int telnetdSocket;
|
||||
|
||||
/**
|
||||
* @brief telent server shell
|
||||
*/
|
||||
static Shell *telnetdShell;
|
||||
|
||||
/**
|
||||
* @brief telnet server 监听端口
|
||||
*/
|
||||
static int telnetdPort = TELNETD_DEFAULT_SERVER_PORT;
|
||||
|
||||
static void telnetdServer(void);
|
||||
static void telnetdConnection(int client);
|
||||
static void telentdWrite(char *data, short len);
|
||||
|
||||
/**
|
||||
* @brief telnet 协议命令
|
||||
*/
|
||||
static char telnetCmd[] = {0xff, 0xfb, 0x01, 0xff, 0xfb, 0x03, 0xff, 0xfc, 0x1f};
|
||||
|
||||
/**
|
||||
* @brief telnet server初始化
|
||||
*
|
||||
* @param newThreadInterface 新线程接口
|
||||
*
|
||||
* @return int 0 启动telent成功 -1 启动失败
|
||||
*/
|
||||
int telentdInit(NewThread newThreadInterface)
|
||||
{
|
||||
newThread = newThreadInterface;
|
||||
return newThread ? 0 : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 启动 telnet server
|
||||
*
|
||||
* @return int 0 启动telent成功 -1 启动失败
|
||||
*/
|
||||
int telnetdStart()
|
||||
{
|
||||
return newThread ? newThread(telnetdServer, NULL) : -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 停止 telnet server
|
||||
*
|
||||
*/
|
||||
void telnetdStop()
|
||||
{
|
||||
close(telnetdSocket);
|
||||
if (telnetdShell != NULL)
|
||||
{
|
||||
close((int) shellCompanionGet(telnetdShell, SHELL_COMPANION_ID_TELNETD));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 修改telnet server 监听端口
|
||||
*
|
||||
* @param port 端口
|
||||
*
|
||||
*/
|
||||
void telnetdSetPort(int port)
|
||||
{
|
||||
telnetdPort = port;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief telent 服务
|
||||
*
|
||||
*
|
||||
*/
|
||||
static void telnetdServer(void)
|
||||
{
|
||||
struct sockaddr_in telnetdAddr;
|
||||
int client;
|
||||
struct sockaddr_in clientAddr;
|
||||
int addrLen = sizeof(clientAddr);
|
||||
|
||||
telnetdSocket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
|
||||
memset(&telnetdAddr, 0, sizeof(telnetdAddr));
|
||||
telnetdAddr.sin_family = AF_INET,
|
||||
telnetdAddr.sin_addr.s_addr = inet_addr(TELNETD_SERVER_ADDRESS);
|
||||
telnetdAddr.sin_port = htons(telnetdPort);
|
||||
if (bind(telnetdSocket, (struct sockaddr *)&telnetdAddr, sizeof(telnetdAddr)) == 0 &&
|
||||
listen(telnetdSocket, 5) == 0)
|
||||
{
|
||||
while (1)
|
||||
{
|
||||
client = accept(telnetdSocket, (struct sockaddr *) &clientAddr, (socklen_t *) &addrLen);
|
||||
if (client > 0)
|
||||
{
|
||||
newThread(telnetdConnection, (void *) client);
|
||||
}
|
||||
else if (client <= 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
close(telnetdSocket);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief telnet server 连接处理
|
||||
*
|
||||
* @param client 客户端连接socket
|
||||
*
|
||||
*/
|
||||
static void telnetdConnection(int client)
|
||||
{
|
||||
int len = 0;
|
||||
char *data = SHELL_MALLOC(16);
|
||||
char *shellBuffer = SHELL_MALLOC(TELNETD_SHELL_BUFFER_SIZE);
|
||||
telnetdShell = SHELL_MALLOC(sizeof(Shell));
|
||||
|
||||
/** 处理 telent 协议 */
|
||||
send(client, telnetCmd, 9, 0);
|
||||
recv(client, data, 6, 0);
|
||||
|
||||
telnetdShell->write = telentdWrite;
|
||||
shellCompanionAdd(telnetdShell, SHELL_COMPANION_ID_TELNETD, (void *)client);
|
||||
shellInit(telnetdShell, shellBuffer, TELNETD_SHELL_BUFFER_SIZE);
|
||||
|
||||
if (TELNETD_SHELL_USER)
|
||||
{
|
||||
shellRun(telnetdShell, TELNETD_SHELL_USER);
|
||||
}
|
||||
|
||||
while (1)
|
||||
{
|
||||
len = recv(client, data, 1, 0);
|
||||
if (len == 0)
|
||||
{
|
||||
break;
|
||||
}
|
||||
else if (len == 1)
|
||||
{
|
||||
shellHandler(telnetdShell, data[0]);
|
||||
}
|
||||
}
|
||||
shellDeInit(telnetdShell);
|
||||
SHELL_FREE(data);
|
||||
SHELL_FREE(shellBuffer);
|
||||
SHELL_FREE(telnetdShell);
|
||||
telnetdShell = NULL;
|
||||
close(client);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief telnet server数据写
|
||||
*
|
||||
* @param data 写入的数据
|
||||
* @param len 数据长度
|
||||
*
|
||||
*/
|
||||
static void telentdWrite(char *data, short len)
|
||||
{
|
||||
int client = (int) shellCompanionGet(telnetdShell, SHELL_COMPANION_ID_TELNETD);
|
||||
if (client != 0)
|
||||
{
|
||||
send(client, data, len, 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ShellCommand telnetdGroup[] =
|
||||
{
|
||||
SHELL_CMD_GROUP_ITEM(SHELL_TYPE_CMD_FUNC, start, telnetdStart, start telnet server),
|
||||
SHELL_CMD_GROUP_ITEM(SHELL_TYPE_CMD_FUNC, stop, telnetdStop, stop telnet server),
|
||||
SHELL_CMD_GROUP_ITEM(SHELL_TYPE_CMD_FUNC, setPort, telnetdSetPort, set telnet server port),
|
||||
SHELL_CMD_GROUP_END()
|
||||
};
|
||||
SHELL_EXPORT_CMD_GROUP(
|
||||
SHELL_CMD_PERMISSION(0)|SHELL_CMD_TYPE(SHELL_TYPE_CMD_MAIN)|SHELL_CMD_DISABLE_RETURN,
|
||||
telnetd, telnetdGroup, telnet server\ninput telent -h for more help);
|
||||
@@ -0,0 +1,76 @@
|
||||
/**
|
||||
* @file telnetd.h
|
||||
* @author Letter
|
||||
* @brief telnet server for letter shell
|
||||
* @version 0.1
|
||||
* @date 2021-08-07
|
||||
*
|
||||
* @copyright (c) 2021 Letter
|
||||
*
|
||||
*/
|
||||
#ifndef __TELNETD_H__
|
||||
#define __TELNETD_H__
|
||||
|
||||
/**
|
||||
* @brief 版本
|
||||
*/
|
||||
#define TELNET_VERSION "1.0.0"
|
||||
|
||||
/**
|
||||
* @brief telnetd shell伴生对象ID
|
||||
*/
|
||||
#define SHELL_COMPANION_ID_TELNETD -3
|
||||
|
||||
/**
|
||||
* @brief telnet server 监听的IP
|
||||
*/
|
||||
#define TELNETD_SERVER_ADDRESS "127.0.0.1"
|
||||
|
||||
/**
|
||||
* @brief telnet 默认监听端口
|
||||
*/
|
||||
#define TELNETD_DEFAULT_SERVER_PORT 23
|
||||
|
||||
/**
|
||||
* @brief telnet shell的数据缓冲区大小
|
||||
*/
|
||||
#define TELNETD_SHELL_BUFFER_SIZE 512
|
||||
|
||||
/**
|
||||
* @brief telnet shell的用户名,使用默认shell用户设置为NULL即可
|
||||
*/
|
||||
#define TELNETD_SHELL_USER NULL
|
||||
|
||||
/**
|
||||
* @brief 新线程接口
|
||||
*
|
||||
* @param void * 线程执行函数
|
||||
* @param void * 线程参数
|
||||
*
|
||||
* @reutrn int 0 启动线程成功 -1 启动线程失败
|
||||
*/
|
||||
typedef int (*NewThread)(void *, void *);
|
||||
|
||||
/**
|
||||
* @brief telnet server初始化
|
||||
*
|
||||
* @param newThreadInterface 新线程接口
|
||||
*
|
||||
* @return int 0 启动telent server成功 -1 启动失败
|
||||
*/
|
||||
int telentdInit(NewThread newThreadInterface);
|
||||
|
||||
/**
|
||||
* @brief 启动 telnet server
|
||||
*
|
||||
* @return int 0 启动telent成功 -1 启动失败
|
||||
*/
|
||||
int telnetdStart();
|
||||
|
||||
/**
|
||||
* @brief 停止 telnet server
|
||||
*
|
||||
*/
|
||||
void telnetdStop();
|
||||
|
||||
#endif
|
||||
Reference in new issue
Block a user