提交V2版本
52
.gitignore
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
*.pyc
|
||||||
|
*.map
|
||||||
|
*.dblite
|
||||||
|
*.elf
|
||||||
|
*.bin
|
||||||
|
*.hex
|
||||||
|
*.axf
|
||||||
|
*.exe
|
||||||
|
*.pdb
|
||||||
|
*.idb
|
||||||
|
*.ilk
|
||||||
|
*.old
|
||||||
|
|
||||||
|
documentation/html
|
||||||
|
*~
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
*.bak
|
||||||
|
*.dep
|
||||||
|
*.lib
|
||||||
|
*.i
|
||||||
|
*.d
|
||||||
|
*.dbgdt
|
||||||
|
*.crun
|
||||||
|
*.bat
|
||||||
|
*.ps1
|
||||||
|
*.scl
|
||||||
|
*.dnx
|
||||||
|
*.regroups
|
||||||
|
*.wsdt
|
||||||
|
tools/kconfig-frontends/kconfig-mconf
|
||||||
|
packages
|
||||||
|
cconfig.h
|
||||||
|
GPUCache
|
||||||
|
*.vs/
|
||||||
|
*bin/
|
||||||
|
*obj/
|
||||||
|
#cscope files
|
||||||
|
cscope.*
|
||||||
|
ncscope.*
|
||||||
|
|
||||||
|
#ctag files
|
||||||
|
/samples/linux/output/*
|
||||||
|
|
||||||
|
/samples/none_os/iar/Debug/*
|
||||||
|
/samples/none_os/iar/settings/*
|
||||||
|
|
||||||
|
/samples/none_os/mdk/Debug
|
||||||
|
/samples/none_os/mdk/list
|
||||||
|
/samples/none_os/mdk/obj
|
||||||
|
/samples/none_os/mdk/DebugConfig
|
||||||
|
|
25
.vscode/launch.json
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "g++ build and debug active file",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/samples/linux/output/demo",
|
||||||
|
"args": [],
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"environment": [],
|
||||||
|
"externalConsole": false,
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"description": "Enable pretty-printing for gdb",
|
||||||
|
"text": "-enable-pretty-printing",
|
||||||
|
"ignoreFailures": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preLaunchTask": "Build"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
9
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"makefile.launchConfigurations": [
|
||||||
|
{
|
||||||
|
"cwd": "${workspaceFolder}/samples/linux/output",
|
||||||
|
"binaryPath": "${workspaceFolder}/samples/linux/output/demo",
|
||||||
|
"binaryArgs": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
38
.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"type": "shell",
|
||||||
|
"label": "Build",
|
||||||
|
"command": "make clean & make",
|
||||||
|
"options": {
|
||||||
|
"cwd": "${workspaceFolder}/samples/linux"
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"echo": true,
|
||||||
|
"reveal": "always",
|
||||||
|
"focus": false,
|
||||||
|
"panel": "shared"
|
||||||
|
},
|
||||||
|
"problemMatcher": {
|
||||||
|
"owner": "cpp",
|
||||||
|
"fileLocation": [
|
||||||
|
"relative",
|
||||||
|
"${workspaceFolder}/samples/linux"
|
||||||
|
],
|
||||||
|
"pattern": {
|
||||||
|
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
|
||||||
|
"file": 1,
|
||||||
|
"line": 2,
|
||||||
|
"column": 3,
|
||||||
|
"severity": 4,
|
||||||
|
"message": 5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -1,534 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
* @brief ATָ<EFBFBD><EFBFBD>ͨ<EFBFBD>Ź<EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020~2021, <morro_luo@163.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apathe-2.0
|
|
||||||
*
|
|
||||||
* Change Logs:
|
|
||||||
* Date Author Notes
|
|
||||||
* 2020-01-02 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* 2021-01-20 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD>debug<EFBFBD><EFBFBD><EFBFBD>Խӿ<EFBFBD>, <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* <EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƚӿ<EFBFBD>
|
|
||||||
* 2021-03-03 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>URC<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӡ<EFBFBD><EFBFBD><EFBFBD>ճ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
#include "at_chat.h"
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
//<2F><>ʱ<EFBFBD>ж<EFBFBD>
|
|
||||||
#define AT_IS_TIMEOUT(start, time) (AT_GET_TICK() - (start) > (time))
|
|
||||||
|
|
||||||
/**AT<41><54>ҵ<EFBFBD><D2B5><EFBFBD><EFBFBD>(ʵ<><CAB5><EFBFBD><EFBFBD>4<EFBFBD><34><EFBFBD><EFBFBD><EFBFBD>͵<EFBFBD>״̬<D7B4><CCAC><EFBFBD><EFBFBD>ѯ<EFBFBD><D1AF><EFBFBD><EFBFBD>) -----------------------------------*/
|
|
||||||
#define AT_TYPE_WORK 0 /* <20><>ͨ<EFBFBD><CDA8>ҵ ----------*/
|
|
||||||
#define AT_TYPE_CMD 1 /* <20><><EFBFBD><D7BC><EFBFBD><EFBFBD> ----------*/
|
|
||||||
#define AT_TYPE_MULTILINE 2 /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ----------*/
|
|
||||||
#define AT_TYPE_SINGLLINE 3 /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ----------*/
|
|
||||||
|
|
||||||
#ifndef AT_DEBUG
|
|
||||||
#define AT_DEBUG(...) do {}while(0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef int (*base_work)(at_obj_t *at, ...);
|
|
||||||
|
|
||||||
static void at_send_line(at_obj_t *at, const char *fmt, va_list args);
|
|
||||||
|
|
||||||
static const inline at_adapter_t *__get_adapter(at_obj_t *at)
|
|
||||||
{
|
|
||||||
return &at->adap;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool at_is_timeout(at_obj_t *at, unsigned int ms)
|
|
||||||
{
|
|
||||||
return AT_IS_TIMEOUT(at->timer, ms);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static void send_data(at_obj_t *at, const void *buf, unsigned int len)
|
|
||||||
{
|
|
||||||
at->adap.write(buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӡ
|
|
||||||
*/
|
|
||||||
static void print(at_obj_t *at, const char *cmd, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
va_start(args, cmd);
|
|
||||||
at_send_line(at, cmd, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD>ݽ<EFBFBD><EFBFBD>ճ<EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static unsigned int get_recv_count(at_obj_t *at)
|
|
||||||
{
|
|
||||||
return at->recv_cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static char *get_recv_buf(at_obj_t *at)
|
|
||||||
{
|
|
||||||
return (char *)at->adap.recv_buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static void recv_buf_clear(at_obj_t *at)
|
|
||||||
{
|
|
||||||
at->recv_cnt = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**ǰ<><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD>*/
|
|
||||||
static char *search_string(at_obj_t *at, const char *str)
|
|
||||||
{
|
|
||||||
return strstr(get_recv_buf(at), str);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD>ִֹ<EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static bool at_isabort(at_obj_t *at)
|
|
||||||
{
|
|
||||||
return at->cursor ? at->cursor->abort : 1;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD>ü<EFBFBD>ʱ<EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static void at_reset_timer(at_obj_t *at)
|
|
||||||
{
|
|
||||||
at->timer = AT_GET_TICK();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @brief ATִ<EFBFBD>лص<EFBFBD>
|
|
||||||
*/
|
|
||||||
static void do_at_callbatk(at_obj_t *a, at_item_t *i, at_callbatk_t cb, at_return ret)
|
|
||||||
{
|
|
||||||
at_response_t r;
|
|
||||||
if ((ret == AT_RET_ERROR || ret == AT_RET_TIMEOUT) && a->adap.error != NULL)
|
|
||||||
a->adap.error();
|
|
||||||
|
|
||||||
if (cb) {
|
|
||||||
r.param = i->param;
|
|
||||||
r.recvbuf = get_recv_buf(a);
|
|
||||||
r.recvcnt = get_recv_count(a);
|
|
||||||
r.ret = ret;
|
|
||||||
cb(&r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ<EFBFBD><D2B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
static bool add_work(at_obj_t *at, void *params, void *info, int type)
|
|
||||||
{
|
|
||||||
at_item_t *i;
|
|
||||||
if (list_empty(&at->ls_idle)) //<2F><EFBFBD><DEBF><EFBFBD>at_item
|
|
||||||
return NULL;
|
|
||||||
i = list_first_entry(&at->ls_idle, at_item_t, node);//<2F>ӿ<EFBFBD><D3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>ҵ
|
|
||||||
i->info = (void *)info;
|
|
||||||
i->param = (void *)params;
|
|
||||||
i->state = AT_STATE_WAIT;
|
|
||||||
i->type = type;
|
|
||||||
i->abort = 0;
|
|
||||||
list_move_tail(&i->node, &at->ls_ready); //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
return i != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ִ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ
|
|
||||||
*/
|
|
||||||
static int do_work_handler(at_obj_t *at)
|
|
||||||
{
|
|
||||||
at_item_t *i = at->cursor;
|
|
||||||
return ((int (*)(at_env_t *e))i->info)(&at->env);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] a - AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @return true - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ, false - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ,
|
|
||||||
*/
|
|
||||||
static int do_cmd_handler(at_obj_t *a)
|
|
||||||
{
|
|
||||||
at_item_t *i = a->cursor;
|
|
||||||
at_env_t *e = &a->env;
|
|
||||||
const at_cmd_t *c = (at_cmd_t *)i->info;
|
|
||||||
switch(e->state) {
|
|
||||||
case 0: /*<2A><><EFBFBD><EFBFBD>״̬ ------------------------------------------------------*/
|
|
||||||
c->sender(e);
|
|
||||||
e->state++;
|
|
||||||
e->reset_timer(a);
|
|
||||||
e->recvclr(a);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
if (search_string(a, c->matcher)) { //<2F><><EFBFBD><EFBFBD>ƥ<EFBFBD><C6A5>
|
|
||||||
AT_DEBUG("<-\r\n%s\r\n", get_recv_buf(a));
|
|
||||||
do_at_callbatk(a, i, c->cb, AT_RET_OK);
|
|
||||||
return true;
|
|
||||||
} else if (search_string(a, "ERROR")) {
|
|
||||||
AT_DEBUG("<-\r\n%s\r\n", get_recv_buf(a));
|
|
||||||
if (++e->i >= c->retry) {
|
|
||||||
do_at_callbatk(a, i, c->cb, AT_RET_ERROR);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
e->state = 2; /* <20><><EFBFBD><EFBFBD>֮<EFBFBD><D6AE><EFBFBD><EFBFBD>ʱһ<CAB1><D2BB>ʱ<EFBFBD><CAB1>*/
|
|
||||||
e->reset_timer(a); /* <20><><EFBFBD>ö<EFBFBD>ʱ<EFBFBD><CAB1>*/
|
|
||||||
} else if (e->is_timeout(a, c->timeout)) { /* <20><>Ӧ<EFBFBD><D3A6>ʱ*/
|
|
||||||
if (++e->i >= c->retry) {
|
|
||||||
do_at_callbatk(a, i, c->cb, AT_RET_TIMEOUT);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
e->state = 0; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ״̬*/
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (e->is_timeout(a, 500))
|
|
||||||
e->state = 0; /*<2A><><EFBFBD>س<EFBFBD>ʼ״̬*/
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
e->state = 0;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] a - AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @return true - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ, false - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ,
|
|
||||||
*/
|
|
||||||
static int send_signlline_handler(at_obj_t *a)
|
|
||||||
{
|
|
||||||
at_item_t *i = a->cursor;
|
|
||||||
at_env_t *e = &a->env;
|
|
||||||
const char *cmd = (const char *)i->param;
|
|
||||||
at_callbatk_t cb = (at_callbatk_t)i->info;
|
|
||||||
|
|
||||||
switch(e->state) {
|
|
||||||
case 0: /*<2A><><EFBFBD><EFBFBD>״̬ ------------------------------------------------------*/
|
|
||||||
e->printf(a, cmd);
|
|
||||||
e->state++;
|
|
||||||
e->reset_timer(a);
|
|
||||||
e->recvclr(a);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
if (search_string(a, "OK")) {
|
|
||||||
AT_DEBUG("<-\r\n%s\r\n", get_recv_buf(a));
|
|
||||||
do_at_callbatk(a, i, cb, AT_RET_OK); //<2F><><EFBFBD><EFBFBD>ƥ<EFBFBD><C6A5>
|
|
||||||
return true;
|
|
||||||
} else if (search_string(a, "ERROR")) {
|
|
||||||
AT_DEBUG("<-\r\n%s\r\n", get_recv_buf(a));
|
|
||||||
if (++e->i >= 3) {
|
|
||||||
do_at_callbatk(a, i, cb, AT_RET_ERROR);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
e->state = 2; /*<2A><><EFBFBD><EFBFBD>֮<EFBFBD><D6AE><EFBFBD><EFBFBD>ʱһ<CAB1><D2BB>ʱ<EFBFBD><CAB1>*/
|
|
||||||
e->reset_timer(a); /*<2A><><EFBFBD>ö<EFBFBD>ʱ<EFBFBD><CAB1>*/
|
|
||||||
} else if (e->is_timeout(a, 3000 + e->i * 2000)) {
|
|
||||||
if (++e->i >= 3) {
|
|
||||||
do_at_callbatk(a, i, cb, AT_RET_TIMEOUT);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
e->state = 0; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ״̬*/
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (e->is_timeout(a, 500))
|
|
||||||
e->state = 0; /**<2A><><EFBFBD>س<EFBFBD>ʼ״̬*/
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
e->state = 0;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] a - AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @return true - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ, false - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ,
|
|
||||||
*/
|
|
||||||
static int send_multiline_handler(at_obj_t *a)
|
|
||||||
{
|
|
||||||
at_item_t *i = a->cursor;
|
|
||||||
at_env_t *e = &a->env;
|
|
||||||
const char **cmds = (const char **)i->param;
|
|
||||||
at_callbatk_t cb = (at_callbatk_t)i->info;
|
|
||||||
switch(e->state) {
|
|
||||||
case 0:
|
|
||||||
if (cmds[e->i] == NULL) { /**<2A><><EFBFBD><EFBFBD>ִ<EFBFBD><D6B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
do_at_callbatk(a, i, cb, AT_RET_OK);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
e->printf(a, "%s\r\n", cmds[e->i]);
|
|
||||||
e->recvclr(a); /**<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
e->reset_timer(a);
|
|
||||||
e->state++;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
if (search_string(a, "OK")) {
|
|
||||||
e->state = 0;
|
|
||||||
e->i++;
|
|
||||||
e->j = 0;
|
|
||||||
AT_DEBUG("<-\r\n%s\r\n", get_recv_buf(a));
|
|
||||||
} else if (search_string(a, "ERROR")) {
|
|
||||||
AT_DEBUG("<-\r\n%s\r\n", get_recv_buf(a));
|
|
||||||
if (++e->j >= 3) {
|
|
||||||
do_at_callbatk(a, i, cb, AT_RET_ERROR);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
e->state = 2; /*<2A><><EFBFBD><EFBFBD>֮<EFBFBD><D6AE><EFBFBD><EFBFBD>ʱһ<CAB1><D2BB>ʱ<EFBFBD><CAB1>*/
|
|
||||||
e->reset_timer(a); /*<2A><><EFBFBD>ö<EFBFBD>ʱ<EFBFBD><CAB1>*/
|
|
||||||
} else if (e->is_timeout(a, 3000)) {
|
|
||||||
do_at_callbatk(a, i, cb, AT_RET_TIMEOUT);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (e->is_timeout(a, 500))
|
|
||||||
e->state = 0; /**<2A><><EFBFBD>س<EFBFBD>ʼ״̬*/
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
e->state = 0;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] fmt - <EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] args - <EFBFBD>ɱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD>
|
|
||||||
*/
|
|
||||||
static void at_send_line(at_obj_t *at, const char *fmt, va_list args)
|
|
||||||
{
|
|
||||||
char buf[MAX_AT_CMD_LEN];
|
|
||||||
int len;
|
|
||||||
const at_adapter_t *adt = __get_adapter(at);
|
|
||||||
len = vsnprintf(buf, sizeof(buf), fmt, args);
|
|
||||||
|
|
||||||
recv_buf_clear(at); //<2F><><EFBFBD>ս<EFBFBD><D5BD>ջ<EFBFBD><D5BB><EFBFBD>
|
|
||||||
send_data(at, buf, len);
|
|
||||||
send_data(at, "\r\n", 2);
|
|
||||||
|
|
||||||
AT_DEBUG("->\r\n%s\r\n", buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief urc(unsolicited code) <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] urc - <EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] size - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
static void urc_handler_entry(at_obj_t *at, char *urc, unsigned int size)
|
|
||||||
{
|
|
||||||
int i, n;
|
|
||||||
utc_item_t *tbl = at->adap.utc_tbl;
|
|
||||||
for (i = 0; i < at->adap.urc_tbl_count; i++, tbl++) {
|
|
||||||
n = strlen(tbl->prefix);
|
|
||||||
if (strncmp(urc, tbl->prefix, n) == 0) { /* ƥ<><C6A5>ǰ */
|
|
||||||
tbl->handler(urc, size); /* <20>ص<EFBFBD><D8B5><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (at->cursor == NULL)
|
|
||||||
AT_DEBUG("<=\r\n%s\r\n", urc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief urc <EFBFBD><EFBFBD><EFBFBD>մ<EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] buf - <EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
static void urc_recv_process(at_obj_t *at, char *buf, unsigned int size)
|
|
||||||
{
|
|
||||||
char *urc_buf;
|
|
||||||
int ch;
|
|
||||||
unsigned short urc_size;
|
|
||||||
urc_buf = (char *)at->adap.urc_buf;
|
|
||||||
urc_size = at->adap.urc_bufsize;
|
|
||||||
|
|
||||||
if (size == 0 && at->urc_cnt > 0) {
|
|
||||||
if (AT_IS_TIMEOUT(at->urc_timer, 2000)) { /* <20><><EFBFBD>ճ<EFBFBD>ʱ*/
|
|
||||||
urc_handler_entry(at, urc_buf, at->urc_cnt);
|
|
||||||
if (at->urc_cnt > 1)
|
|
||||||
AT_DEBUG("Urc recv timeout.\r\n");
|
|
||||||
at->urc_cnt = 0;
|
|
||||||
}
|
|
||||||
} else if (urc_buf != NULL){
|
|
||||||
at->urc_timer = AT_GET_TICK();
|
|
||||||
while (size--) {
|
|
||||||
ch = *buf++;
|
|
||||||
urc_buf[at->urc_cnt++] = ch;
|
|
||||||
if (ch == '\n' || ch == '\r' || ch == '\0') { /*urc<72><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
urc_buf[at->urc_cnt] = '\0';
|
|
||||||
if (at->urc_cnt > 2)
|
|
||||||
urc_handler_entry(at, urc_buf, at->urc_cnt);
|
|
||||||
at->urc_cnt = 0;
|
|
||||||
} else if (at->urc_cnt >= urc_size) /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
|
||||||
at->urc_cnt = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><EFBFBD><EFBFBD>մ<EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
static void resp_recv_process(at_obj_t *at, const char *buf, unsigned int size)
|
|
||||||
{
|
|
||||||
char *recv_buf;
|
|
||||||
unsigned short recv_size;
|
|
||||||
|
|
||||||
recv_buf = (char *)at->adap.recv_buf;
|
|
||||||
recv_size = at->adap.recv_bufsize;
|
|
||||||
|
|
||||||
if (at->recv_cnt + size >= recv_size) //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
at->recv_cnt = 0;
|
|
||||||
|
|
||||||
memcpy(recv_buf + at->recv_cnt, buf, size);
|
|
||||||
at->recv_cnt += size;
|
|
||||||
recv_buf[at->recv_cnt] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>
|
|
||||||
* @param[in] at - AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] adap - AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
void at_obj_init(at_obj_t *at, const at_adapter_t *adap)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
at_env_t *e;
|
|
||||||
at->adap = *adap;
|
|
||||||
e = &at->env;
|
|
||||||
at->recv_cnt = 0;
|
|
||||||
|
|
||||||
e->is_timeout = at_is_timeout;
|
|
||||||
e->printf = print;
|
|
||||||
e->recvbuf = get_recv_buf;
|
|
||||||
e->recvclr = recv_buf_clear;
|
|
||||||
e->recvlen = get_recv_count;
|
|
||||||
e->find = search_string;
|
|
||||||
e->abort = at_isabort;
|
|
||||||
e->reset_timer = at_reset_timer;
|
|
||||||
|
|
||||||
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC>*/
|
|
||||||
INIT_LIST_HEAD(&at->ls_idle);
|
|
||||||
INIT_LIST_HEAD(&at->ls_ready);
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(at->items) / sizeof(at_item_t); i++)
|
|
||||||
list_add_tail(&at->items[i].node, &at->ls_idle);
|
|
||||||
|
|
||||||
while (adap->recv_buf == NULL) {} //ȷ<><C8B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD>ǿ<EFBFBD>
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ִ<EFBFBD><EFBFBD>AT<EFBFBD><EFBFBD>ҵ(<EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ)
|
|
||||||
* @param[in] a - AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] work - AT<EFBFBD><EFBFBD>ҵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] params -
|
|
||||||
*/
|
|
||||||
bool at_do_work(at_obj_t *at, int (*work)(at_env_t *e), void *params)
|
|
||||||
{
|
|
||||||
return add_work(at, params, (void *)work, AT_TYPE_WORK);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ִ<EFBFBD><EFBFBD>ATָ<EFBFBD><EFBFBD>
|
|
||||||
* @param[in] a - AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] cmd - cmd<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
bool at_do_cmd(at_obj_t *at, void *params, const at_cmd_t *cmd)
|
|
||||||
{
|
|
||||||
return add_work(at, params, (void *)cmd, AT_TYPE_CMD);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD>͵<EFBFBD><EFBFBD><EFBFBD>AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD>(Ĭ<EFBFBD>ϵȴ<EFBFBD>OK<EFBFBD><EFBFBD><EFBFBD><EFBFBD>, 3s<EFBFBD><EFBFBD>ʱ)
|
|
||||||
* @param[in] at - AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] cb - ִ<EFBFBD>лص<EFBFBD>
|
|
||||||
* @param[in] singlline - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @note <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֮ǰ,singlline<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч
|
|
||||||
*/
|
|
||||||
bool at_send_singlline(at_obj_t *at, at_callbatk_t cb, const char *singlline)
|
|
||||||
{
|
|
||||||
return add_work(at, (void *)singlline, (void *)cb, AT_TYPE_SINGLLINE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD><EFBFBD><EFBFBD>AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڳ<EFBFBD>ʼ<EFBFBD><EFBFBD>ģ<EFBFBD><EFBFBD>, Ĭ<EFBFBD>ϵȴ<EFBFBD>OK<EFBFBD><EFBFBD><EFBFBD><EFBFBD>, 3s<EFBFBD><EFBFBD>ʱ)
|
|
||||||
* @param[in] at - AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] cb - ִ<EFBFBD>лص<EFBFBD>
|
|
||||||
* @param[in] multiline - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @note <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֮ǰ,multiline
|
|
||||||
*/
|
|
||||||
bool at_send_multiline(at_obj_t *at, at_callbatk_t cb, const char **multiline)
|
|
||||||
{
|
|
||||||
return add_work(at, multiline, (void *)cb, AT_TYPE_MULTILINE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ǿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֹAT<EFBFBD><EFBFBD>ҵ
|
|
||||||
*/
|
|
||||||
|
|
||||||
void at_item_abort(at_item_t *i)
|
|
||||||
{
|
|
||||||
i->abort = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ATæ<EFBFBD>ж<EFBFBD>
|
|
||||||
* @return true - <EFBFBD><EFBFBD>ATָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
bool at_obj_busy(at_obj_t *at)
|
|
||||||
{
|
|
||||||
return !list_empty(&at->ls_ready);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief AT<EFBFBD><EFBFBD>ҵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static void at_work_manager(at_obj_t *at)
|
|
||||||
{
|
|
||||||
at_env_t *e = &at->env;
|
|
||||||
/*<2A><>ҵ<EFBFBD><D2B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD> --------------------------------------------------------------*/
|
|
||||||
static int (*const work_handler_table[])(at_obj_t *) = {
|
|
||||||
do_work_handler,
|
|
||||||
do_cmd_handler,
|
|
||||||
send_multiline_handler,
|
|
||||||
send_signlline_handler
|
|
||||||
};
|
|
||||||
if (at->cursor == NULL) {
|
|
||||||
if (list_empty(&at->ls_ready)) //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA>
|
|
||||||
return;
|
|
||||||
e->i = 0;
|
|
||||||
e->j = 0;
|
|
||||||
e->state = 0;
|
|
||||||
at->cursor = list_first_entry(&at->ls_ready, at_item_t, node);
|
|
||||||
e->params = at->cursor->param;
|
|
||||||
e->recvclr(at);
|
|
||||||
e->reset_timer(at);
|
|
||||||
}
|
|
||||||
/* <20><><EFBFBD><EFBFBD>ִ<EFBFBD><D6B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>뵽<EFBFBD><EBB5BD><EFBFBD>й<EFBFBD><D0B9><EFBFBD><EFBFBD><EFBFBD> -------------------------------------*/
|
|
||||||
if (work_handler_table[at->cursor->type](at) || at->cursor->abort) {
|
|
||||||
list_move_tail(&at->cursor->node, &at->ls_idle);
|
|
||||||
at->cursor = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief AT<EFBFBD><EFBFBD>ѯ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
void at_poll_task(at_obj_t *at)
|
|
||||||
{
|
|
||||||
char rbuf[32];
|
|
||||||
int read_size;
|
|
||||||
read_size = __get_adapter(at)->read(rbuf, sizeof(rbuf));
|
|
||||||
urc_recv_process(at, rbuf, read_size);
|
|
||||||
resp_recv_process(at, rbuf, read_size);
|
|
||||||
at_work_manager(at);
|
|
||||||
}
|
|
@ -1,148 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
* @brief ATָ<EFBFBD><EFBFBD>ͨ<EFBFBD>Ź<EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020~2021, <morro_luo@163.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apathe-2.0
|
|
||||||
*
|
|
||||||
* Change Logs:
|
|
||||||
* Date Author Notes
|
|
||||||
* 2020-01-02 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* 2021-01-20 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD>debug<EFBFBD><EFBFBD><EFBFBD>Խӿ<EFBFBD>, <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* <EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƚӿ<EFBFBD>
|
|
||||||
* 2021-03-03 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>URC<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӡ<EFBFBD><EFBFBD><EFBFBD>ճ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
#ifndef _ATCHAT_H_
|
|
||||||
#define _ATCHAT_H_
|
|
||||||
|
|
||||||
#include <list.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
|
|
||||||
/*<2A><><EFBFBD><EFBFBD>AT<41><54><EFBFBD><EFBFBD><EEB3A4> --------------------------------------------------------------*/
|
|
||||||
#define MAX_AT_CMD_LEN 128
|
|
||||||
|
|
||||||
/* debug <20><>ӡ<EFBFBD>ӿ<EFBFBD> ------------------------------------------------------------*/
|
|
||||||
#include <stdio.h>
|
|
||||||
#define AT_DEBUG(...) printf("[AT]:");printf(__VA_ARGS__) /*do{}while(0)*/
|
|
||||||
|
|
||||||
/* <20><>ȡϵͳ<CFB5>δ<EFBFBD>(ms) -----------------------------------------------------------*/
|
|
||||||
#include "platform.h"
|
|
||||||
#define AT_GET_TICK() get_tick()
|
|
||||||
|
|
||||||
struct at_obj;
|
|
||||||
|
|
||||||
/*urc<72><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD> -----------------------------------------------------------------*/
|
|
||||||
typedef struct {
|
|
||||||
const char *prefix; //<2F><>Ҫƥ<D2AA><C6A5><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7>
|
|
||||||
void (*handler)(char *recvbuf, int size);
|
|
||||||
}utc_item_t;
|
|
||||||
|
|
||||||
/*AT<41>ӿ<EFBFBD><D3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ---------------------------------------------------------------*/
|
|
||||||
typedef struct {
|
|
||||||
unsigned int (*write)(const void *buf, unsigned int len); /* <20><><EFBFBD>ͽӿ<CDBD>*/
|
|
||||||
unsigned int (*read)(void *buf, unsigned int len); /* <20><><EFBFBD>սӿ<D5BD>*/
|
|
||||||
void (*error)(void); /* ATִ<54><D6B4><EFBFBD>쳣<EFBFBD>¼<EFBFBD>*/
|
|
||||||
utc_item_t *utc_tbl; /* urc <20><>*/
|
|
||||||
unsigned char *urc_buf; /* urc<72><63><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
unsigned char *recv_buf; /* <20><><EFBFBD>ݻ<EFBFBD><DDBB><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
unsigned short urc_tbl_count; /* urc<72><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
unsigned short urc_bufsize; /* urc<72><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С*/
|
|
||||||
unsigned short recv_bufsize; /* <20><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С*/
|
|
||||||
}at_adapter_t;
|
|
||||||
|
|
||||||
/*AT<41><54>ҵ<EFBFBD><D2B5><EFBFBD>л<EFBFBD><D0BB><EFBFBD>*/
|
|
||||||
typedef struct {
|
|
||||||
int i,j,state;
|
|
||||||
void *params;
|
|
||||||
void (*reset_timer)(struct at_obj *at);
|
|
||||||
bool (*is_timeout)(struct at_obj *at, unsigned int ms); /*ʱ<><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>*/
|
|
||||||
void (*printf)(struct at_obj *at, const char *fmt, ...);
|
|
||||||
char * (*find)(struct at_obj *at, const char *expect);
|
|
||||||
char * (*recvbuf)(struct at_obj *at); /* ָ<><D6B8><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
unsigned int(*recvlen)(struct at_obj *at); /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܳ<EFBFBD><DCB3><EFBFBD>*/
|
|
||||||
void (*recvclr)(struct at_obj *at); /* <20><><EFBFBD>ս<EFBFBD><D5BD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
bool (*abort)(struct at_obj *at); /* <20><>ִֹ<D6B9><D6B4>*/
|
|
||||||
}at_env_t;
|
|
||||||
|
|
||||||
/*AT<41><54><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6>*/
|
|
||||||
typedef enum {
|
|
||||||
AT_RET_OK = 0, /* ִ<>гɹ<D0B3>*/
|
|
||||||
AT_RET_ERROR, /* ִ<>д<EFBFBD><D0B4><EFBFBD>*/
|
|
||||||
AT_RET_TIMEOUT, /* <20><>Ӧ<EFBFBD><D3A6>ʱ*/
|
|
||||||
AT_RET_ABORT, /* ǿ<><C7BF><EFBFBD><EFBFBD>ֹ*/
|
|
||||||
}at_return;
|
|
||||||
|
|
||||||
/*AT<41><54>Ӧ */
|
|
||||||
typedef struct {
|
|
||||||
void *param;
|
|
||||||
char *recvbuf; /* <20><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
unsigned short recvcnt; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݳ<EFBFBD><DDB3><EFBFBD>*/
|
|
||||||
at_return ret; /* ATִ<54>н<EFBFBD><D0BD><EFBFBD>*/
|
|
||||||
}at_response_t;
|
|
||||||
|
|
||||||
typedef void (*at_callbatk_t)(at_response_t *r); /* AT ִ<>лص<D0BB>*/
|
|
||||||
|
|
||||||
/*AT״̬ (<28><>ǰ<EFBFBD>汾δ<E6B1BE><CEB4>) ------------------------------------------------------*/
|
|
||||||
typedef enum {
|
|
||||||
AT_STATE_IDLE, /* <20><><EFBFBD><EFBFBD>״̬*/
|
|
||||||
AT_STATE_WAIT, /* <20>ȴ<EFBFBD>ִ<EFBFBD><D6B4>*/
|
|
||||||
AT_STATE_EXEC, /* <20><><EFBFBD><EFBFBD>ִ<EFBFBD><D6B4>*/
|
|
||||||
}at_work_state;
|
|
||||||
|
|
||||||
/*AT<41><54>ҵ<EFBFBD><D2B5>*/
|
|
||||||
typedef struct {
|
|
||||||
unsigned int state : 3;
|
|
||||||
unsigned int type : 3; /* <20><>ҵ<EFBFBD><D2B5><EFBFBD><EFBFBD>*/
|
|
||||||
unsigned int abort : 1;
|
|
||||||
void *param; /* ͨ<>ò<EFBFBD><C3B2><EFBFBD>*/
|
|
||||||
void *info; /* ͨ<><CDA8><EFBFBD><EFBFBD>Ϣָ<CFA2><D6B8>*/
|
|
||||||
struct list_head node; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
}at_item_t;
|
|
||||||
|
|
||||||
/*AT<41><54><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ------------------------------------------------------------------*/
|
|
||||||
typedef struct at_obj{
|
|
||||||
at_adapter_t adap;
|
|
||||||
at_env_t env; /* <20><>ҵ<EFBFBD><D2B5><EFBFBD>л<EFBFBD><D0BB><EFBFBD>*/
|
|
||||||
at_item_t items[10]; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>10<31><30><EFBFBD><EFBFBD>ҵ*/
|
|
||||||
at_item_t *cursor; /* <20><>ǰ<EFBFBD><C7B0>ҵ<EFBFBD><D2B5>*/
|
|
||||||
struct list_head ls_ready, ls_idle; /* <20><><EFBFBD><EFBFBD>,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ<EFBFBD><D2B5>*/
|
|
||||||
unsigned int timer;
|
|
||||||
unsigned int urc_timer; /* urc<72><63><EFBFBD>ռ<EFBFBD>ʱ<EFBFBD><CAB1>*/
|
|
||||||
at_return ret;
|
|
||||||
//urc<72><63><EFBFBD>ռ<EFBFBD><D5BC><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD>ռ<EFBFBD><D5BC><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
unsigned short urc_cnt, recv_cnt;
|
|
||||||
unsigned char suspend: 1;
|
|
||||||
}at_obj_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
void (*sender)(at_env_t *e); /*<2A>Զ<EFBFBD><D4B6>巢<EFBFBD><E5B7A2><EFBFBD><EFBFBD> */
|
|
||||||
const char *matcher; /*<2A><><EFBFBD><EFBFBD>ƥ<EFBFBD>䴮 */
|
|
||||||
at_callbatk_t cb; /*<2A><>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD> */
|
|
||||||
unsigned char retry; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><D4B4><EFBFBD> */
|
|
||||||
unsigned short timeout; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱʱ<CAB1><CAB1> */
|
|
||||||
}at_cmd_t;
|
|
||||||
|
|
||||||
void at_obj_init(at_obj_t *at, const at_adapter_t *);
|
|
||||||
|
|
||||||
bool at_send_singlline(at_obj_t *at, at_callbatk_t cb, const char *singlline);
|
|
||||||
|
|
||||||
bool at_send_multiline(at_obj_t *at, at_callbatk_t cb, const char **multiline);
|
|
||||||
|
|
||||||
bool at_do_cmd(at_obj_t *at, void *params, const at_cmd_t *cmd);
|
|
||||||
|
|
||||||
bool at_do_work(at_obj_t *at, int (*work)(at_env_t *e), void *params);
|
|
||||||
|
|
||||||
void at_item_abort(at_item_t *it); /*<2A><>ֹ<EFBFBD><D6B9>ǰ<EFBFBD><C7B0>ҵ*/
|
|
||||||
|
|
||||||
bool at_obj_busy(at_obj_t *at); /*æ<>ж<EFBFBD>*/
|
|
||||||
|
|
||||||
void at_suspend(at_obj_t *at);
|
|
||||||
|
|
||||||
void at_resume(at_obj_t *at);
|
|
||||||
|
|
||||||
void at_poll_task(at_obj_t *at);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,705 +0,0 @@
|
|||||||
#ifndef _LINUX_LIST_H
|
|
||||||
#define _LINUX_LIST_H
|
|
||||||
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#if !defined(__GNUC__)
|
|
||||||
#define typeof (struct list_head)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#undef offsetof
|
|
||||||
#define offsetof(TYPE, MEMBER) ((size_t) &((TYPE *)0)->MEMBER)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* container_of - cast a member of a structure out to the containing structure
|
|
||||||
* @ptr: the pointer to the member.
|
|
||||||
* @type: the type of the container struct this is embedded in.
|
|
||||||
* @member: the name of the member within the struct.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
#if !defined(__GNUC__)
|
|
||||||
#define container_of(ptr, type, member) ( \
|
|
||||||
(type *)( (char *)(ptr) - offsetof(type,member) ))
|
|
||||||
#else
|
|
||||||
#define container_of(ptr, type, member) ({ \
|
|
||||||
const typeof( ((type *)0)->member ) *__mptr = (ptr); \
|
|
||||||
(type *)( (char *)__mptr - offsetof(type,member) );})
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/* copy from <linux/poison.h>, */
|
|
||||||
/*
|
|
||||||
* used to verify that nobody uses non-initialized list entries.
|
|
||||||
*/
|
|
||||||
#define LIST_POISON1 ((void *) 0x0)
|
|
||||||
#define LIST_POISON2 ((void *) 0x0)
|
|
||||||
|
|
||||||
|
|
||||||
#ifndef ARCH_HAS_PREFETCH
|
|
||||||
#define ARCH_HAS_PREFETCH
|
|
||||||
static inline void prefetch(const void *x) {;}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Simple doubly linked list implementation.
|
|
||||||
*
|
|
||||||
* Some of the internal functions ("__xxx") are useful when
|
|
||||||
* manipulating whole lists rather than single entries, as
|
|
||||||
* sometimes we already know the next/prev entries and we can
|
|
||||||
* generate better code by using them directly rather than
|
|
||||||
* using the generic single-entry routines.
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct list_head {
|
|
||||||
struct list_head *next, *prev;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define LIST_HEAD_INIT(name) { &(name), &(name) }
|
|
||||||
|
|
||||||
#define LIST_HEAD(name) \
|
|
||||||
struct list_head name = LIST_HEAD_INIT(name)
|
|
||||||
|
|
||||||
static inline void INIT_LIST_HEAD(struct list_head *list)
|
|
||||||
{
|
|
||||||
list->next = list;
|
|
||||||
list->prev = list;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Insert a new entry between two known consecutive entries.
|
|
||||||
*
|
|
||||||
* This is only for internal list manipulation where we know
|
|
||||||
* the prev/next entries already!
|
|
||||||
*/
|
|
||||||
static inline void __list_add(struct list_head *new,
|
|
||||||
struct list_head *prev,
|
|
||||||
struct list_head *next)
|
|
||||||
{
|
|
||||||
next->prev = new;
|
|
||||||
new->next = next;
|
|
||||||
new->prev = prev;
|
|
||||||
prev->next = new;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_add - add a new entry
|
|
||||||
* @new: new entry to be added
|
|
||||||
* @head: list head to add it after
|
|
||||||
*
|
|
||||||
* Insert a new entry after the specified head.
|
|
||||||
* This is good for implementing stacks.
|
|
||||||
*/
|
|
||||||
static inline void list_add(struct list_head *new, struct list_head *head)
|
|
||||||
{
|
|
||||||
__list_add(new, head, head->next);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_add_tail - add a new entry
|
|
||||||
* @new: new entry to be added
|
|
||||||
* @head: list head to add it before
|
|
||||||
*
|
|
||||||
* Insert a new entry before the specified head.
|
|
||||||
* This is useful for implementing queues.
|
|
||||||
*/
|
|
||||||
static inline void list_add_tail(struct list_head *new, struct list_head *head)
|
|
||||||
{
|
|
||||||
__list_add(new, head->prev, head);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Delete a list entry by making the prev/next entries
|
|
||||||
* point to each other.
|
|
||||||
*
|
|
||||||
* This is only for internal list manipulation where we know
|
|
||||||
* the prev/next entries already!
|
|
||||||
*/
|
|
||||||
static inline void __list_del(struct list_head *prev, struct list_head *next)
|
|
||||||
{
|
|
||||||
next->prev = prev;
|
|
||||||
prev->next = next;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_del - deletes entry from list.
|
|
||||||
* @entry: the element to delete from the list.
|
|
||||||
* Note: list_empty() on entry does not return true after this, the entry is
|
|
||||||
* in an undefined state.
|
|
||||||
*/
|
|
||||||
static inline void list_del(struct list_head *entry)
|
|
||||||
{
|
|
||||||
__list_del(entry->prev, entry->next);
|
|
||||||
entry->next = LIST_POISON1;
|
|
||||||
entry->prev = LIST_POISON2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_replace - replace old entry by new one
|
|
||||||
* @old : the element to be replaced
|
|
||||||
* @new : the new element to insert
|
|
||||||
*
|
|
||||||
* If @old was empty, it will be overwritten.
|
|
||||||
*/
|
|
||||||
static inline void list_replace(struct list_head *old,
|
|
||||||
struct list_head *new)
|
|
||||||
{
|
|
||||||
new->next = old->next;
|
|
||||||
new->next->prev = new;
|
|
||||||
new->prev = old->prev;
|
|
||||||
new->prev->next = new;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void list_replace_init(struct list_head *old,
|
|
||||||
struct list_head *new)
|
|
||||||
{
|
|
||||||
list_replace(old, new);
|
|
||||||
INIT_LIST_HEAD(old);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_del_init - deletes entry from list and reinitialize it.
|
|
||||||
* @entry: the element to delete from the list.
|
|
||||||
*/
|
|
||||||
static inline void list_del_init(struct list_head *entry)
|
|
||||||
{
|
|
||||||
__list_del(entry->prev, entry->next);
|
|
||||||
INIT_LIST_HEAD(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_move - delete from one list and add as another's head
|
|
||||||
* @list: the entry to move
|
|
||||||
* @head: the head that will precede our entry
|
|
||||||
*/
|
|
||||||
static inline void list_move(struct list_head *list, struct list_head *head)
|
|
||||||
{
|
|
||||||
__list_del(list->prev, list->next);
|
|
||||||
list_add(list, head);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_move_tail - delete from one list and add as another's tail
|
|
||||||
* @list: the entry to move
|
|
||||||
* @head: the head that will follow our entry
|
|
||||||
*/
|
|
||||||
static inline void list_move_tail(struct list_head *list,
|
|
||||||
struct list_head *head)
|
|
||||||
{
|
|
||||||
__list_del(list->prev, list->next);
|
|
||||||
list_add_tail(list, head);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_is_last - tests whether @list is the last entry in list @head
|
|
||||||
* @list: the entry to test
|
|
||||||
* @head: the head of the list
|
|
||||||
*/
|
|
||||||
static inline int list_is_last(const struct list_head *list,
|
|
||||||
const struct list_head *head)
|
|
||||||
{
|
|
||||||
return list->next == head;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_empty - tests whether a list is empty
|
|
||||||
* @head: the list to test.
|
|
||||||
*/
|
|
||||||
static inline int list_empty(const struct list_head *head)
|
|
||||||
{
|
|
||||||
return head->next == head;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_empty_careful - tests whether a list is empty and not being modified
|
|
||||||
* @head: the list to test
|
|
||||||
*
|
|
||||||
* Description:
|
|
||||||
* tests whether a list is empty _and_ checks that no other CPU might be
|
|
||||||
* in the process of modifying either member (next or prev)
|
|
||||||
*
|
|
||||||
* NOTE: using list_empty_careful() without synchronization
|
|
||||||
* can only be safe if the only activity that can happen
|
|
||||||
* to the list entry is list_del_init(). Eg. it cannot be used
|
|
||||||
* if another CPU could re-list_add() it.
|
|
||||||
*/
|
|
||||||
static inline int list_empty_careful(const struct list_head *head)
|
|
||||||
{
|
|
||||||
struct list_head *next = head->next;
|
|
||||||
return (next == head) && (next == head->prev);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_is_singular - tests whether a list has just one entry.
|
|
||||||
* @head: the list to test.
|
|
||||||
*/
|
|
||||||
static inline int list_is_singular(const struct list_head *head)
|
|
||||||
{
|
|
||||||
return !list_empty(head) && (head->next == head->prev);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __list_cut_position(struct list_head *list,
|
|
||||||
struct list_head *head, struct list_head *entry)
|
|
||||||
{
|
|
||||||
struct list_head *new_first = entry->next;
|
|
||||||
list->next = head->next;
|
|
||||||
list->next->prev = list;
|
|
||||||
list->prev = entry;
|
|
||||||
entry->next = list;
|
|
||||||
head->next = new_first;
|
|
||||||
new_first->prev = head;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_cut_position - cut a list into two
|
|
||||||
* @list: a new list to add all removed entries
|
|
||||||
* @head: a list with entries
|
|
||||||
* @entry: an entry within head, could be the head itself
|
|
||||||
* and if so we won't cut the list
|
|
||||||
*
|
|
||||||
* This helper moves the initial part of @head, up to and
|
|
||||||
* including @entry, from @head to @list. You should
|
|
||||||
* pass on @entry an element you know is on @head. @list
|
|
||||||
* should be an empty list or a list you do not care about
|
|
||||||
* losing its data.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
static inline void list_cut_position(struct list_head *list,
|
|
||||||
struct list_head *head, struct list_head *entry)
|
|
||||||
{
|
|
||||||
if (list_empty(head))
|
|
||||||
return;
|
|
||||||
if (list_is_singular(head) &&
|
|
||||||
(head->next != entry && head != entry))
|
|
||||||
return;
|
|
||||||
if (entry == head)
|
|
||||||
INIT_LIST_HEAD(list);
|
|
||||||
else
|
|
||||||
__list_cut_position(list, head, entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __list_splice(const struct list_head *list,
|
|
||||||
struct list_head *prev,
|
|
||||||
struct list_head *next)
|
|
||||||
{
|
|
||||||
struct list_head *first = list->next;
|
|
||||||
struct list_head *last = list->prev;
|
|
||||||
|
|
||||||
first->prev = prev;
|
|
||||||
prev->next = first;
|
|
||||||
|
|
||||||
last->next = next;
|
|
||||||
next->prev = last;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_splice - join two lists, this is designed for stacks
|
|
||||||
* @list: the new list to add.
|
|
||||||
* @head: the place to add it in the first list.
|
|
||||||
*/
|
|
||||||
static inline void list_splice(const struct list_head *list,
|
|
||||||
struct list_head *head)
|
|
||||||
{
|
|
||||||
if (!list_empty(list))
|
|
||||||
__list_splice(list, head, head->next);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_splice_tail - join two lists, each list being a queue
|
|
||||||
* @list: the new list to add.
|
|
||||||
* @head: the place to add it in the first list.
|
|
||||||
*/
|
|
||||||
static inline void list_splice_tail(struct list_head *list,
|
|
||||||
struct list_head *head)
|
|
||||||
{
|
|
||||||
if (!list_empty(list))
|
|
||||||
__list_splice(list, head->prev, head);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_splice_init - join two lists and reinitialise the emptied list.
|
|
||||||
* @list: the new list to add.
|
|
||||||
* @head: the place to add it in the first list.
|
|
||||||
*
|
|
||||||
* The list at @list is reinitialised
|
|
||||||
*/
|
|
||||||
static inline void list_splice_init(struct list_head *list,
|
|
||||||
struct list_head *head)
|
|
||||||
{
|
|
||||||
if (!list_empty(list)) {
|
|
||||||
__list_splice(list, head, head->next);
|
|
||||||
INIT_LIST_HEAD(list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_splice_tail_init - join two lists and reinitialise the emptied list
|
|
||||||
* @list: the new list to add.
|
|
||||||
* @head: the place to add it in the first list.
|
|
||||||
*
|
|
||||||
* Each of the lists is a queue.
|
|
||||||
* The list at @list is reinitialised
|
|
||||||
*/
|
|
||||||
static inline void list_splice_tail_init(struct list_head *list,
|
|
||||||
struct list_head *head)
|
|
||||||
{
|
|
||||||
if (!list_empty(list)) {
|
|
||||||
__list_splice(list, head->prev, head);
|
|
||||||
INIT_LIST_HEAD(list);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_entry - get the struct for this entry
|
|
||||||
* @ptr: the &struct list_head pointer.
|
|
||||||
* @type: the type of the struct this is embedded in.
|
|
||||||
* @member: the name of the list_struct within the struct.
|
|
||||||
*/
|
|
||||||
#define list_entry(ptr, type, member) \
|
|
||||||
container_of(ptr, type, member)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_first_entry - get the first element from a list
|
|
||||||
* @ptr: the list head to take the element from.
|
|
||||||
* @type: the type of the struct this is embedded in.
|
|
||||||
* @member: the name of the list_struct within the struct.
|
|
||||||
*
|
|
||||||
* Note, that list is expected to be not empty.
|
|
||||||
*/
|
|
||||||
#define list_first_entry(ptr, type, member) \
|
|
||||||
list_entry((ptr)->next, type, member)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each - iterate over a list
|
|
||||||
* @pos: the &struct list_head to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
*/
|
|
||||||
#define list_for_each(pos, head) \
|
|
||||||
for (pos = (head)->next; prefetch(pos->next), pos != (head); \
|
|
||||||
pos = pos->next)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* __list_for_each - iterate over a list
|
|
||||||
* @pos: the &struct list_head to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
*
|
|
||||||
* This variant differs from list_for_each() in that it's the
|
|
||||||
* simplest possible list iteration code, no prefetching is done.
|
|
||||||
* Use this for code that knows the list to be very short (empty
|
|
||||||
* or 1 entry) most of the time.
|
|
||||||
*/
|
|
||||||
#define __list_for_each(pos, head) \
|
|
||||||
for (pos = (head)->next; pos != (head); pos = pos->next)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_prev - iterate over a list backwards
|
|
||||||
* @pos: the &struct list_head to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
*/
|
|
||||||
#define list_for_each_prev(pos, head) \
|
|
||||||
for (pos = (head)->prev; prefetch(pos->prev), pos != (head); \
|
|
||||||
pos = pos->prev)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_safe - iterate over a list safe against removal of list entry
|
|
||||||
* @pos: the &struct list_head to use as a loop cursor.
|
|
||||||
* @n: another &struct list_head to use as temporary storage
|
|
||||||
* @head: the head for your list.
|
|
||||||
*/
|
|
||||||
#define list_for_each_safe(pos, n, head) \
|
|
||||||
for (pos = (head)->next, n = pos->next; pos != (head); \
|
|
||||||
pos = n, n = pos->next)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_prev_safe - iterate over a list backwards safe against removal of list entry
|
|
||||||
* @pos: the &struct list_head to use as a loop cursor.
|
|
||||||
* @n: another &struct list_head to use as temporary storage
|
|
||||||
* @head: the head for your list.
|
|
||||||
*/
|
|
||||||
#define list_for_each_prev_safe(pos, n, head) \
|
|
||||||
for (pos = (head)->prev, n = pos->prev; \
|
|
||||||
prefetch(pos->prev), pos != (head); \
|
|
||||||
pos = n, n = pos->prev)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry - iterate over list of given type
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_struct within the struct.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry(pos, head, member) \
|
|
||||||
for (pos = list_entry((head)->next, typeof(*pos), member); \
|
|
||||||
prefetch(pos->member.next), &pos->member != (head); \
|
|
||||||
pos = list_entry(pos->member.next, typeof(*pos), member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_reverse - iterate backwards over list of given type.
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_struct within the struct.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_reverse(pos, head, member) \
|
|
||||||
for (pos = list_entry((head)->prev, typeof(*pos), member); \
|
|
||||||
prefetch(pos->member.prev), &pos->member != (head); \
|
|
||||||
pos = list_entry(pos->member.prev, typeof(*pos), member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_prepare_entry - prepare a pos entry for use in list_for_each_entry_continue()
|
|
||||||
* @pos: the type * to use as a start point
|
|
||||||
* @head: the head of the list
|
|
||||||
* @member: the name of the list_struct within the struct.
|
|
||||||
*
|
|
||||||
* Prepares a pos entry for use as a start point in list_for_each_entry_continue().
|
|
||||||
*/
|
|
||||||
#define list_prepare_entry(pos, head, member) \
|
|
||||||
((pos) ? : list_entry(head, typeof(*pos), member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_continue - continue iteration over list of given type
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_struct within the struct.
|
|
||||||
*
|
|
||||||
* Continue to iterate over list of given type, continuing after
|
|
||||||
* the current position.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_continue(pos, head, member) \
|
|
||||||
for (pos = list_entry(pos->member.next, typeof(*pos), member); \
|
|
||||||
prefetch(pos->member.next), &pos->member != (head); \
|
|
||||||
pos = list_entry(pos->member.next, typeof(*pos), member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_continue_reverse - iterate backwards from the given point
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_struct within the struct.
|
|
||||||
*
|
|
||||||
* Start to iterate over list of given type backwards, continuing after
|
|
||||||
* the current position.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_continue_reverse(pos, head, member) \
|
|
||||||
for (pos = list_entry(pos->member.prev, typeof(*pos), member); \
|
|
||||||
prefetch(pos->member.prev), &pos->member != (head); \
|
|
||||||
pos = list_entry(pos->member.prev, typeof(*pos), member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_from - iterate over list of given type from the current point
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_struct within the struct.
|
|
||||||
*
|
|
||||||
* Iterate over list of given type, continuing from current position.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_from(pos, head, member) \
|
|
||||||
for (; prefetch(pos->member.next), &pos->member != (head); \
|
|
||||||
pos = list_entry(pos->member.next, typeof(*pos), member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @n: another type * to use as temporary storage
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_struct within the struct.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_safe(pos, n, head, member) \
|
|
||||||
for (pos = list_entry((head)->next, typeof(*pos), member), \
|
|
||||||
n = list_entry(pos->member.next, typeof(*pos), member); \
|
|
||||||
&pos->member != (head); \
|
|
||||||
pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_safe_continue
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @n: another type * to use as temporary storage
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_struct within the struct.
|
|
||||||
*
|
|
||||||
* Iterate over list of given type, continuing after current point,
|
|
||||||
* safe against removal of list entry.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_safe_continue(pos, n, head, member) \
|
|
||||||
for (pos = list_entry(pos->member.next, typeof(*pos), member), \
|
|
||||||
n = list_entry(pos->member.next, typeof(*pos), member); \
|
|
||||||
&pos->member != (head); \
|
|
||||||
pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_safe_from
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @n: another type * to use as temporary storage
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_struct within the struct.
|
|
||||||
*
|
|
||||||
* Iterate over list of given type from current point, safe against
|
|
||||||
* removal of list entry.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_safe_from(pos, n, head, member) \
|
|
||||||
for (n = list_entry(pos->member.next, typeof(*pos), member); \
|
|
||||||
&pos->member != (head); \
|
|
||||||
pos = n, n = list_entry(n->member.next, typeof(*n), member))
|
|
||||||
|
|
||||||
/**
|
|
||||||
* list_for_each_entry_safe_reverse
|
|
||||||
* @pos: the type * to use as a loop cursor.
|
|
||||||
* @n: another type * to use as temporary storage
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the list_struct within the struct.
|
|
||||||
*
|
|
||||||
* Iterate backwards over list of given type, safe against removal
|
|
||||||
* of list entry.
|
|
||||||
*/
|
|
||||||
#define list_for_each_entry_safe_reverse(pos, n, head, member) \
|
|
||||||
for (pos = list_entry((head)->prev, typeof(*pos), member), \
|
|
||||||
n = list_entry(pos->member.prev, typeof(*pos), member); \
|
|
||||||
&pos->member != (head); \
|
|
||||||
pos = n, n = list_entry(n->member.prev, typeof(*n), member))
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Double linked lists with a single pointer list head.
|
|
||||||
* Mostly useful for hash tables where the two pointer list head is
|
|
||||||
* too wasteful.
|
|
||||||
* You lose the ability to access the tail in O(1).
|
|
||||||
*/
|
|
||||||
|
|
||||||
struct hlist_head {
|
|
||||||
struct hlist_node *first;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct hlist_node {
|
|
||||||
struct hlist_node *next, **pprev;
|
|
||||||
};
|
|
||||||
|
|
||||||
#define HLIST_HEAD_INIT { .first = NULL }
|
|
||||||
#define HLIST_HEAD(name) struct hlist_head name = { .first = NULL }
|
|
||||||
#define INIT_HLIST_HEAD(ptr) ((ptr)->first = NULL)
|
|
||||||
static inline void INIT_HLIST_NODE(struct hlist_node *h)
|
|
||||||
{
|
|
||||||
h->next = NULL;
|
|
||||||
h->pprev = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int hlist_unhashed(const struct hlist_node *h)
|
|
||||||
{
|
|
||||||
return !h->pprev;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline int hlist_empty(const struct hlist_head *h)
|
|
||||||
{
|
|
||||||
return !h->first;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void __hlist_del(struct hlist_node *n)
|
|
||||||
{
|
|
||||||
struct hlist_node *next = n->next;
|
|
||||||
struct hlist_node **pprev = n->pprev;
|
|
||||||
*pprev = next;
|
|
||||||
if (next)
|
|
||||||
next->pprev = pprev;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void hlist_del(struct hlist_node *n)
|
|
||||||
{
|
|
||||||
__hlist_del(n);
|
|
||||||
n->next = LIST_POISON1;
|
|
||||||
n->pprev = LIST_POISON2;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void hlist_del_init(struct hlist_node *n)
|
|
||||||
{
|
|
||||||
if (!hlist_unhashed(n)) {
|
|
||||||
__hlist_del(n);
|
|
||||||
INIT_HLIST_NODE(n);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void hlist_add_head(struct hlist_node *n, struct hlist_head *h)
|
|
||||||
{
|
|
||||||
struct hlist_node *first = h->first;
|
|
||||||
n->next = first;
|
|
||||||
if (first)
|
|
||||||
first->pprev = &n->next;
|
|
||||||
h->first = n;
|
|
||||||
n->pprev = &h->first;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* next must be != NULL */
|
|
||||||
static inline void hlist_add_before(struct hlist_node *n,
|
|
||||||
struct hlist_node *next)
|
|
||||||
{
|
|
||||||
n->pprev = next->pprev;
|
|
||||||
n->next = next;
|
|
||||||
next->pprev = &n->next;
|
|
||||||
*(n->pprev) = n;
|
|
||||||
}
|
|
||||||
|
|
||||||
static inline void hlist_add_after(struct hlist_node *n,
|
|
||||||
struct hlist_node *next)
|
|
||||||
{
|
|
||||||
next->next = n->next;
|
|
||||||
n->next = next;
|
|
||||||
next->pprev = &n->next;
|
|
||||||
|
|
||||||
if(next->next)
|
|
||||||
next->next->pprev = &next->next;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define hlist_entry(ptr, type, member) container_of(ptr,type,member)
|
|
||||||
|
|
||||||
#define hlist_for_each(pos, head) \
|
|
||||||
for (pos = (head)->first; pos && ({ prefetch(pos->next); 1; }); \
|
|
||||||
pos = pos->next)
|
|
||||||
|
|
||||||
#define hlist_for_each_safe(pos, n, head) \
|
|
||||||
for (pos = (head)->first; pos && ({ n = pos->next; 1; }); \
|
|
||||||
pos = n)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_for_each_entry - iterate over list of given type
|
|
||||||
* @tpos: the type * to use as a loop cursor.
|
|
||||||
* @pos: the &struct hlist_node to use as a loop cursor.
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the hlist_node within the struct.
|
|
||||||
*/
|
|
||||||
#define hlist_for_each_entry(tpos, pos, head, member) \
|
|
||||||
for (pos = (head)->first; \
|
|
||||||
pos && ({ prefetch(pos->next); 1;}) && \
|
|
||||||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
|
|
||||||
pos = pos->next)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_for_each_entry_continue - iterate over a hlist continuing after current point
|
|
||||||
* @tpos: the type * to use as a loop cursor.
|
|
||||||
* @pos: the &struct hlist_node to use as a loop cursor.
|
|
||||||
* @member: the name of the hlist_node within the struct.
|
|
||||||
*/
|
|
||||||
#define hlist_for_each_entry_continue(tpos, pos, member) \
|
|
||||||
for (pos = (pos)->next; \
|
|
||||||
pos && ({ prefetch(pos->next); 1;}) && \
|
|
||||||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
|
|
||||||
pos = pos->next)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_for_each_entry_from - iterate over a hlist continuing from current point
|
|
||||||
* @tpos: the type * to use as a loop cursor.
|
|
||||||
* @pos: the &struct hlist_node to use as a loop cursor.
|
|
||||||
* @member: the name of the hlist_node within the struct.
|
|
||||||
*/
|
|
||||||
#define hlist_for_each_entry_from(tpos, pos, member) \
|
|
||||||
for (; pos && ({ prefetch(pos->next); 1;}) && \
|
|
||||||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
|
|
||||||
pos = pos->next)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* hlist_for_each_entry_safe - iterate over list of given type safe against removal of list entry
|
|
||||||
* @tpos: the type * to use as a loop cursor.
|
|
||||||
* @pos: the &struct hlist_node to use as a loop cursor.
|
|
||||||
* @n: another &struct hlist_node to use as temporary storage
|
|
||||||
* @head: the head for your list.
|
|
||||||
* @member: the name of the hlist_node within the struct.
|
|
||||||
*/
|
|
||||||
#define hlist_for_each_entry_safe(tpos, pos, n, head, member) \
|
|
||||||
for (pos = (head)->first; \
|
|
||||||
pos && ({ n = pos->next; 1; }) && \
|
|
||||||
({ tpos = hlist_entry(pos, typeof(*tpos), member); 1;}); \
|
|
||||||
pos = n)
|
|
||||||
|
|
||||||
#endif
|
|
201
Demo/LICENSE
@ -1,201 +0,0 @@
|
|||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [2015~2020] [master_roger@sina.com]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
@ -1,77 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*
|
|
||||||
* Copyright (c) 2015-2020, <morro_luo@163.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* Change Logs:
|
|
||||||
* Date Author Notes
|
|
||||||
* 2015-06-09 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*
|
|
||||||
* 2017-07-04 Morro <EFBFBD>Ż<EFBFBD><EFBFBD>ֶηָ<EFBFBD><EFBFBD>
|
|
||||||
*
|
|
||||||
* 2020-07-05 Morro ʹ<EFBFBD><EFBFBD>cli_obj_t<EFBFBD><EFBFBD><EFBFBD><EFBFBD>, ֧<EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
******************************************************************************/
|
|
||||||
#ifndef _CMDLINE_H_
|
|
||||||
#define _CMDLINE_H_
|
|
||||||
|
|
||||||
#include "comdef.h"
|
|
||||||
|
|
||||||
#define CLI_MAX_CMD_LEN 64 /*<2A><><EFBFBD><EFBFBD><EFBFBD>г<EFBFBD><D0B3><EFBFBD>*/
|
|
||||||
#define CLI_MAX_ARGS 16 /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
#define CLI_MAX_CMDS 32 /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
|
|
||||||
struct cli_obj;
|
|
||||||
|
|
||||||
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EEB6A8>*/
|
|
||||||
typedef struct {
|
|
||||||
char *name; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
/*<2A><><EFBFBD><EFBFBD><EEB4A6><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
int (*handler)(struct cli_obj *o, int argc, char *argv[]);
|
|
||||||
const char *brief; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
}cmd_item_t;
|
|
||||||
|
|
||||||
#define __cmd_register(name,handler,brief)\
|
|
||||||
USED ANONY_TYPE(const cmd_item_t,__cli_cmd_##handler)\
|
|
||||||
SECTION("cli.cmd.1") = {name, handler, brief}
|
|
||||||
|
|
||||||
/*******************************************************************************
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ע<EFBFBD><EFBFBD>
|
|
||||||
* @params name - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @params handler - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD>:int (*handler)(struct cli_obj *s, int argc, char *argv[]);
|
|
||||||
* @params brief - ʹ<EFBFBD><EFBFBD>˵<EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
#define cmd_register(name,handler,brief)\
|
|
||||||
__cmd_register(name,handler,brief)
|
|
||||||
|
|
||||||
/*cli <20>ӿڶ<D3BF><DAB6><EFBFBD> -------------------------------------------------------------*/
|
|
||||||
typedef struct {
|
|
||||||
unsigned int (*write)(const void *buf, unsigned int len);
|
|
||||||
unsigned int (*read) (void *buf, unsigned int len);
|
|
||||||
}cli_port_t;
|
|
||||||
|
|
||||||
/*<2A><><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD><D0B6><EFBFBD>*/
|
|
||||||
typedef struct cli_obj {
|
|
||||||
unsigned int (*write)(const void *buf, unsigned int len);
|
|
||||||
unsigned int (*read) (void *buf, unsigned int len);
|
|
||||||
void (*print)(struct cli_obj *this, const char *fmt, ...);
|
|
||||||
char recvbuf[CLI_MAX_CMD_LEN + 1]; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
unsigned short recvcnt; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ճ<EFBFBD><D5B3><EFBFBD>*/
|
|
||||||
unsigned enable : 1;
|
|
||||||
}cli_obj_t;
|
|
||||||
|
|
||||||
void cli_init(cli_obj_t *obj, const cli_port_t *p);
|
|
||||||
|
|
||||||
void cli_enable(cli_obj_t *obj);
|
|
||||||
|
|
||||||
void cli_disable (cli_obj_t *obj);
|
|
||||||
|
|
||||||
void cli_exec_cmd(cli_obj_t *obj, const char *cmd);
|
|
||||||
|
|
||||||
void cli_process(cli_obj_t *obj);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#endif /* __CMDLINE_H */
|
|
@ -1,30 +0,0 @@
|
|||||||
del *.bak /s
|
|
||||||
del *.ddk /s
|
|
||||||
del *.edk /s
|
|
||||||
del *.lst /s
|
|
||||||
del *.lnp /s
|
|
||||||
del *.mpf /s
|
|
||||||
del *.mpj /s
|
|
||||||
del *.obj /s
|
|
||||||
del *.omf /s
|
|
||||||
::del *.opt /s ::<3A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɾ<EFBFBD><C9BE>JLINK<4E><4B><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
del *.plg /s
|
|
||||||
del *.rpt /s
|
|
||||||
del *.tmp /s
|
|
||||||
del *.__i /s
|
|
||||||
del *.crf /s
|
|
||||||
del *.o /s
|
|
||||||
del *.d /s
|
|
||||||
del *.axf /s
|
|
||||||
del *.tra /s
|
|
||||||
del *.dep /s
|
|
||||||
del JLinkLog.txt /s
|
|
||||||
|
|
||||||
del *.iex /s
|
|
||||||
del *.htm /s
|
|
||||||
del *.sct /s
|
|
||||||
del *.map /s
|
|
||||||
del *.pbi /s
|
|
||||||
del *.out /s
|
|
||||||
|
|
||||||
exit
|
|
@ -1,251 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
* @brief wifi<EFBFBD><EFBFBD><EFBFBD><EFBFBD>(AT-command<EFBFBD><EFBFBD>ʾ, ʹ<EFBFBD>õ<EFBFBD>ģ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>M169WI-FI)
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020, <morro_luo@163.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* Change Logs:
|
|
||||||
* Date Author Notes
|
|
||||||
* 2021-01-20 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* 2021-03-03 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD>URCʹ<EFBFBD>ð<EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
******************************************************************************/
|
|
||||||
#include "at_chat.h"
|
|
||||||
#include "wifi_uart.h"
|
|
||||||
#include "public.h"
|
|
||||||
#include "module.h"
|
|
||||||
#include "cli.h"
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
/* Private function prototypes -----------------------------------------------*/
|
|
||||||
void wifi_open(void);
|
|
||||||
void wifi_close(void);
|
|
||||||
static void at_error(void);
|
|
||||||
void wifi_query_version(void);
|
|
||||||
void wifi_ready_handler(char *recvbuf, int size);
|
|
||||||
void wifi_connected_handler(char *recvbuf, int size);
|
|
||||||
void wifi_disconnected_handler(char *recvbuf, int size);
|
|
||||||
|
|
||||||
/* Private variables ---------------------------------------------------------*/
|
|
||||||
/*
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static at_obj_t at;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief wifi <EFBFBD><EFBFBD><EFBFBD>ݽ<EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static unsigned char wifi_recvbuf[256];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief wifi URC<EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static unsigned char wifi_urcbuf[128];
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief wifi URC<EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static const utc_item_t urc_table[] = {
|
|
||||||
"ready", wifi_ready_handler,
|
|
||||||
"WIFI CONNECTED:", wifi_connected_handler,
|
|
||||||
"WIFI DISCONNECTED", wifi_disconnected_handler,
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static const at_adapter_t at_adapter = {
|
|
||||||
.write = wifi_uart_write,
|
|
||||||
.read = wifi_uart_read,
|
|
||||||
.error = at_error,
|
|
||||||
.utc_tbl = (utc_item_t *)urc_table,
|
|
||||||
.urc_buf = wifi_urcbuf,
|
|
||||||
.recv_buf = wifi_recvbuf,
|
|
||||||
.urc_tbl_count = sizeof(urc_table) / sizeof(urc_table[0]),
|
|
||||||
.urc_bufsize = sizeof(wifi_urcbuf),
|
|
||||||
.recv_bufsize = sizeof(wifi_recvbuf)
|
|
||||||
};
|
|
||||||
|
|
||||||
/* Private functions ---------------------------------------------------------*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief wifi<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>
|
|
||||||
*/
|
|
||||||
void wifi_ready_handler(char *recvbuf, int size)
|
|
||||||
{
|
|
||||||
printf("WIFI ready...\r\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief wifi<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>
|
|
||||||
*/
|
|
||||||
static void wifi_connected_handler(char *recvbuf, int size)
|
|
||||||
{
|
|
||||||
printf("WIFI connection detected...\r\n");
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* @brief wifi<EFBFBD>Ͽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD>
|
|
||||||
*/
|
|
||||||
static void wifi_disconnected_handler(char *recvbuf, int size)
|
|
||||||
{
|
|
||||||
printf("WIFI disconnect detected...\r\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>wifi
|
|
||||||
*/
|
|
||||||
void wifi_open(void)
|
|
||||||
{
|
|
||||||
GPIO_SetBits(GPIOA, GPIO_Pin_4);
|
|
||||||
printf("wifi open\r\n");
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* @brief <EFBFBD>ر<EFBFBD>wifi
|
|
||||||
*/
|
|
||||||
void wifi_close(void)
|
|
||||||
{
|
|
||||||
GPIO_ResetBits(GPIOA, GPIO_Pin_4);
|
|
||||||
printf("wifi close\r\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief WIFI<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬<EFBFBD><EFBFBD>
|
|
||||||
* @return true - <EFBFBD>˳<EFBFBD>״̬<EFBFBD><EFBFBD>, false - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>״̬<EFBFBD><EFBFBD>,
|
|
||||||
*/
|
|
||||||
static int wifi_reset_work(at_env_t *e)
|
|
||||||
{
|
|
||||||
at_obj_t *a = (at_obj_t *)e->params;
|
|
||||||
switch (e->state) {
|
|
||||||
case 0: //<2F>ر<EFBFBD>WIFI<46><49>Դ
|
|
||||||
wifi_close();
|
|
||||||
e->reset_timer(a);
|
|
||||||
e->state++;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
if (e->is_timeout(a, 2000)) //<2F><>ʱ<EFBFBD>ȴ<EFBFBD>2s
|
|
||||||
e->state++;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
wifi_open(); //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>wifi
|
|
||||||
e->state++;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
if (e->is_timeout(a, 5000)) //<2F><>Լ<EFBFBD><D4BC>ʱ<EFBFBD>ȴ<EFBFBD>5s<35><73>wifi<66><69><EFBFBD><EFBFBD>
|
|
||||||
return true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* @brief wifi ͨ<EFBFBD><EFBFBD><EFBFBD>쳣<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static void at_error(void)
|
|
||||||
{
|
|
||||||
printf("wifi AT communication error\r\n");
|
|
||||||
//ִ<><D6B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ
|
|
||||||
at_do_work(&at, wifi_reset_work, &at);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD>ص<EFBFBD>
|
|
||||||
*/
|
|
||||||
static void at_init_callbatk(at_response_t *r)
|
|
||||||
{
|
|
||||||
if (r->ret == AT_RET_OK ) {
|
|
||||||
printf("wifi Initialization successfully...\r\n");
|
|
||||||
|
|
||||||
/* <20><>ѯ<EFBFBD>汾<EFBFBD><E6B1BE>*/
|
|
||||||
wifi_query_version();
|
|
||||||
|
|
||||||
} else
|
|
||||||
printf("wifi Initialization failure...\r\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief wifi<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static const char *wifi_init_cmds[] = {
|
|
||||||
"AT+GPIO_WR=1,1\r\n",
|
|
||||||
"AT+GPIO_WR=2,0\r\n",
|
|
||||||
"AT+GPIO_WR=3,1\r\n",
|
|
||||||
NULL
|
|
||||||
};
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief wifi<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
void wifi_init(void)
|
|
||||||
{
|
|
||||||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA , ENABLE);
|
|
||||||
gpio_conf(GPIOA, GPIO_Mode_OUT, GPIO_PuPd_NOPULL, GPIO_Pin_4);
|
|
||||||
|
|
||||||
wifi_uart_init(115200);
|
|
||||||
at_obj_init(&at, &at_adapter);
|
|
||||||
|
|
||||||
//<2F><><EFBFBD><EFBFBD>WIFI
|
|
||||||
at_do_work(&at, wifi_reset_work, &at);
|
|
||||||
|
|
||||||
//<2F><>ʼ<EFBFBD><CABC>wifi
|
|
||||||
at_send_multiline(&at, at_init_callbatk, wifi_init_cmds);
|
|
||||||
|
|
||||||
//GPIO<49><4F><EFBFBD><EFBFBD>
|
|
||||||
at_send_singlline(&at, NULL, "AT+GPIO_TEST_EN=1\r\n");
|
|
||||||
|
|
||||||
}driver_init("wifi", wifi_init);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief wifi<EFBFBD><EFBFBD><EFBFBD><EFBFBD>(10ms <EFBFBD><EFBFBD>ѯ1<EFBFBD><EFBFBD>)
|
|
||||||
*/
|
|
||||||
void wifi_task(void)
|
|
||||||
{
|
|
||||||
at_poll_task(&at);
|
|
||||||
}task_register("wifi", wifi_task, 10);
|
|
||||||
|
|
||||||
|
|
||||||
/** <20>DZ<EFBFBD>AT<41><54><EFBFBD><EFBFBD>----------------------------------------------------------------
|
|
||||||
* <EFBFBD>Բ<EFBFBD>ѯ<EFBFBD>汾<EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD>:
|
|
||||||
* -> AT+VER\r\n
|
|
||||||
* <- VERSION:M169-YH01
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
|
|
||||||
//<2F><>ʽ1, ʹ<><CAB9>at_do_cmd<6D>ӿ<EFBFBD>
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief <EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD>AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static void at_ver_sender(at_env_t *e)
|
|
||||||
{
|
|
||||||
e->printf(&at, "AT+VER\r\n");
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* @brief <EFBFBD>汾<EFBFBD><EFBFBD>ѯ<EFBFBD>ص<EFBFBD>
|
|
||||||
*/
|
|
||||||
static void query_version_callback(at_response_t *r)
|
|
||||||
{
|
|
||||||
if (r->ret == AT_RET_OK ) {
|
|
||||||
printf("wifi version info : %s\r\n", r->recvbuf);
|
|
||||||
} else
|
|
||||||
printf("wifi version query failure...\r\n");
|
|
||||||
}
|
|
||||||
|
|
||||||
/* <20><><EFBFBD><EFBFBD>AT<41><54><EFBFBD><EFBFBD>*/
|
|
||||||
static const at_cmd_t at_cmd_ver = {
|
|
||||||
at_ver_sender, //<2F>Զ<EFBFBD><D4B6><EFBFBD>AT<41><54><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
"VERSION:", //<2F><><EFBFBD><EFBFBD>ƥ<EFBFBD><C6A5>ǰ
|
|
||||||
query_version_callback, //<2F><>ѯ<EFBFBD>ص<EFBFBD>
|
|
||||||
3, 3000 //<2F><><EFBFBD>Դ<EFBFBD><D4B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱʱ<CAB1><CAB1>
|
|
||||||
};
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief ִ<EFBFBD>а汾<EFBFBD><EFBFBD>ѯ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
void wifi_query_version(void)
|
|
||||||
{
|
|
||||||
at_do_cmd(&at, NULL, &at_cmd_ver);
|
|
||||||
}
|
|
201
LICENSE
@ -1,201 +0,0 @@
|
|||||||
Apache License
|
|
||||||
Version 2.0, January 2004
|
|
||||||
http://www.apache.org/licenses/
|
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
||||||
|
|
||||||
1. Definitions.
|
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
|
||||||
the copyright owner that is granting the License.
|
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
|
||||||
other entities that control, are controlled by, or are under common
|
|
||||||
control with that entity. For the purposes of this definition,
|
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
|
||||||
direction or management of such entity, whether by contract or
|
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
|
||||||
exercising permissions granted by this License.
|
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
|
||||||
including but not limited to software source code, documentation
|
|
||||||
source, and configuration files.
|
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
|
||||||
transformation or translation of a Source form, including but
|
|
||||||
not limited to compiled object code, generated documentation,
|
|
||||||
and conversions to other media types.
|
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
|
||||||
Object form, made available under the License, as indicated by a
|
|
||||||
copyright notice that is included in or attached to the work
|
|
||||||
(an example is provided in the Appendix below).
|
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
|
||||||
form, that is based on (or derived from) the Work and for which the
|
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
|
||||||
of this License, Derivative Works shall not include works that remain
|
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
|
||||||
the Work and Derivative Works thereof.
|
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
|
||||||
the original version of the Work and any modifications or additions
|
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
|
||||||
means any form of electronic, verbal, or written communication sent
|
|
||||||
to the Licensor or its representatives, including but not limited to
|
|
||||||
communication on electronic mailing lists, source code control systems,
|
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
|
||||||
excluding communication that is conspicuously marked or otherwise
|
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
|
||||||
subsequently incorporated within the Work.
|
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
|
||||||
Work and such Derivative Works in Source or Object form.
|
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
||||||
(except as stated in this section) patent license to make, have made,
|
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
||||||
where such license applies only to those patent claims licensable
|
|
||||||
by such Contributor that are necessarily infringed by their
|
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
|
||||||
institute patent litigation against any entity (including a
|
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
|
||||||
or contributory patent infringement, then any patent licenses
|
|
||||||
granted to You under this License for that Work shall terminate
|
|
||||||
as of the date such litigation is filed.
|
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
|
||||||
modifications, and in Source or Object form, provided that You
|
|
||||||
meet the following conditions:
|
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
|
||||||
Derivative Works a copy of this License; and
|
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
|
||||||
stating that You changed the files; and
|
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
|
||||||
that You distribute, all copyright, patent, trademark, and
|
|
||||||
attribution notices from the Source form of the Work,
|
|
||||||
excluding those notices that do not pertain to any part of
|
|
||||||
the Derivative Works; and
|
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
|
||||||
distribution, then any Derivative Works that You distribute must
|
|
||||||
include a readable copy of the attribution notices contained
|
|
||||||
within such NOTICE file, excluding those notices that do not
|
|
||||||
pertain to any part of the Derivative Works, in at least one
|
|
||||||
of the following places: within a NOTICE text file distributed
|
|
||||||
as part of the Derivative Works; within the Source form or
|
|
||||||
documentation, if provided along with the Derivative Works; or,
|
|
||||||
within a display generated by the Derivative Works, if and
|
|
||||||
wherever such third-party notices normally appear. The contents
|
|
||||||
of the NOTICE file are for informational purposes only and
|
|
||||||
do not modify the License. You may add Your own attribution
|
|
||||||
notices within Derivative Works that You distribute, alongside
|
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
|
||||||
that such additional attribution notices cannot be construed
|
|
||||||
as modifying the License.
|
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
|
||||||
may provide additional or different license terms and conditions
|
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
|
||||||
the conditions stated in this License.
|
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
|
||||||
this License, without any additional terms or conditions.
|
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
|
||||||
the terms of any separate license agreement you may have executed
|
|
||||||
with Licensor regarding such Contributions.
|
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
|
||||||
except as required for reasonable and customary use in describing the
|
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
||||||
implied, including, without limitation, any warranties or conditions
|
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
||||||
appropriateness of using or redistributing the Work and assume any
|
|
||||||
risks associated with Your exercise of permissions under this License.
|
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
|
||||||
unless required by applicable law (such as deliberate and grossly
|
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
|
||||||
liable to You for damages, including any direct, indirect, special,
|
|
||||||
incidental, or consequential damages of any character arising as a
|
|
||||||
result of this License or out of the use or inability to use the
|
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
|
||||||
other commercial damages or losses), even if such Contributor
|
|
||||||
has been advised of the possibility of such damages.
|
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
||||||
or other liability obligations and/or rights consistent with this
|
|
||||||
License. However, in accepting such obligations, You may act only
|
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
|
||||||
defend, and hold each Contributor harmless for any liability
|
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
|
||||||
of your accepting any such warranty or additional liability.
|
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
||||||
replaced with your own identifying information. (Don't include
|
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
|
||||||
comment syntax for the file format. We also recommend that a
|
|
||||||
file or class name and description of purpose be included on the
|
|
||||||
same "printed page" as the copyright notice for easier
|
|
||||||
identification within third-party archives.
|
|
||||||
|
|
||||||
Copyright [2015~2020] [master_roger@sina.com]
|
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
you may not use this file except in compliance with the License.
|
|
||||||
You may obtain a copy of the License at
|
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
See the License for the specific language governing permissions and
|
|
||||||
limitations under the License.
|
|
366
README.md
@ -2,268 +2,176 @@
|
|||||||
|
|
||||||
[![License](https://img.shields.io/badge/license-Apache%202-green.svg)](https://gitee.com/moluo-tech/ril/blob/master/LICENSE)
|
[![License](https://img.shields.io/badge/license-Apache%202-green.svg)](https://gitee.com/moluo-tech/ril/blob/master/LICENSE)
|
||||||
|
|
||||||
## 介绍
|
## 简介
|
||||||
一种AT命令通信解析模块,支持裸机(at_chat)和OS版本(at)。适用于modem、WIFI模块、蓝牙通信。
|
|
||||||
|
|
||||||
## 软件架构
|
AT command(V2) 一款管理AT命令通信交互组件, 适用于Modem、WIFI模块、蓝牙等使用AT命令或者ASCII命令行通信的场景,它涵盖了大部分AT通信形式,如参数设置,查询,二进制数据发送等,同时也支持自定义命令交互管理,由于它的每个命令请求都是异步的,所以对于无操作系统的环境也支持。相对于V1版本,新版本在命令接收匹配,URC不定长度数据捕获以及内存安全上做了大量优化,让它可以应对更多复杂产品应用。
|
||||||
|
|
||||||
- at_chat.c at_chat.h list.h
|
## 基本特性
|
||||||
|
- 所有命令请求都是异步的,无操作系统也可以运行。
|
||||||
|
- 支持单行命令,批量命令,可变参数命令以及自定义AT命令。
|
||||||
|
- 支持命令响应超时,错误重传,优先级管理。
|
||||||
|
- 支持不定长度URC(未经请求主动主报)消息捕获。
|
||||||
|
- 支持多个AT设备通信管理。
|
||||||
|
- 支持内存使用监视与限制。
|
||||||
|
- 支持命令请求的生命周期管理,实时监视命令执行状态。
|
||||||
|
|
||||||
用于无OS版本,使用链式队列及异步回调方式处理AT命令收发,支持URC处理、自定义命令发送与解析作业。
|
## 系统要求
|
||||||
- at.c at.h at_util.h comdef.h
|
|
||||||
|
|
||||||
用于OS版本, 使用前需要根据at_util.h规定的操作系统相关的接口进行移植,如提供信号量操作、任务延时等操作。
|
为了能够使AT命令正常通信,目标系统必须满足以下要求:
|
||||||
|
- 动态内存支持。
|
||||||
|
- RAM 资源:至少 1KB (取决于接收缓冲区与URC缓冲区的设置),建议在可分配3KB内存以上的系统中使用。
|
||||||
|
- 编译器:系统中使用了一些C99的特性(柔性数组、内联),所以编译器需要开启对C99的支持。对于IAR,GCC它们默认是打开的,而Keil MDK需要手动增加编译选项(--c99 --gnu)。
|
||||||
|
|
||||||
|
## 新版本与V1版本区别
|
||||||
|
|
||||||
## 使用说明
|
V1版本分成了两个模块,"at"模块仅适用于在OS环境下运行,而"at_chat"模块则适用于无操作系统的环境下运行,采用预分配内存的方式管理AT请求,不需要动态内存支持,也因为如此限制了其应用范围。虽然也可以在OS下运行,但是支持并不完善。V2版本主要是针对"at_chat"模块整体上进行优化,支持URC功能,同时也加强了对OS环境下的支持,由于使用动态内存方式管理AT命令请求,对于RAM的资源要求更高一些,但是使用上会更加便捷。
|
||||||
|
|
||||||
### at_chat 模块(无OS)
|
### 如何选择
|
||||||
|
如果使用的平台RAM资源(如8位单片机)有限,而且只用来做一些简单的AT通信,使用V1版本是比较合适的,而如果RAM资源充足,建议使用V2版本。
|
||||||
|
|
||||||
|
## 使用入门
|
||||||
|
|
||||||
#### 基本概念
|
下面简单介绍如何使用,4步完成:
|
||||||
|
|
||||||
at_chat 模块使用链式队列进行管理,包含2条链表,空闲链表和就绪链表。它们的每一个基本工作单元称为一个作业项,对于将要执行的命令都会放到就绪链表中,命令执行完成之后由空闲链表来进行回收,作业项的定义如下:
|
### 1.定义适配器,完成驱动接口及缓冲区设置
|
||||||
|
|
||||||
```c
|
```c
|
||||||
|
/**
|
||||||
/*AT作业项*/
|
* @brief AT适配器
|
||||||
typedef struct {
|
|
||||||
unsigned int state : 3;
|
|
||||||
unsigned int type : 3; /* 作业类型*/
|
|
||||||
unsigned int abort : 1;
|
|
||||||
void *param; /* 通用参数*/
|
|
||||||
void *info; /* 通用信息指针*/
|
|
||||||
struct list_head node; /* 链表结点*/
|
|
||||||
}at_item_t;
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
作业是AT控制器定义时固定分配的,没有使用动态内存,默认支持10个作业项,即同时可以允许10个AT命令排队等待处理。
|
|
||||||
|
|
||||||
/*...未完,待续*/
|
|
||||||
|
|
||||||
#### 基本接口与描述
|
|
||||||
- at_send_singlline, 发送单行命令,默认等待OK响应,超时3S
|
|
||||||
- at_send_multiline, 多行命令,默认等待OK响应,超时3S
|
|
||||||
- at_do_cmd,支持自定义发送格式与接收匹配串
|
|
||||||
- at_do_work,支持自定义发送与接收解析
|
|
||||||
|
|
||||||
#### 效果演示
|
|
||||||
|
|
||||||
详细使用可以参考Demo程序wifi_task.c模块
|
|
||||||
|
|
||||||
![m169 wifi模组通信效果图](images/wifi.jpg)
|
|
||||||
|
|
||||||
#### 使用步骤
|
|
||||||
|
|
||||||
1.定义AT控制器及通信适配器接口
|
|
||||||
```c
|
|
||||||
/*
|
|
||||||
* @brief 定义AT控制器
|
|
||||||
*/
|
*/
|
||||||
static at_obj_t at;
|
static const at_adapter_t at_adapter = {
|
||||||
|
.lock = at_mutex_lock, //多任务上锁(非OS下填NULL)
|
||||||
const at_adapter_t adap = { //AT适配器接口
|
.unlock = at_mutex_unlock, //多任务解锁(非OS下填NULL)
|
||||||
//适配GPRS模块的串口读写接口
|
.write = at_device_write, //数据写接口(非阻塞式)
|
||||||
.write = uart_write,
|
.read = at_device_read, //数据读接口(非阻塞式)
|
||||||
.read = uart_read
|
.debug = at_debug, //调试打印接口(不需要则填NULL)
|
||||||
...
|
.recv_bufsize = 256 //接收缓冲区大小(按实际情况填写)
|
||||||
};
|
};
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
2. 初始化AT控制器并放入任务中轮询(考虑到处理实时性,建议20ms以下)
|
### 2.使用AT适配器创建AT通信对象
|
||||||
|
|
||||||
```c
|
```c
|
||||||
/*
|
at_obj_t *at_obj;
|
||||||
* @brief wifi初始化
|
//....
|
||||||
*/
|
at_obj = at_obj_create(&at_adapter);
|
||||||
void wifi_init(void)
|
if (at_obj == NULL) {
|
||||||
{
|
printf("at object create failed\r\n");
|
||||||
at_obj_init(&at, &adap);
|
}
|
||||||
/*...*/
|
//...
|
||||||
}driver_init("wifi", wifi_init);
|
```
|
||||||
|
|
||||||
/*
|
### 3.加入定时轮询任务
|
||||||
* @brief wifi任务(10ms 轮询1次)
|
```c
|
||||||
|
/**
|
||||||
|
* @brief 轮询程序
|
||||||
*/
|
*/
|
||||||
void wifi_task(void)
|
void at_device_process(void)
|
||||||
{
|
{
|
||||||
at_poll_task(&at);
|
static unsigned int timer;
|
||||||
}task_register("wifi", wifi_task, 10);
|
//为了加快AT命令处理响应速度,建议5ms以内轮询一次
|
||||||
|
if (get_tick() - timer > 5) {
|
||||||
|
timer = get_tick();
|
||||||
|
at_obj_process(&at_obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
### 4.发送AT命令
|
||||||
|
|
||||||
|
完成上面几个步骤之后,就可以执行AT命令请求了,下面以查询MODEM信号质量为例,演示如何发送AT命令及解析响应内容.
|
||||||
|
|
||||||
|
**命令格式如下:**
|
||||||
|
|
||||||
|
```shell
|
||||||
|
|
||||||
|
=> AT+CSQ
|
||||||
|
<= +CSQ: <rssi>,<ber>
|
||||||
|
<= OK
|
||||||
|
|
||||||
```
|
```
|
||||||
|
|
||||||
|
**代码实现:**
|
||||||
#### 例子演示
|
|
||||||
|
|
||||||
```C
|
```C
|
||||||
//WIFI IO配置命令
|
|
||||||
=> AT+GPIO_TEST_EN=1\r\n
|
|
||||||
|
|
||||||
<= OK\r\n
|
|
||||||
```
|
|
||||||
```c
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief AT执行回调处理程序
|
* @brief 命令响应处理程序
|
||||||
*/
|
*/
|
||||||
static void test_gpio_callback(at_response_t *r)
|
static void csq_respose_callback(at_response_t *r)
|
||||||
{
|
{
|
||||||
if (r->ret == AT_RET_OK ) {
|
int rssi, ber;
|
||||||
printf("Execute successfully\r\n");
|
//+CSQ: <rssi>,<ber>
|
||||||
} else {
|
if (r->code == AT_RESP_OK) {
|
||||||
printf("Execute failure\r\n");
|
//命令响应成功后,解析出rssi,ber.
|
||||||
}
|
if (sscanf(r->prefix, "+CSQ:%d,%d", &rssi, &ber) == 2) {
|
||||||
}
|
printf("rssi:%d, ber:%d\r\n", rssi, ber);
|
||||||
at_send_singlline(&at, test_gpio_callback, "AT+GPIO_TEST_EN=1");
|
}
|
||||||
```
|
} else {
|
||||||
|
printf("'CSQ' command response failed!\r\n");
|
||||||
|
|
||||||
### at 模块(OS版本)
|
|
||||||
|
|
||||||
由于AT命令通信是一个比较复杂的过程,对于没有OS的环境下处理难度比较大,也很绕,对于不允许阻塞程序,除了使用状态与+回调没有其它更好的办法,所以推荐使用这个模块
|
|
||||||
|
|
||||||
#### 基本接口与描述
|
|
||||||
|
|
||||||
- at_do_cmd,执行AT命令,可以通过这个接口进一步封装出一常用的单行命令、多行命令。
|
|
||||||
- at_split_respond_lines,命令响应分割器。
|
|
||||||
- at_do_work,适用于发送组合命令,如GPRS模组发送短信或者发送socket数据需要等待"<"或者"CONNECT"提示符,可以通过这个接口自定义收发。
|
|
||||||
|
|
||||||
#### 案例演示
|
|
||||||
|
|
||||||
参考我的另外一个项目[RIL(Radio Interface Layer)](https://gitee.com/moluo-tech/ril)
|
|
||||||
|
|
||||||
#### 使用步骤
|
|
||||||
|
|
||||||
1.定义AT控制器、通信适配器接口(包含URC回调函数表,接口缓冲区URC)
|
|
||||||
```c
|
|
||||||
|
|
||||||
static at_obj_t at; //定义AT控制器对象
|
|
||||||
|
|
||||||
static char urc_buf[128]; //URC主动上报缓冲区
|
|
||||||
|
|
||||||
utc_item_t utc_tbl[] = { //定义URC表
|
|
||||||
"+CSQ: ", csq_updated_handler
|
|
||||||
}
|
|
||||||
|
|
||||||
const at_adapter_t adap = { //AT适配器接口
|
|
||||||
.urc_buf = urc_buf,
|
|
||||||
.urc_bufsize = sizeof(urc_buf),
|
|
||||||
.utc_tbl = utc_tbl,
|
|
||||||
.urc_tbl_count = sizeof(utc_tbl) / sizeof(utc_item_t),
|
|
||||||
//debug调试接口
|
|
||||||
.debug = at_debug,
|
|
||||||
//适配GPRS模块的串口读写接口
|
|
||||||
.write = uart_write,
|
|
||||||
.read = uart_read
|
|
||||||
};
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
2.创建AT控制器并创建轮询处理线程
|
|
||||||
|
|
||||||
```c
|
|
||||||
|
|
||||||
void at_thread(void)
|
|
||||||
{
|
|
||||||
at_obj_create(&at, &adap);
|
|
||||||
while (1) {
|
|
||||||
at_process(&at);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
```
|
|
||||||
#### 例子演示
|
|
||||||
|
|
||||||
##### 例子1(查询无线模组信号质量)
|
|
||||||
```c
|
|
||||||
/** at_do_cmd 接口使用演示
|
|
||||||
查询GPRS模组信号质量命令
|
|
||||||
=> AT+CSQ
|
|
||||||
|
|
||||||
<= +CSQ: 24, 0
|
|
||||||
<= OK
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief 获取csq值
|
|
||||||
*/
|
|
||||||
bool read_csq_value(at_obj_t *at, int *rssi, int *error_rate)
|
|
||||||
{
|
|
||||||
//接收缓冲区
|
|
||||||
unsigned char recvbuf[32];
|
|
||||||
//AT应答
|
|
||||||
at_respond_t r = {"OK", recvbuf, sizeof(recvbuf), 3000};
|
|
||||||
//
|
|
||||||
if (at_do_cmd(at, &r, "AT+CSQ") != AT_RET_OK)
|
|
||||||
return false;
|
|
||||||
//提取出响应数据
|
|
||||||
return (sscanf(recv, "%*[^+]+CSQ: %d,%d", rssi, error_rate) == 2);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
```
|
|
||||||
|
|
||||||
##### 例子2(发送TCP数据)
|
|
||||||
```C
|
|
||||||
|
|
||||||
/** at_do_work 接口使用演示
|
|
||||||
参考自hl8518模组Socket 数据发送命令
|
|
||||||
=> AT+KTCPSND=<session_id>,<ndata>
|
|
||||||
|
|
||||||
<= CONNECT
|
|
||||||
|
|
||||||
=> <data>
|
|
||||||
|
|
||||||
<= OK
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief 数据发送处理
|
|
||||||
* @retval none
|
|
||||||
*/
|
|
||||||
static bool socket_send_handler(at_work_ctx_t *e)
|
|
||||||
{
|
|
||||||
struct socket_info *i = (struct socket_info *)e->params;
|
|
||||||
struct ril_sock *s = i->s;
|
|
||||||
|
|
||||||
if (s->type == SOCK_TYPE_TCP)
|
|
||||||
e->printf(e, "AT+KTCPSND=%d,%d", s->session, i->bufsize);
|
|
||||||
else
|
|
||||||
e->printf(e, "AT+KUDPSND=%d,%s,%d,%d",s->session, s->host,
|
|
||||||
s->port, i->bufsize);
|
|
||||||
|
|
||||||
if (e->wait_resp(e, "CONNECT", 5000) != AT_RET_OK) { //等待提示符
|
|
||||||
goto Error;
|
|
||||||
}
|
|
||||||
e->write(i->buf, i->bufsize); //发送数据
|
|
||||||
|
|
||||||
e->write("--EOF--Pattern--", strlen("--EOF--Pattern--")); //发送结束符
|
|
||||||
|
|
||||||
if (e->wait_resp(e, "OK", 5000) == AT_RET_OK)
|
|
||||||
return true;
|
|
||||||
else {
|
|
||||||
Error:
|
|
||||||
e->write("--EOF--Pattern--", strlen("--EOF--Pattern--"));
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief socket 数据发送
|
* @brief 读CSQ值请求
|
||||||
* @param[in] s - socket
|
|
||||||
* @param[in] buf - 数据缓冲区
|
|
||||||
* @param[in] len - 缓冲区长度
|
|
||||||
*/
|
*/
|
||||||
static bool hl8518_sock_send(ril_obj_t *r, struct ril_sock *s, const void *buf,
|
static void read_csq(void)
|
||||||
unsigned int len)
|
|
||||||
{
|
{
|
||||||
struct socket_info info = {s, (unsigned char *)buf, len, 0};
|
//发送命令,超时时间为1000ms,重发次数为0
|
||||||
if (len == 0)
|
at_send_singlline(at_obj, csq_respose_callback, 1000, 0, "AT+CSQ");
|
||||||
return false;
|
|
||||||
return at_do_work(&r->at, (at_work)socket_send_handler, &info);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
```
|
```
|
||||||
|
**下面是在M169 WIFI上运行的效果图(例子:`at_chat/samples/none_os`)**
|
||||||
|
![wifi](images/../docs/images/wifi.png)
|
||||||
|
|
||||||
|
## 更多案例
|
||||||
|
如果你想获取更多完整的应用案例可以参考目录'at_chat/samples',里面提供了几个典型平台下的例子。
|
||||||
|
|
||||||
|
以Linux平台下的案例为例,可以通过终端输入以下命令运行AT通信模拟器:
|
||||||
|
|
||||||
|
```shell
|
||||||
|
cd ./at_chat/samples/linux
|
||||||
|
make clean & make
|
||||||
|
./output/demo
|
||||||
|
```
|
||||||
|
|
||||||
|
如果您使用的是vscode,直接进入samples/linux目录下,按F5开始运行。
|
||||||
|
|
||||||
|
如果程序运行正常,您将看到终端打印如下信息。
|
||||||
|
|
||||||
|
```c
|
||||||
|
*******************************************************
|
||||||
|
This is an asynchronous AT command framework.
|
||||||
|
Author:roger.luo, Mail:morro_luo@163.com
|
||||||
|
*******************************************************
|
||||||
|
|
||||||
|
Please input test item:
|
||||||
|
1:Display memory information.
|
||||||
|
2:Testing singlline command.
|
||||||
|
3:Testing multiline commands.
|
||||||
|
4:Testing variable parameter command.
|
||||||
|
5:Testing response timeout retry.
|
||||||
|
6:Testing response error retry.
|
||||||
|
7:Testing command abort.
|
||||||
|
8:Testing specific response prefix.
|
||||||
|
9:Testing custom command.
|
||||||
|
10:Testing buffer send.
|
||||||
|
11:Testing 'at_do_work' 1.
|
||||||
|
12:Testing read binary data via 'at work'.
|
||||||
|
13:Testing capture unsolicited binary data.
|
||||||
|
14:Testing at context interface.
|
||||||
|
*******************************************************
|
||||||
|
<=
|
||||||
|
+POWER:1
|
||||||
|
...
|
||||||
|
Device power on event detected!
|
||||||
|
```
|
||||||
|
|
||||||
|
根据命令行提示,输入的序号并回车就可以验证对应的用例了.
|
||||||
|
|
||||||
|
|
||||||
|
**更多详细的使用说明,请参考:**
|
||||||
|
|
||||||
|
- [介绍](https://gitee.com/moluo-tech/AT-Command/docs/readme.md)
|
||||||
|
- [快速上手](https://gitee.com/moluo-tech/AT-Command/docs/quickStart.md)
|
||||||
|
- [高级教程](https://gitee.com/moluo-tech/AT-Command/docs/Expert.md)
|
||||||
|
- [平台移植](https://gitee.com/moluo-tech/AT-Command/docs/Porting.md)
|
||||||
|
416
at.c
@ -1,416 +0,0 @@
|
|||||||
/**
|
|
||||||
******************************************************************************
|
|
||||||
* @brief AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD>Ź<EFBFBD><EFBFBD><EFBFBD>(OS<EFBFBD>汾)
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020, <morro_luo@163.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* Change Logs:
|
|
||||||
* Date Author Notes
|
|
||||||
* 2020-01-02 Morro Initial version.
|
|
||||||
* 2021-02-01 Morro ֧<EFBFBD><EFBFBD>URC<EFBFBD>ص<EFBFBD><EFBFBD>н<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
|
||||||
* 2021-02-05 Morro 1.<EFBFBD><EFBFBD>struct at_obj,ȥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* 2.ɾ<EFBFBD><EFBFBD> at_obj_destroy<EFBFBD>ӿ<EFBFBD>
|
|
||||||
* 2021-03-21 Morro ɾ<EFBFBD><EFBFBD>at_obj<EFBFBD>е<EFBFBD>at_work_ctx_t<EFBFBD><EFBFBD>,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>ʹ<EFBFBD><EFBFBD>
|
|
||||||
* 2021-04-08 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ظ<EFBFBD><EFBFBD>ͷ<EFBFBD><EFBFBD>ź<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵȴ<EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* 2021-05-15 Morro <EFBFBD>Ż<EFBFBD>URCƥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* 2021-07-20 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD>at_do_workʱurc<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݶ<EFBFBD>ʧ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* 2021-11-20 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>urc<EFBFBD>¼<EFBFBD><EFBFBD>ж<EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ
|
|
||||||
* <EFBFBD><EFBFBD><EFBFBD>º<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݶ<EFBFBD>ʧ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
******************************************************************************
|
|
||||||
*/
|
|
||||||
#include "at.h"
|
|
||||||
#include "comdef.h"
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
#define MAX_AT_LOCK_TIME 60 * 1000 //AT<41><54><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>
|
|
||||||
|
|
||||||
static void urc_recv_process(at_obj_t *at, const char *buf, unsigned int size);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Ĭ<EFBFBD>ϵ<EFBFBD><EFBFBD>Խӿ<EFBFBD>
|
|
||||||
*/
|
|
||||||
static void nop_dbg(const char *fmt, ...){}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static void put_string(at_obj_t *at, const char *s)
|
|
||||||
{
|
|
||||||
while (*s != '\0')
|
|
||||||
at->adap.write(s++, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
|
||||||
*/
|
|
||||||
static void put_line(at_obj_t *at, const char *s)
|
|
||||||
{
|
|
||||||
put_string(at, s);
|
|
||||||
put_string(at, "\r\n");
|
|
||||||
at->adap.debug("->\r\n%s\r\n", s);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD>ҵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static unsigned int at_work_read(struct at_work_ctx *e, void *buf, unsigned int len)
|
|
||||||
{
|
|
||||||
at_obj_t *at = e->at;
|
|
||||||
len = at->adap.read(buf, len);
|
|
||||||
urc_recv_process(at, buf, len); //<2F>ݽ<EFBFBD><DDBD><EFBFBD>URC<52><43><EFBFBD>д<EFBFBD><D0B4><EFBFBD>
|
|
||||||
return len;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD>ҵд<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static unsigned int at_work_write(struct at_work_ctx *e, const void *buf, unsigned int len)
|
|
||||||
{
|
|
||||||
return e->at->adap.write(buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
//<2F><>ӡ<EFBFBD><D3A1><EFBFBD><EFBFBD>
|
|
||||||
static void at_work_print(struct at_work_ctx *e, const char *cmd, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
va_start(args, cmd);
|
|
||||||
char buf[MAX_AT_CMD_LEN];
|
|
||||||
vsnprintf(buf, sizeof(buf), cmd, args);
|
|
||||||
put_line(e->at, buf);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
|
|
||||||
//<2F>ȴ<EFBFBD>AT<41><54><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ
|
|
||||||
static at_return wait_resp(at_obj_t *at, at_respond_t *r)
|
|
||||||
{
|
|
||||||
at->ret = AT_RET_TIMEOUT;
|
|
||||||
at->resp_timer = at_get_ms();
|
|
||||||
at->rcv_cnt = 0; //<2F><><EFBFBD>ս<EFBFBD><D5BD>ջ<EFBFBD><D5BB><EFBFBD>
|
|
||||||
at->resp = r;
|
|
||||||
at_sem_wait(at->completed, r->timeout);
|
|
||||||
at->adap.debug("<-\r\n%s\r\n", r->recvbuf);
|
|
||||||
at->resp = NULL;
|
|
||||||
return at->ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD>ȴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>յ<EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] resp - <EFBFBD>ڴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>մ<EFBFBD>(<EFBFBD><EFBFBD>"OK",">")
|
|
||||||
* @param[in] timeout - <EFBFBD>ȴ<EFBFBD><EFBFBD><EFBFBD>ʱʱ<EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
at_return wait_recv(struct at_work_ctx *e, const char *resp, unsigned int timeout)
|
|
||||||
{
|
|
||||||
char buf[64];
|
|
||||||
int cnt = 0, len;
|
|
||||||
at_obj_t *at = e->at;
|
|
||||||
at_return ret = AT_RET_TIMEOUT;
|
|
||||||
unsigned int timer = at_get_ms();
|
|
||||||
while (at_get_ms() - timer < timeout) {
|
|
||||||
len = e->read(e, &buf[cnt], sizeof(buf) - cnt);
|
|
||||||
if (len > 0) {
|
|
||||||
cnt += len;
|
|
||||||
buf[cnt] = '\0';
|
|
||||||
if (strstr(buf, resp)) {
|
|
||||||
ret = AT_RET_OK;
|
|
||||||
break;
|
|
||||||
} else if (strstr(buf, "ERROR")) {
|
|
||||||
ret = AT_RET_ERROR;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} else
|
|
||||||
at_delay(1);
|
|
||||||
}
|
|
||||||
at->adap.debug("%s\r\n", buf);
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] adap - AT<EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
void at_obj_init(at_obj_t *at, const at_adapter_t *adap)
|
|
||||||
{
|
|
||||||
at->adap = *adap;
|
|
||||||
at->rcv_cnt = 0;
|
|
||||||
at->send_lock = at_sem_new(1);
|
|
||||||
at->recv_lock = at_sem_new(1);
|
|
||||||
at->completed = at_sem_new(0);
|
|
||||||
at->urc_item = NULL;
|
|
||||||
if (at->adap.debug == NULL)
|
|
||||||
at->adap.debug = nop_dbg;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ִ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] fmt - <EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] r - <EFBFBD><EFBFBD>Ӧ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>NULL, Ĭ<EFBFBD>Ϸ<EFBFBD><EFBFBD><EFBFBD>OK<EFBFBD><EFBFBD>ʾ<EFBFBD>ɹ<EFBFBD>,<EFBFBD>ȴ<EFBFBD>5s
|
|
||||||
* @param[in] args - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD>
|
|
||||||
*/
|
|
||||||
at_return at_do_cmd(at_obj_t *at, at_respond_t *r, const char *cmd)
|
|
||||||
{
|
|
||||||
at_return ret;
|
|
||||||
char defbuf[64];
|
|
||||||
at_respond_t default_resp = {"OK", defbuf, sizeof(defbuf), 5000};
|
|
||||||
if (r == NULL) {
|
|
||||||
r = &default_resp; //Ĭ<><C4AC><EFBFBD><EFBFBD>Ӧ
|
|
||||||
}
|
|
||||||
if (!at_sem_wait(at->send_lock, r->timeout)) {
|
|
||||||
return AT_RET_TIMEOUT;
|
|
||||||
}
|
|
||||||
at->busy = true;
|
|
||||||
|
|
||||||
while (at->urc_cnt) {
|
|
||||||
at_delay(10);
|
|
||||||
}
|
|
||||||
put_line(at, cmd);
|
|
||||||
ret = wait_resp(at, r);
|
|
||||||
at_sem_post(at->send_lock);
|
|
||||||
at->busy = false;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ִ<EFBFBD><EFBFBD>AT<EFBFBD><EFBFBD>ҵ
|
|
||||||
* @param[in] at - AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] work - <EFBFBD><EFBFBD>ҵ<EFBFBD><EFBFBD><EFBFBD>ں<EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD> - int (*)(at_work_ctx_t *))
|
|
||||||
* @param[in] params- <EFBFBD><EFBFBD>ҵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>work<EFBFBD>ķ<EFBFBD><EFBFBD><EFBFBD>ֵ
|
|
||||||
*/
|
|
||||||
int at_do_work(at_obj_t *at, at_work work, void *params)
|
|
||||||
{
|
|
||||||
at_work_ctx_t ctx;
|
|
||||||
int ret;
|
|
||||||
if (!at_sem_wait(at->send_lock, MAX_AT_LOCK_TIME)) {
|
|
||||||
return AT_RET_TIMEOUT;
|
|
||||||
}
|
|
||||||
if (!at_sem_wait(at->recv_lock, MAX_AT_LOCK_TIME))
|
|
||||||
return AT_RET_TIMEOUT;
|
|
||||||
|
|
||||||
at->busy = true;
|
|
||||||
//<2F><><EFBFBD><EFBFBD>at_work_ctx_t
|
|
||||||
ctx.params = params;
|
|
||||||
ctx.printf = at_work_print;
|
|
||||||
ctx.read = at_work_read;
|
|
||||||
ctx.write = at_work_write;
|
|
||||||
ctx.wait_resp = wait_recv;
|
|
||||||
ctx.at = at;
|
|
||||||
|
|
||||||
at->rcv_cnt = 0;
|
|
||||||
ret = work(&ctx);
|
|
||||||
at_sem_post(at->recv_lock);
|
|
||||||
at_sem_post(at->send_lock);
|
|
||||||
at->busy = false;
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><EFBFBD>
|
|
||||||
* @param[in] recvbuf - <EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[out] lines - <EFBFBD><EFBFBD>Ӧ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] separator- <EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>(, \n)
|
|
||||||
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
int at_split_respond_lines(char *recvbuf, char *lines[], int count, char separator)
|
|
||||||
{
|
|
||||||
char *s = recvbuf;
|
|
||||||
size_t i = 0;
|
|
||||||
if (s == NULL || lines == NULL)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
lines[i++] = s;
|
|
||||||
while(*s && i < count) {
|
|
||||||
if (*s == ',') {
|
|
||||||
*s = '\0';
|
|
||||||
lines[i++] = s + 1; /*ָ<><D6B8><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>Ӵ<EFBFBD>*/
|
|
||||||
}
|
|
||||||
s++;
|
|
||||||
}
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD>URC<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>в<EFBFBD>ѯURC<EFBFBD><EFBFBD>
|
|
||||||
* @param[in] urcline - URC<EFBFBD><EFBFBD>
|
|
||||||
* @return true - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>, false - δʶ<EFBFBD><EFBFBD>URC
|
|
||||||
*/
|
|
||||||
const urc_item_t *find_urc_item(at_obj_t *at, char *urc_buf, unsigned int size)
|
|
||||||
{
|
|
||||||
const urc_item_t *tbl = at->adap.utc_tbl;
|
|
||||||
int i;
|
|
||||||
if (size < 2)
|
|
||||||
return NULL;
|
|
||||||
for (i = 0; i < at->adap.urc_tbl_count; i++) {
|
|
||||||
if (strstr(urc_buf, tbl->prefix))
|
|
||||||
return tbl;
|
|
||||||
tbl++;
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief urc <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] urcline - URC<EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static void urc_handler_entry(at_obj_t *at, char *urcline, unsigned int size)
|
|
||||||
{
|
|
||||||
at_urc_ctx_t context = {at->adap.read, urcline, at->adap.urc_bufsize, size};
|
|
||||||
at->adap.debug("<=\r\n%s\r\n", urcline);
|
|
||||||
at->urc_item->handler(&context); /* <20>ݽ<EFBFBD><DDBD><EFBFBD><EFBFBD>ϲ㴦<CFB2><E3B4A6> */
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief urc <EFBFBD><EFBFBD><EFBFBD>մ<EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] ch - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD>
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
static void urc_recv_process(at_obj_t *at, const char *buf, unsigned int size)
|
|
||||||
{
|
|
||||||
register char *urc_buf;
|
|
||||||
int ch;
|
|
||||||
urc_buf = at->adap.urc_buf;
|
|
||||||
|
|
||||||
//<2F><><EFBFBD>ճ<EFBFBD>ʱ<EFBFBD><CAB1><EFBFBD><EFBFBD>,Ĭ<><C4AC>MAX_URC_RECV_TIMEOUT
|
|
||||||
if (at->urc_cnt > 0 && at_istimeout(at->urc_timer, MAX_URC_RECV_TIMEOUT)) {
|
|
||||||
urc_buf[at->urc_cnt] = '\0';
|
|
||||||
if (at->urc_cnt > 2)
|
|
||||||
at->adap.debug("urc recv timeout=>%s\r\n", urc_buf);
|
|
||||||
at->urc_cnt = 0;
|
|
||||||
at->urc_item = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
while (size--) {
|
|
||||||
at->urc_timer = at_get_ms();
|
|
||||||
ch = *buf++;
|
|
||||||
urc_buf[at->urc_cnt++] = ch;
|
|
||||||
|
|
||||||
if (strchr(SPEC_URC_END_MARKS, ch) || ch == '\0') { //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD>
|
|
||||||
urc_buf[at->urc_cnt] = '\0';
|
|
||||||
if (at->urc_item == NULL)
|
|
||||||
at->urc_item = find_urc_item(at, urc_buf, at->urc_cnt);
|
|
||||||
if (at->urc_item != NULL){
|
|
||||||
if (strchr(at->urc_item->end_mark, ch)) { //ƥ<><C6A5><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
urc_handler_entry(at, urc_buf, at->urc_cnt);
|
|
||||||
at->urc_cnt = 0;
|
|
||||||
at->urc_item = NULL;
|
|
||||||
}
|
|
||||||
} else if (ch == '\r' || ch == '\n'|| ch == '\0') {
|
|
||||||
if (at->urc_cnt > 2 && !at->busy) {
|
|
||||||
at->adap.debug("%s\r\n", urc_buf); //δʶ<CEB4><EFBFBD>URC
|
|
||||||
}
|
|
||||||
at->urc_cnt = 0;
|
|
||||||
}
|
|
||||||
} else if (at->urc_cnt >= at->adap.urc_bufsize) { //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
at->urc_cnt = 0;
|
|
||||||
at->urc_item = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ֪ͨ
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
static void resp_notification(at_obj_t *at, at_return ret)
|
|
||||||
{
|
|
||||||
at->ret = ret;
|
|
||||||
at->resp = NULL;
|
|
||||||
|
|
||||||
at_sem_post(at->completed);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><EFBFBD><EFBFBD>մ<EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] buf - <EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] size - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݳ<EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
static void resp_recv_process(at_obj_t *at, const char *buf, unsigned int size)
|
|
||||||
{
|
|
||||||
char *rcv_buf;
|
|
||||||
unsigned short rcv_size;
|
|
||||||
at_respond_t *resp = at->resp;
|
|
||||||
|
|
||||||
if (resp == NULL) //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
return;
|
|
||||||
|
|
||||||
if (size) {
|
|
||||||
rcv_buf = (char *)resp->recvbuf;
|
|
||||||
rcv_size = resp->bufsize;
|
|
||||||
|
|
||||||
if (at->rcv_cnt + size >= rcv_size) { //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
at->rcv_cnt = 0;
|
|
||||||
at->adap.debug("Receive overflow:%s", rcv_buf);
|
|
||||||
}
|
|
||||||
/*<2A><><EFBFBD><EFBFBD><EFBFBD>յ<EFBFBD><D5B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݷ<EFBFBD><DDB7><EFBFBD>rcv_buf<75><66> ---------------------------------------------*/
|
|
||||||
memcpy(rcv_buf + at->rcv_cnt, buf, size);
|
|
||||||
at->rcv_cnt += size;
|
|
||||||
rcv_buf[at->rcv_cnt] = '\0';
|
|
||||||
|
|
||||||
if (strstr(rcv_buf, resp->matcher)) { //<2F><><EFBFBD><EFBFBD>ƥ<EFBFBD><C6A5>
|
|
||||||
resp_notification(at, AT_RET_OK);
|
|
||||||
return;
|
|
||||||
} else if (strstr(rcv_buf, "ERROR")) {
|
|
||||||
resp_notification(at, AT_RET_ERROR);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (at_istimeout(at->resp_timer, resp->timeout)) //<2F><><EFBFBD>ճ<EFBFBD>ʱ
|
|
||||||
resp_notification(at, AT_RET_TIMEOUT);
|
|
||||||
else if (at->suspend) //ǿ<><C7BF><EFBFBD><EFBFBD>ֹ
|
|
||||||
resp_notification(at, AT_RET_ABORT);
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ATæ<EFBFBD>ж<EFBFBD>
|
|
||||||
* @return true - <EFBFBD><EFBFBD>ATָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
bool at_obj_busy(at_obj_t *at)
|
|
||||||
{
|
|
||||||
return !at->busy && at_istimeout(at->urc_timer, 2000);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>AT<EFBFBD><EFBFBD>ҵ
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
void at_suspend(at_obj_t *at)
|
|
||||||
{
|
|
||||||
at->suspend = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD>ָ<EFBFBD>AT<EFBFBD><EFBFBD>ҵ
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
void at_resume(at_obj_t *at)
|
|
||||||
{
|
|
||||||
at->suspend = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
void at_process(at_obj_t *at)
|
|
||||||
{
|
|
||||||
char buf[1];
|
|
||||||
unsigned int len;
|
|
||||||
if (!at_sem_wait(at->recv_lock, MAX_AT_LOCK_TIME))
|
|
||||||
return;
|
|
||||||
do {
|
|
||||||
len = at->adap.read(buf, sizeof(buf));
|
|
||||||
urc_recv_process(at, buf,len);
|
|
||||||
resp_recv_process(at, buf, len);
|
|
||||||
} while (len);
|
|
||||||
|
|
||||||
at_sem_post(at->recv_lock);
|
|
||||||
}
|
|
193
at.h
@ -1,193 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
* @brief AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD>Ź<EFBFBD><EFBFBD><EFBFBD>(OS<EFBFBD>汾)
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020, <morro_luo@163.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* Change Logs:
|
|
||||||
* Date Author Notes
|
|
||||||
* 2020-01-02 Morro Initial version.
|
|
||||||
* 2021-02-01 Morro ֧<EFBFBD><EFBFBD>URC<EFBFBD>ص<EFBFBD><EFBFBD>н<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>.
|
|
||||||
* 2021-02-05 Morro 1.<EFBFBD><EFBFBD>struct at_obj,ȥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* 2.ɾ<EFBFBD><EFBFBD> at_obj_destroy<EFBFBD>ӿ<EFBFBD>
|
|
||||||
* 2021-03-21 Morro ɾ<EFBFBD><EFBFBD>at_obj<EFBFBD>е<EFBFBD>at_work_ctx_t<EFBFBD><EFBFBD>,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>ʹ<EFBFBD><EFBFBD>
|
|
||||||
* 2021-04-08 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ظ<EFBFBD><EFBFBD>ͷ<EFBFBD><EFBFBD>ź<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵȴ<EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* 2021-05-15 Morro <EFBFBD>Ż<EFBFBD>URCƥ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* 2021-07-20 Morro <EFBFBD><EFBFBD><EFBFBD>ӽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD>at_do_workʱurc<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݶ<EFBFBD>ʧ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
#ifndef _AT_H_
|
|
||||||
#define _AT_H_
|
|
||||||
|
|
||||||
#include "at_util.h"
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EEB3A4> */
|
|
||||||
#define MAX_AT_CMD_LEN 128
|
|
||||||
|
|
||||||
/* <20><><EFBFBD><EFBFBD>urc<72><63><EFBFBD>ճ<EFBFBD>ʱʱ<CAB1><CAB1>*/
|
|
||||||
#define MAX_URC_RECV_TIMEOUT 300
|
|
||||||
|
|
||||||
/* ָ<><D6B8><EFBFBD><EFBFBD>URC <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD> */
|
|
||||||
#define SPEC_URC_END_MARKS ":,\r\n"
|
|
||||||
|
|
||||||
struct at_obj; /* AT<41><54><EFBFBD><EFBFBD>*/
|
|
||||||
|
|
||||||
/*AT<41><54><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6> ---------------------------------------------------------------*/
|
|
||||||
typedef enum {
|
|
||||||
AT_RET_OK = 0, /* ִ<>гɹ<D0B3>*/
|
|
||||||
AT_RET_ERROR, /* ִ<>д<EFBFBD><D0B4><EFBFBD>*/
|
|
||||||
AT_RET_TIMEOUT, /* <20><>Ӧ<EFBFBD><D3A6>ʱ*/
|
|
||||||
AT_RET_ABORT, /* δ֪<CEB4><D6AA><EFBFBD><EFBFBD>*/
|
|
||||||
}at_return;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief URC <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(Context) <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD>ݶ<EFBFBD>ȡ<EFBFBD>ӿ<EFBFBD>
|
|
||||||
* @params buf - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @params len - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С
|
|
||||||
*/
|
|
||||||
unsigned int (*read)(void *buf, unsigned int len);
|
|
||||||
char *buf; /* <20><><EFBFBD>ݻ<EFBFBD><DDBB><EFBFBD><EFBFBD><EFBFBD> */
|
|
||||||
int bufsize; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С */
|
|
||||||
int recvlen; /* <20>ѽ<EFBFBD><D1BD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݳ<EFBFBD><DDB3><EFBFBD>*/
|
|
||||||
} at_urc_ctx_t;
|
|
||||||
|
|
||||||
/*(Unsolicited Result Codes (URCs))<29><><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ------------------------------------*/
|
|
||||||
typedef struct {
|
|
||||||
/**
|
|
||||||
* @brief urc ǰ(<EFBFBD><EFBFBD>"+CSQ: ")
|
|
||||||
*/
|
|
||||||
const char *prefix;
|
|
||||||
/**
|
|
||||||
* @brief urc ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD>ο<EFBFBD>DEF_URC_END_MARKS<EFBFBD>б<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ĭ<EFBFBD><EFBFBD>"\n")
|
|
||||||
* @note
|
|
||||||
*/
|
|
||||||
const char *end_mark;
|
|
||||||
/**
|
|
||||||
* @brief urc<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @params ctx - URC <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
void (*handler)(at_urc_ctx_t *ctx);
|
|
||||||
}urc_item_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief AT<EFBFBD>ӿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD>ڳ<EFBFBD>ʼ<EFBFBD><EFBFBD>AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD>ӿ<EFBFBD>
|
|
||||||
*/
|
|
||||||
unsigned int (*write)(const void *buf, unsigned int len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD>ݶ<EFBFBD><EFBFBD>ӿ<EFBFBD>
|
|
||||||
*/
|
|
||||||
unsigned int (*read)(void *buf, unsigned int len);
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD>ӡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD>,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>NULL
|
|
||||||
*/
|
|
||||||
void (*debug)(const char *fmt, ...);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief urc <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>NULL
|
|
||||||
*/
|
|
||||||
urc_item_t *utc_tbl;
|
|
||||||
/**
|
|
||||||
* @brief urc<EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>NULL
|
|
||||||
*/
|
|
||||||
char *urc_buf;
|
|
||||||
/**
|
|
||||||
* @brief utc_tbl<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>0
|
|
||||||
*/
|
|
||||||
unsigned short urc_tbl_count;
|
|
||||||
/**
|
|
||||||
* @brief urc<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>0
|
|
||||||
*/
|
|
||||||
unsigned short urc_bufsize;
|
|
||||||
}at_adapter_t;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
typedef struct {
|
|
||||||
const char *matcher; /* <20><><EFBFBD><EFBFBD>ƥ<EFBFBD>䴮 */
|
|
||||||
char *recvbuf; /* <20><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD> */
|
|
||||||
unsigned short bufsize; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
|
||||||
unsigned int timeout; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱʱ<CAB1><CAB1> */
|
|
||||||
} at_respond_t;
|
|
||||||
|
|
||||||
/** work context ------------------------------------------------------------*/
|
|
||||||
/**
|
|
||||||
* @brief AT<EFBFBD><EFBFBD>ҵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(Work Context) <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
typedef struct at_work_ctx {
|
|
||||||
struct at_obj *at;
|
|
||||||
|
|
||||||
//<2F><>ҵ<EFBFBD><D2B5><EFBFBD><EFBFBD>,<2C><>at_do_work<72>ӿڴ<D3BF><DAB4><EFBFBD>
|
|
||||||
void *params;
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
unsigned int (*write)(struct at_work_ctx *self, const void *buf, unsigned int len);
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD>ݶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
unsigned int (*read)(struct at_work_ctx *self, void *buf, unsigned int len);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
void (*printf)(struct at_work_ctx *self, const char *fmt, ...);
|
|
||||||
/*
|
|
||||||
* @brief <EFBFBD>ȴ<EFBFBD><EFBFBD>ظ<EFBFBD>
|
|
||||||
* @param[in] prefix - <EFBFBD>ڴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ǰ(<EFBFBD><EFBFBD>"OK",">")
|
|
||||||
* @param[in] timeout - <EFBFBD>ȴ<EFBFBD><EFBFBD><EFBFBD>ʱʱ<EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
at_return (*wait_resp)(struct at_work_ctx *self, const char *prefix,
|
|
||||||
unsigned int timeout);
|
|
||||||
}at_work_ctx_t;
|
|
||||||
|
|
||||||
|
|
||||||
/*AT<41><54><EFBFBD><EFBFBD> ---------------------------------------------------------------------*/
|
|
||||||
typedef struct at_obj {
|
|
||||||
at_adapter_t adap; /* <20>ӿ<EFBFBD><D3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
at_sem_t send_lock; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
at_sem_t recv_lock; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
at_sem_t completed; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ź<EFBFBD>*/
|
|
||||||
at_respond_t *resp; /* ATӦ<54><D3A6><EFBFBD><EFBFBD>Ϣ*/
|
|
||||||
const urc_item_t *urc_item; /* <20><>ǰURC<52><43>*/
|
|
||||||
unsigned int resp_timer; /* <20><>Ӧ<EFBFBD><D3A6><EFBFBD>ն<EFBFBD>ʱ<EFBFBD><CAB1>*/
|
|
||||||
unsigned int urc_timer; /* URC<52><43>ʱ<EFBFBD><CAB1> */
|
|
||||||
at_return ret; /* <20><><EFBFBD><EFBFBD>ִ<EFBFBD>н<EFBFBD><D0BD><EFBFBD>*/
|
|
||||||
unsigned short urc_cnt, rcv_cnt; /* <20><><EFBFBD>ռ<EFBFBD><D5BC><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
unsigned char busy : 1;
|
|
||||||
unsigned char suspend: 1;
|
|
||||||
unsigned char dowork : 1;
|
|
||||||
}at_obj_t;
|
|
||||||
|
|
||||||
typedef int (*at_work)(at_work_ctx_t *);
|
|
||||||
|
|
||||||
void at_obj_init(at_obj_t *at, const at_adapter_t *adap); /* AT<41><54>ʼ<EFBFBD><CABC>*/
|
|
||||||
|
|
||||||
bool at_obj_busy(at_obj_t *at);
|
|
||||||
|
|
||||||
void at_suspend(at_obj_t *at); /* <20><><EFBFBD><EFBFBD>*/
|
|
||||||
|
|
||||||
void at_resume(at_obj_t *at); /* <20>ָ<EFBFBD>*/
|
|
||||||
|
|
||||||
at_return at_do_cmd(at_obj_t *at, at_respond_t *r, const char *cmd);
|
|
||||||
|
|
||||||
int at_split_respond_lines(char *recvbuf, char *lines[], int count, char separator);
|
|
||||||
|
|
||||||
int at_do_work(at_obj_t *at, at_work work, void *params); /* <20>Զ<EFBFBD><D4B6><EFBFBD>AT<41><54>ҵ*/
|
|
||||||
|
|
||||||
|
|
||||||
void at_process(at_obj_t *at); /* AT<41><54><EFBFBD>մ<EFBFBD><D5B4><EFBFBD>*/
|
|
||||||
|
|
||||||
#endif
|
|
534
at_chat.c
@ -1,534 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
* @brief ATָ<EFBFBD><EFBFBD>ͨ<EFBFBD>Ź<EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020~2021, <morro_luo@163.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apathe-2.0
|
|
||||||
*
|
|
||||||
* Change Logs:
|
|
||||||
* Date Author Notes
|
|
||||||
* 2020-01-02 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* 2021-01-20 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD>debug<EFBFBD><EFBFBD><EFBFBD>Խӿ<EFBFBD>, <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* <EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƚӿ<EFBFBD>
|
|
||||||
* 2021-03-03 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>URC<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӡ<EFBFBD><EFBFBD><EFBFBD>ճ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
#include "at_chat.h"
|
|
||||||
#include <stdarg.h>
|
|
||||||
#include <string.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
|
|
||||||
//<2F><>ʱ<EFBFBD>ж<EFBFBD>
|
|
||||||
#define AT_IS_TIMEOUT(start, time) (AT_GET_TICK() - (start) > (time))
|
|
||||||
|
|
||||||
/**AT<41><54>ҵ<EFBFBD><D2B5><EFBFBD><EFBFBD>(ʵ<><CAB5><EFBFBD><EFBFBD>4<EFBFBD><34><EFBFBD><EFBFBD><EFBFBD>͵<EFBFBD>״̬<D7B4><CCAC><EFBFBD><EFBFBD>ѯ<EFBFBD><D1AF><EFBFBD><EFBFBD>) -----------------------------------*/
|
|
||||||
#define AT_TYPE_WORK 0 /* <20><>ͨ<EFBFBD><CDA8>ҵ ----------*/
|
|
||||||
#define AT_TYPE_CMD 1 /* <20><><EFBFBD><D7BC><EFBFBD><EFBFBD> ----------*/
|
|
||||||
#define AT_TYPE_MULTILINE 2 /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ----------*/
|
|
||||||
#define AT_TYPE_SINGLLINE 3 /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ----------*/
|
|
||||||
|
|
||||||
#ifndef AT_DEBUG
|
|
||||||
#define AT_DEBUG(...) do {}while(0)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
typedef int (*base_work)(at_obj_t *at, ...);
|
|
||||||
|
|
||||||
static void at_send_line(at_obj_t *at, const char *fmt, va_list args);
|
|
||||||
|
|
||||||
static const inline at_adapter_t *__get_adapter(at_obj_t *at)
|
|
||||||
{
|
|
||||||
return &at->adap;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool at_is_timeout(at_obj_t *at, unsigned int ms)
|
|
||||||
{
|
|
||||||
return AT_IS_TIMEOUT(at->timer, ms);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static void send_data(at_obj_t *at, const void *buf, unsigned int len)
|
|
||||||
{
|
|
||||||
at->adap.write(buf, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӡ
|
|
||||||
*/
|
|
||||||
static void print(at_obj_t *at, const char *cmd, ...)
|
|
||||||
{
|
|
||||||
va_list args;
|
|
||||||
va_start(args, cmd);
|
|
||||||
at_send_line(at, cmd, args);
|
|
||||||
va_end(args);
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>ǰ<EFBFBD><EFBFBD><EFBFBD>ݽ<EFBFBD><EFBFBD>ճ<EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static unsigned int get_recv_count(at_obj_t *at)
|
|
||||||
{
|
|
||||||
return at->recv_cnt;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static char *get_recv_buf(at_obj_t *at)
|
|
||||||
{
|
|
||||||
return (char *)at->adap.recv_buf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static void recv_buf_clear(at_obj_t *at)
|
|
||||||
{
|
|
||||||
at->recv_cnt = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**ǰ<><C7B0><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD>*/
|
|
||||||
static char *search_string(at_obj_t *at, const char *str)
|
|
||||||
{
|
|
||||||
return strstr(get_recv_buf(at), str);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD>ִֹ<EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static bool at_isabort(at_obj_t *at)
|
|
||||||
{
|
|
||||||
return at->cursor ? at->cursor->abort : 1;
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD>ü<EFBFBD>ʱ<EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static void at_reset_timer(at_obj_t *at)
|
|
||||||
{
|
|
||||||
at->timer = AT_GET_TICK();
|
|
||||||
}
|
|
||||||
/**
|
|
||||||
* @brief ATִ<EFBFBD>лص<EFBFBD>
|
|
||||||
*/
|
|
||||||
static void do_at_callbatk(at_obj_t *a, at_item_t *i, at_callbatk_t cb, at_return ret)
|
|
||||||
{
|
|
||||||
at_response_t r;
|
|
||||||
if ((ret == AT_RET_ERROR || ret == AT_RET_TIMEOUT) && a->adap.error != NULL)
|
|
||||||
a->adap.error();
|
|
||||||
|
|
||||||
if (cb) {
|
|
||||||
r.param = i->param;
|
|
||||||
r.recvbuf = get_recv_buf(a);
|
|
||||||
r.recvcnt = get_recv_count(a);
|
|
||||||
r.ret = ret;
|
|
||||||
cb(&r);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ<EFBFBD><D2B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
static bool add_work(at_obj_t *at, void *params, void *info, int type)
|
|
||||||
{
|
|
||||||
at_item_t *i;
|
|
||||||
if (list_empty(&at->ls_idle)) //<2F><EFBFBD><DEBF><EFBFBD>at_item
|
|
||||||
return NULL;
|
|
||||||
i = list_first_entry(&at->ls_idle, at_item_t, node);//<2F>ӿ<EFBFBD><D3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>ҵ
|
|
||||||
i->info = (void *)info;
|
|
||||||
i->param = (void *)params;
|
|
||||||
i->state = AT_STATE_WAIT;
|
|
||||||
i->type = type;
|
|
||||||
i->abort = 0;
|
|
||||||
list_move_tail(&i->node, &at->ls_ready); //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
return i != 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ִ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ
|
|
||||||
*/
|
|
||||||
static int do_work_handler(at_obj_t *at)
|
|
||||||
{
|
|
||||||
at_item_t *i = at->cursor;
|
|
||||||
return ((int (*)(at_env_t *e))i->info)(&at->env);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] a - AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @return true - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ, false - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ,
|
|
||||||
*/
|
|
||||||
static int do_cmd_handler(at_obj_t *a)
|
|
||||||
{
|
|
||||||
at_item_t *i = a->cursor;
|
|
||||||
at_env_t *e = &a->env;
|
|
||||||
const at_cmd_t *c = (at_cmd_t *)i->info;
|
|
||||||
switch(e->state) {
|
|
||||||
case 0: /*<2A><><EFBFBD><EFBFBD>״̬ ------------------------------------------------------*/
|
|
||||||
c->sender(e);
|
|
||||||
e->state++;
|
|
||||||
e->reset_timer(a);
|
|
||||||
e->recvclr(a);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
if (search_string(a, c->matcher)) { //<2F><><EFBFBD><EFBFBD>ƥ<EFBFBD><C6A5>
|
|
||||||
AT_DEBUG("<-\r\n%s\r\n", get_recv_buf(a));
|
|
||||||
do_at_callbatk(a, i, c->cb, AT_RET_OK);
|
|
||||||
return true;
|
|
||||||
} else if (search_string(a, "ERROR")) {
|
|
||||||
AT_DEBUG("<-\r\n%s\r\n", get_recv_buf(a));
|
|
||||||
if (++e->i >= c->retry) {
|
|
||||||
do_at_callbatk(a, i, c->cb, AT_RET_ERROR);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
e->state = 2; /* <20><><EFBFBD><EFBFBD>֮<EFBFBD><D6AE><EFBFBD><EFBFBD>ʱһ<CAB1><D2BB>ʱ<EFBFBD><CAB1>*/
|
|
||||||
e->reset_timer(a); /* <20><><EFBFBD>ö<EFBFBD>ʱ<EFBFBD><CAB1>*/
|
|
||||||
} else if (e->is_timeout(a, c->timeout)) { /* <20><>Ӧ<EFBFBD><D3A6>ʱ*/
|
|
||||||
if (++e->i >= c->retry) {
|
|
||||||
do_at_callbatk(a, i, c->cb, AT_RET_TIMEOUT);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
e->state = 0; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ״̬*/
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (e->is_timeout(a, 500))
|
|
||||||
e->state = 0; /*<2A><><EFBFBD>س<EFBFBD>ʼ״̬*/
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
e->state = 0;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] a - AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @return true - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ, false - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ,
|
|
||||||
*/
|
|
||||||
static int send_signlline_handler(at_obj_t *a)
|
|
||||||
{
|
|
||||||
at_item_t *i = a->cursor;
|
|
||||||
at_env_t *e = &a->env;
|
|
||||||
const char *cmd = (const char *)i->param;
|
|
||||||
at_callbatk_t cb = (at_callbatk_t)i->info;
|
|
||||||
|
|
||||||
switch(e->state) {
|
|
||||||
case 0: /*<2A><><EFBFBD><EFBFBD>״̬ ------------------------------------------------------*/
|
|
||||||
e->printf(a, cmd);
|
|
||||||
e->state++;
|
|
||||||
e->reset_timer(a);
|
|
||||||
e->recvclr(a);
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
if (search_string(a, "OK")) {
|
|
||||||
AT_DEBUG("<-\r\n%s\r\n", get_recv_buf(a));
|
|
||||||
do_at_callbatk(a, i, cb, AT_RET_OK); //<2F><><EFBFBD><EFBFBD>ƥ<EFBFBD><C6A5>
|
|
||||||
return true;
|
|
||||||
} else if (search_string(a, "ERROR")) {
|
|
||||||
AT_DEBUG("<-\r\n%s\r\n", get_recv_buf(a));
|
|
||||||
if (++e->i >= 3) {
|
|
||||||
do_at_callbatk(a, i, cb, AT_RET_ERROR);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
e->state = 2; /*<2A><><EFBFBD><EFBFBD>֮<EFBFBD><D6AE><EFBFBD><EFBFBD>ʱһ<CAB1><D2BB>ʱ<EFBFBD><CAB1>*/
|
|
||||||
e->reset_timer(a); /*<2A><><EFBFBD>ö<EFBFBD>ʱ<EFBFBD><CAB1>*/
|
|
||||||
} else if (e->is_timeout(a, 3000 + e->i * 2000)) {
|
|
||||||
if (++e->i >= 3) {
|
|
||||||
do_at_callbatk(a, i, cb, AT_RET_TIMEOUT);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
e->state = 0; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ״̬*/
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (e->is_timeout(a, 500))
|
|
||||||
e->state = 0; /**<2A><><EFBFBD>س<EFBFBD>ʼ״̬*/
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
e->state = 0;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] a - AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @return true - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ, false - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ,
|
|
||||||
*/
|
|
||||||
static int send_multiline_handler(at_obj_t *a)
|
|
||||||
{
|
|
||||||
at_item_t *i = a->cursor;
|
|
||||||
at_env_t *e = &a->env;
|
|
||||||
const char **cmds = (const char **)i->param;
|
|
||||||
at_callbatk_t cb = (at_callbatk_t)i->info;
|
|
||||||
switch(e->state) {
|
|
||||||
case 0:
|
|
||||||
if (cmds[e->i] == NULL) { /**<2A><><EFBFBD><EFBFBD>ִ<EFBFBD><D6B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
do_at_callbatk(a, i, cb, AT_RET_OK);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
e->printf(a, "%s\r\n", cmds[e->i]);
|
|
||||||
e->recvclr(a); /**<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
e->reset_timer(a);
|
|
||||||
e->state++;
|
|
||||||
break;
|
|
||||||
case 1:
|
|
||||||
if (search_string(a, "OK")) {
|
|
||||||
e->state = 0;
|
|
||||||
e->i++;
|
|
||||||
e->j = 0;
|
|
||||||
AT_DEBUG("<-\r\n%s\r\n", get_recv_buf(a));
|
|
||||||
} else if (search_string(a, "ERROR")) {
|
|
||||||
AT_DEBUG("<-\r\n%s\r\n", get_recv_buf(a));
|
|
||||||
if (++e->j >= 3) {
|
|
||||||
do_at_callbatk(a, i, cb, AT_RET_ERROR);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
e->state = 2; /*<2A><><EFBFBD><EFBFBD>֮<EFBFBD><D6AE><EFBFBD><EFBFBD>ʱһ<CAB1><D2BB>ʱ<EFBFBD><CAB1>*/
|
|
||||||
e->reset_timer(a); /*<2A><><EFBFBD>ö<EFBFBD>ʱ<EFBFBD><CAB1>*/
|
|
||||||
} else if (e->is_timeout(a, 3000)) {
|
|
||||||
do_at_callbatk(a, i, cb, AT_RET_TIMEOUT);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
if (e->is_timeout(a, 500))
|
|
||||||
e->state = 0; /**<2A><><EFBFBD>س<EFBFBD>ʼ״̬*/
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
e->state = 0;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] fmt - <EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] args - <EFBFBD>ɱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>б<EFBFBD>
|
|
||||||
*/
|
|
||||||
static void at_send_line(at_obj_t *at, const char *fmt, va_list args)
|
|
||||||
{
|
|
||||||
char buf[MAX_AT_CMD_LEN];
|
|
||||||
int len;
|
|
||||||
const at_adapter_t *adt = __get_adapter(at);
|
|
||||||
len = vsnprintf(buf, sizeof(buf), fmt, args);
|
|
||||||
|
|
||||||
recv_buf_clear(at); //<2F><><EFBFBD>ս<EFBFBD><D5BD>ջ<EFBFBD><D5BB><EFBFBD>
|
|
||||||
send_data(at, buf, len);
|
|
||||||
send_data(at, "\r\n", 2);
|
|
||||||
|
|
||||||
AT_DEBUG("->\r\n%s\r\n", buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief urc(unsolicited code) <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] urc - <EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] size - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
static void urc_handler_entry(at_obj_t *at, char *urc, unsigned int size)
|
|
||||||
{
|
|
||||||
int i, n;
|
|
||||||
utc_item_t *tbl = at->adap.utc_tbl;
|
|
||||||
for (i = 0; i < at->adap.urc_tbl_count; i++, tbl++) {
|
|
||||||
n = strlen(tbl->prefix);
|
|
||||||
if (strncmp(urc, tbl->prefix, n) == 0) { /* ƥ<><C6A5>ǰ */
|
|
||||||
tbl->handler(urc, size); /* <20>ص<EFBFBD><D8B5><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (at->cursor == NULL)
|
|
||||||
AT_DEBUG("<=\r\n%s\r\n", urc);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief urc <EFBFBD><EFBFBD><EFBFBD>մ<EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] buf - <EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
static void urc_recv_process(at_obj_t *at, char *buf, unsigned int size)
|
|
||||||
{
|
|
||||||
char *urc_buf;
|
|
||||||
int ch;
|
|
||||||
unsigned short urc_size;
|
|
||||||
urc_buf = (char *)at->adap.urc_buf;
|
|
||||||
urc_size = at->adap.urc_bufsize;
|
|
||||||
|
|
||||||
if (size == 0 && at->urc_cnt > 0) {
|
|
||||||
if (AT_IS_TIMEOUT(at->urc_timer, 2000)) { /* <20><><EFBFBD>ճ<EFBFBD>ʱ*/
|
|
||||||
urc_handler_entry(at, urc_buf, at->urc_cnt);
|
|
||||||
if (at->urc_cnt > 1)
|
|
||||||
AT_DEBUG("Urc recv timeout.\r\n");
|
|
||||||
at->urc_cnt = 0;
|
|
||||||
}
|
|
||||||
} else if (urc_buf != NULL){
|
|
||||||
at->urc_timer = AT_GET_TICK();
|
|
||||||
while (size--) {
|
|
||||||
ch = *buf++;
|
|
||||||
urc_buf[at->urc_cnt++] = ch;
|
|
||||||
if (ch == '\n' || ch == '\r' || ch == '\0') { /*urc<72><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
urc_buf[at->urc_cnt] = '\0';
|
|
||||||
if (at->urc_cnt > 2)
|
|
||||||
urc_handler_entry(at, urc_buf, at->urc_cnt);
|
|
||||||
at->urc_cnt = 0;
|
|
||||||
} else if (at->urc_cnt >= urc_size) /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
|
||||||
at->urc_cnt = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><EFBFBD><EFBFBD>մ<EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @return none
|
|
||||||
*/
|
|
||||||
static void resp_recv_process(at_obj_t *at, const char *buf, unsigned int size)
|
|
||||||
{
|
|
||||||
char *recv_buf;
|
|
||||||
unsigned short recv_size;
|
|
||||||
|
|
||||||
recv_buf = (char *)at->adap.recv_buf;
|
|
||||||
recv_size = at->adap.recv_bufsize;
|
|
||||||
|
|
||||||
if (at->recv_cnt + size >= recv_size) //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
at->recv_cnt = 0;
|
|
||||||
|
|
||||||
memcpy(recv_buf + at->recv_cnt, buf, size);
|
|
||||||
at->recv_cnt += size;
|
|
||||||
recv_buf[at->recv_cnt] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>
|
|
||||||
* @param[in] at - AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] adap - AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
void at_obj_init(at_obj_t *at, const at_adapter_t *adap)
|
|
||||||
{
|
|
||||||
int i;
|
|
||||||
at_env_t *e;
|
|
||||||
at->adap = *adap;
|
|
||||||
e = &at->env;
|
|
||||||
at->recv_cnt = 0;
|
|
||||||
|
|
||||||
e->is_timeout = at_is_timeout;
|
|
||||||
e->printf = print;
|
|
||||||
e->recvbuf = get_recv_buf;
|
|
||||||
e->recvclr = recv_buf_clear;
|
|
||||||
e->recvlen = get_recv_count;
|
|
||||||
e->find = search_string;
|
|
||||||
e->abort = at_isabort;
|
|
||||||
e->reset_timer = at_reset_timer;
|
|
||||||
|
|
||||||
/* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC>*/
|
|
||||||
INIT_LIST_HEAD(&at->ls_idle);
|
|
||||||
INIT_LIST_HEAD(&at->ls_ready);
|
|
||||||
|
|
||||||
for (i = 0; i < sizeof(at->items) / sizeof(at_item_t); i++)
|
|
||||||
list_add_tail(&at->items[i].node, &at->ls_idle);
|
|
||||||
|
|
||||||
while (adap->recv_buf == NULL) {} //ȷ<><C8B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD>ǿ<EFBFBD>
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ִ<EFBFBD><EFBFBD>AT<EFBFBD><EFBFBD>ҵ(<EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ)
|
|
||||||
* @param[in] a - AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] work - AT<EFBFBD><EFBFBD>ҵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] params -
|
|
||||||
*/
|
|
||||||
bool at_do_work(at_obj_t *at, int (*work)(at_env_t *e), void *params)
|
|
||||||
{
|
|
||||||
return add_work(at, params, (void *)work, AT_TYPE_WORK);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ִ<EFBFBD><EFBFBD>ATָ<EFBFBD><EFBFBD>
|
|
||||||
* @param[in] a - AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] cmd - cmd<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
bool at_do_cmd(at_obj_t *at, void *params, const at_cmd_t *cmd)
|
|
||||||
{
|
|
||||||
return add_work(at, params, (void *)cmd, AT_TYPE_CMD);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD>͵<EFBFBD><EFBFBD><EFBFBD>AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD>(Ĭ<EFBFBD>ϵȴ<EFBFBD>OK<EFBFBD><EFBFBD><EFBFBD><EFBFBD>, 3s<EFBFBD><EFBFBD>ʱ)
|
|
||||||
* @param[in] at - AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] cb - ִ<EFBFBD>лص<EFBFBD>
|
|
||||||
* @param[in] singlline - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @note <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֮ǰ,singlline<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч
|
|
||||||
*/
|
|
||||||
bool at_send_singlline(at_obj_t *at, at_callbatk_t cb, const char *singlline)
|
|
||||||
{
|
|
||||||
return add_work(at, (void *)singlline, (void *)cb, AT_TYPE_SINGLLINE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD><EFBFBD><EFBFBD>AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڳ<EFBFBD>ʼ<EFBFBD><EFBFBD>ģ<EFBFBD><EFBFBD>, Ĭ<EFBFBD>ϵȴ<EFBFBD>OK<EFBFBD><EFBFBD><EFBFBD><EFBFBD>, 3s<EFBFBD><EFBFBD>ʱ)
|
|
||||||
* @param[in] at - AT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @param[in] cb - ִ<EFBFBD>лص<EFBFBD>
|
|
||||||
* @param[in] multiline - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* @note <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֮ǰ,multiline
|
|
||||||
*/
|
|
||||||
bool at_send_multiline(at_obj_t *at, at_callbatk_t cb, const char **multiline)
|
|
||||||
{
|
|
||||||
return add_work(at, multiline, (void *)cb, AT_TYPE_MULTILINE);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ǿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֹAT<EFBFBD><EFBFBD>ҵ
|
|
||||||
*/
|
|
||||||
|
|
||||||
void at_item_abort(at_item_t *i)
|
|
||||||
{
|
|
||||||
i->abort = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief ATæ<EFBFBD>ж<EFBFBD>
|
|
||||||
* @return true - <EFBFBD><EFBFBD>ATָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
bool at_obj_busy(at_obj_t *at)
|
|
||||||
{
|
|
||||||
return !list_empty(&at->ls_ready);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief AT<EFBFBD><EFBFBD>ҵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static void at_work_manager(at_obj_t *at)
|
|
||||||
{
|
|
||||||
at_env_t *e = &at->env;
|
|
||||||
/*<2A><>ҵ<EFBFBD><D2B5><EFBFBD><EFBFBD><EFBFBD><EFBFBD> --------------------------------------------------------------*/
|
|
||||||
static int (*const work_handler_table[])(at_obj_t *) = {
|
|
||||||
do_work_handler,
|
|
||||||
do_cmd_handler,
|
|
||||||
send_multiline_handler,
|
|
||||||
send_signlline_handler
|
|
||||||
};
|
|
||||||
if (at->cursor == NULL) {
|
|
||||||
if (list_empty(&at->ls_ready)) //<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><CEAA>
|
|
||||||
return;
|
|
||||||
e->i = 0;
|
|
||||||
e->j = 0;
|
|
||||||
e->state = 0;
|
|
||||||
at->cursor = list_first_entry(&at->ls_ready, at_item_t, node);
|
|
||||||
e->params = at->cursor->param;
|
|
||||||
e->recvclr(at);
|
|
||||||
e->reset_timer(at);
|
|
||||||
}
|
|
||||||
/* <20><><EFBFBD><EFBFBD>ִ<EFBFBD><D6B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>뵽<EFBFBD><EBB5BD><EFBFBD>й<EFBFBD><D0B9><EFBFBD><EFBFBD><EFBFBD> -------------------------------------*/
|
|
||||||
if (work_handler_table[at->cursor->type](at) || at->cursor->abort) {
|
|
||||||
list_move_tail(&at->cursor->node, &at->ls_idle);
|
|
||||||
at->cursor = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief AT<EFBFBD><EFBFBD>ѯ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
void at_poll_task(at_obj_t *at)
|
|
||||||
{
|
|
||||||
char rbuf[32];
|
|
||||||
int read_size;
|
|
||||||
read_size = __get_adapter(at)->read(rbuf, sizeof(rbuf));
|
|
||||||
urc_recv_process(at, rbuf, read_size);
|
|
||||||
resp_recv_process(at, rbuf, read_size);
|
|
||||||
at_work_manager(at);
|
|
||||||
}
|
|
148
at_chat.h
@ -1,148 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
* @brief ATָ<EFBFBD><EFBFBD>ͨ<EFBFBD>Ź<EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020~2021, <morro_luo@163.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apathe-2.0
|
|
||||||
*
|
|
||||||
* Change Logs:
|
|
||||||
* Date Author Notes
|
|
||||||
* 2020-01-02 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* 2021-01-20 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD>debug<EFBFBD><EFBFBD><EFBFBD>Խӿ<EFBFBD>, <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
* <EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƚӿ<EFBFBD>
|
|
||||||
* 2021-03-03 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>URC<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӡ<EFBFBD><EFBFBD><EFBFBD>ճ<EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
#ifndef _ATCHAT_H_
|
|
||||||
#define _ATCHAT_H_
|
|
||||||
|
|
||||||
#include <list.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
|
|
||||||
/*<2A><><EFBFBD><EFBFBD>AT<41><54><EFBFBD><EFBFBD><EEB3A4> --------------------------------------------------------------*/
|
|
||||||
#define MAX_AT_CMD_LEN 128
|
|
||||||
|
|
||||||
/* debug <20><>ӡ<EFBFBD>ӿ<EFBFBD> ------------------------------------------------------------*/
|
|
||||||
#include <stdio.h>
|
|
||||||
#define AT_DEBUG(...) printf("[AT]:");printf(__VA_ARGS__) /*do{}while(0)*/
|
|
||||||
|
|
||||||
/* <20><>ȡϵͳ<CFB5>δ<EFBFBD>(ms) -----------------------------------------------------------*/
|
|
||||||
#include "platform.h"
|
|
||||||
#define AT_GET_TICK() get_tick()
|
|
||||||
|
|
||||||
struct at_obj;
|
|
||||||
|
|
||||||
/*urc<72><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD> -----------------------------------------------------------------*/
|
|
||||||
typedef struct {
|
|
||||||
const char *prefix; //<2F><>Ҫƥ<D2AA><C6A5><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7>
|
|
||||||
void (*handler)(char *recvbuf, int size);
|
|
||||||
}utc_item_t;
|
|
||||||
|
|
||||||
/*AT<41>ӿ<EFBFBD><D3BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ---------------------------------------------------------------*/
|
|
||||||
typedef struct {
|
|
||||||
unsigned int (*write)(const void *buf, unsigned int len); /* <20><><EFBFBD>ͽӿ<CDBD>*/
|
|
||||||
unsigned int (*read)(void *buf, unsigned int len); /* <20><><EFBFBD>սӿ<D5BD>*/
|
|
||||||
void (*error)(void); /* ATִ<54><D6B4><EFBFBD>쳣<EFBFBD>¼<EFBFBD>*/
|
|
||||||
utc_item_t *utc_tbl; /* urc <20><>*/
|
|
||||||
unsigned char *urc_buf; /* urc<72><63><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
unsigned char *recv_buf; /* <20><><EFBFBD>ݻ<EFBFBD><DDBB><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
unsigned short urc_tbl_count; /* urc<72><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
unsigned short urc_bufsize; /* urc<72><63><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С*/
|
|
||||||
unsigned short recv_bufsize; /* <20><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>С*/
|
|
||||||
}at_adapter_t;
|
|
||||||
|
|
||||||
/*AT<41><54>ҵ<EFBFBD><D2B5><EFBFBD>л<EFBFBD><D0BB><EFBFBD>*/
|
|
||||||
typedef struct {
|
|
||||||
int i,j,state;
|
|
||||||
void *params;
|
|
||||||
void (*reset_timer)(struct at_obj *at);
|
|
||||||
bool (*is_timeout)(struct at_obj *at, unsigned int ms); /*ʱ<><CAB1><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>*/
|
|
||||||
void (*printf)(struct at_obj *at, const char *fmt, ...);
|
|
||||||
char * (*find)(struct at_obj *at, const char *expect);
|
|
||||||
char * (*recvbuf)(struct at_obj *at); /* ָ<><D6B8><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
unsigned int(*recvlen)(struct at_obj *at); /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ܳ<EFBFBD><DCB3><EFBFBD>*/
|
|
||||||
void (*recvclr)(struct at_obj *at); /* <20><><EFBFBD>ս<EFBFBD><D5BD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
bool (*abort)(struct at_obj *at); /* <20><>ִֹ<D6B9><D6B4>*/
|
|
||||||
}at_env_t;
|
|
||||||
|
|
||||||
/*AT<41><54><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6>*/
|
|
||||||
typedef enum {
|
|
||||||
AT_RET_OK = 0, /* ִ<>гɹ<D0B3>*/
|
|
||||||
AT_RET_ERROR, /* ִ<>д<EFBFBD><D0B4><EFBFBD>*/
|
|
||||||
AT_RET_TIMEOUT, /* <20><>Ӧ<EFBFBD><D3A6>ʱ*/
|
|
||||||
AT_RET_ABORT, /* ǿ<><C7BF><EFBFBD><EFBFBD>ֹ*/
|
|
||||||
}at_return;
|
|
||||||
|
|
||||||
/*AT<41><54>Ӧ */
|
|
||||||
typedef struct {
|
|
||||||
void *param;
|
|
||||||
char *recvbuf; /* <20><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
unsigned short recvcnt; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݳ<EFBFBD><DDB3><EFBFBD>*/
|
|
||||||
at_return ret; /* ATִ<54>н<EFBFBD><D0BD><EFBFBD>*/
|
|
||||||
}at_response_t;
|
|
||||||
|
|
||||||
typedef void (*at_callbatk_t)(at_response_t *r); /* AT ִ<>лص<D0BB>*/
|
|
||||||
|
|
||||||
/*AT״̬ (<28><>ǰ<EFBFBD>汾δ<E6B1BE><CEB4>) ------------------------------------------------------*/
|
|
||||||
typedef enum {
|
|
||||||
AT_STATE_IDLE, /* <20><><EFBFBD><EFBFBD>״̬*/
|
|
||||||
AT_STATE_WAIT, /* <20>ȴ<EFBFBD>ִ<EFBFBD><D6B4>*/
|
|
||||||
AT_STATE_EXEC, /* <20><><EFBFBD><EFBFBD>ִ<EFBFBD><D6B4>*/
|
|
||||||
}at_work_state;
|
|
||||||
|
|
||||||
/*AT<41><54>ҵ<EFBFBD><D2B5>*/
|
|
||||||
typedef struct {
|
|
||||||
unsigned int state : 3;
|
|
||||||
unsigned int type : 3; /* <20><>ҵ<EFBFBD><D2B5><EFBFBD><EFBFBD>*/
|
|
||||||
unsigned int abort : 1;
|
|
||||||
void *param; /* ͨ<>ò<EFBFBD><C3B2><EFBFBD>*/
|
|
||||||
void *info; /* ͨ<><CDA8><EFBFBD><EFBFBD>Ϣָ<CFA2><D6B8>*/
|
|
||||||
struct list_head node; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
}at_item_t;
|
|
||||||
|
|
||||||
/*AT<41><54><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ------------------------------------------------------------------*/
|
|
||||||
typedef struct at_obj{
|
|
||||||
at_adapter_t adap;
|
|
||||||
at_env_t env; /* <20><>ҵ<EFBFBD><D2B5><EFBFBD>л<EFBFBD><D0BB><EFBFBD>*/
|
|
||||||
at_item_t items[10]; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>10<31><30><EFBFBD><EFBFBD>ҵ*/
|
|
||||||
at_item_t *cursor; /* <20><>ǰ<EFBFBD><C7B0>ҵ<EFBFBD><D2B5>*/
|
|
||||||
struct list_head ls_ready, ls_idle; /* <20><><EFBFBD><EFBFBD>,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҵ<EFBFBD><D2B5>*/
|
|
||||||
unsigned int timer;
|
|
||||||
unsigned int urc_timer; /* urc<72><63><EFBFBD>ռ<EFBFBD>ʱ<EFBFBD><CAB1>*/
|
|
||||||
at_return ret;
|
|
||||||
//urc<72><63><EFBFBD>ռ<EFBFBD><D5BC><EFBFBD>, <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ӧ<EFBFBD><D3A6><EFBFBD>ռ<EFBFBD><D5BC><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
unsigned short urc_cnt, recv_cnt;
|
|
||||||
unsigned char suspend: 1;
|
|
||||||
}at_obj_t;
|
|
||||||
|
|
||||||
typedef struct {
|
|
||||||
void (*sender)(at_env_t *e); /*<2A>Զ<EFBFBD><D4B6>巢<EFBFBD><E5B7A2><EFBFBD><EFBFBD> */
|
|
||||||
const char *matcher; /*<2A><><EFBFBD><EFBFBD>ƥ<EFBFBD>䴮 */
|
|
||||||
at_callbatk_t cb; /*<2A><>Ӧ<EFBFBD><D3A6><EFBFBD><EFBFBD> */
|
|
||||||
unsigned char retry; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><D4B4><EFBFBD> */
|
|
||||||
unsigned short timeout; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱʱ<CAB1><CAB1> */
|
|
||||||
}at_cmd_t;
|
|
||||||
|
|
||||||
void at_obj_init(at_obj_t *at, const at_adapter_t *);
|
|
||||||
|
|
||||||
bool at_send_singlline(at_obj_t *at, at_callbatk_t cb, const char *singlline);
|
|
||||||
|
|
||||||
bool at_send_multiline(at_obj_t *at, at_callbatk_t cb, const char **multiline);
|
|
||||||
|
|
||||||
bool at_do_cmd(at_obj_t *at, void *params, const at_cmd_t *cmd);
|
|
||||||
|
|
||||||
bool at_do_work(at_obj_t *at, int (*work)(at_env_t *e), void *params);
|
|
||||||
|
|
||||||
void at_item_abort(at_item_t *it); /*<2A><>ֹ<EFBFBD><D6B9>ǰ<EFBFBD><C7B0>ҵ*/
|
|
||||||
|
|
||||||
bool at_obj_busy(at_obj_t *at); /*æ<>ж<EFBFBD>*/
|
|
||||||
|
|
||||||
void at_suspend(at_obj_t *at);
|
|
||||||
|
|
||||||
void at_resume(at_obj_t *at);
|
|
||||||
|
|
||||||
void at_poll_task(at_obj_t *at);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
82
at_util.h
@ -1,82 +0,0 @@
|
|||||||
/******************************************************************************
|
|
||||||
* @brief atģ<EFBFBD><EFBFBD>OS<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֲ<EFBFBD>ӿ<EFBFBD>
|
|
||||||
*
|
|
||||||
* Copyright (c) 2020, <morro_luo@163.com>
|
|
||||||
*
|
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
|
||||||
*
|
|
||||||
* Change Logs:
|
|
||||||
* Date Author Notes
|
|
||||||
* 2020-01-02 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
******************************************************************************/
|
|
||||||
|
|
||||||
#ifndef _ATUTIL_H_
|
|
||||||
#define _ATUTIL_H_
|
|
||||||
|
|
||||||
#include <stdint.h>
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stddef.h>
|
|
||||||
|
|
||||||
typedef void *at_sem_t; /*<2A>ź<EFBFBD><C5BA><EFBFBD>*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD>ǰϵͳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
|
||||||
*/
|
|
||||||
static inline unsigned int at_get_ms(void)
|
|
||||||
{
|
|
||||||
/*Add here...*/
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* @brief <EFBFBD><EFBFBD>ʱ<EFBFBD>ж<EFBFBD>
|
|
||||||
* @retval true | false
|
|
||||||
*/
|
|
||||||
static inline bool at_istimeout(unsigned int start_time, unsigned int timeout)
|
|
||||||
{
|
|
||||||
return at_get_ms() - start_time > timeout;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ
|
|
||||||
* @retval none
|
|
||||||
*/
|
|
||||||
static inline void at_delay(uint32_t ms)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ź<EFBFBD>
|
|
||||||
* @retval none
|
|
||||||
*/
|
|
||||||
static inline at_sem_t at_sem_new(int value)
|
|
||||||
{
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
/*
|
|
||||||
* @brief <EFBFBD>ȴ<EFBFBD><EFBFBD>ź<EFBFBD>
|
|
||||||
* @retval none
|
|
||||||
*/
|
|
||||||
static inline bool at_sem_wait(at_sem_t s, uint32_t timeout)
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief <EFBFBD>ͷ<EFBFBD><EFBFBD>ź<EFBFBD>
|
|
||||||
* @retval none
|
|
||||||
*/
|
|
||||||
static inline void at_sem_post(at_sem_t s)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD>ٵ<EFBFBD><EFBFBD>ź<EFBFBD>
|
|
||||||
* @retval none
|
|
||||||
*/
|
|
||||||
static inline void at_sem_free(at_sem_t s)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
0
docs/.nojekyll
Normal file
553
docs/Expert.md
Normal file
@ -0,0 +1,553 @@
|
|||||||
|
# 高级教程
|
||||||
|
|
||||||
|
了解完一般命令处理之后,下面我们来讲一下一些特殊场景下的AT命令请求及其处理方式,以及了解处理这些请求涉及到的相关概念和接口,同时我也会详细说明有关URC消息处理办法和在OS上的应用。
|
||||||
|
|
||||||
|
本节导读如下:
|
||||||
|
- 组合命令处理
|
||||||
|
- 自定义AT作业
|
||||||
|
- URC消息处理
|
||||||
|
- 多实例并存
|
||||||
|
- AT作业上下文
|
||||||
|
- OS应用之异步转同步
|
||||||
|
- 内存监视器
|
||||||
|
|
||||||
|
## 组合命令处理
|
||||||
|
|
||||||
|
在一些场景下,主机与从机之前间需要通过组合命令来交换信息,即主机与从机间完成一次业务需要进行多次命令交互,例如sms收发,socket数据收发,不同模组产商命令可能是不一样的,下面是几个组合命令的例子。
|
||||||
|
|
||||||
|
发送短信流程(参考SIM900A模组):
|
||||||
|
|
||||||
|
```shell
|
||||||
|
主机 =>
|
||||||
|
AT+CMGS=<Phone numer> + \x1A //发送目标手机号+ctrl+z
|
||||||
|
从机 <=
|
||||||
|
'<' //从机回复提示符'<'
|
||||||
|
主机 =>
|
||||||
|
<sms message> //发送短信内容
|
||||||
|
从机 <=
|
||||||
|
OK //从机回复OK
|
||||||
|
```
|
||||||
|
|
||||||
|
发送Socket数据流程(参考移远EC21模组):
|
||||||
|
```shell
|
||||||
|
主机 =>
|
||||||
|
AT+QISEND=<connectID>,<send_length>
|
||||||
|
从机 <=
|
||||||
|
'<' //从机回复提示符'<'
|
||||||
|
主机 =>
|
||||||
|
<data> //发送二进制数据内容
|
||||||
|
\x1A //发送CTRL+z启动发送
|
||||||
|
从机 <=
|
||||||
|
OK //从机回复OK
|
||||||
|
```
|
||||||
|
|
||||||
|
发送TCP Socket数据流程(参考Sierra 模组):
|
||||||
|
```shell
|
||||||
|
主机 =>
|
||||||
|
AT+KTCPSND=<session>,<send_length>
|
||||||
|
从机 <=
|
||||||
|
'CONNECT' //从机回复提示符'CONNECT'
|
||||||
|
主机 =>
|
||||||
|
<data> //发送二进制数据内容
|
||||||
|
"--EOF--Pattern--"" //发送结束符
|
||||||
|
从机 <=
|
||||||
|
OK //从机回复OK
|
||||||
|
```
|
||||||
|
|
||||||
|
接收TCP Socket数据(参考Sierra 模组):
|
||||||
|
```shell
|
||||||
|
主机 =>
|
||||||
|
AT+KTCPRCV=<session_id>,<recv_length>
|
||||||
|
从机 <=
|
||||||
|
'CONNECT' //从机回复提示符'CONNECT'
|
||||||
|
<data> //二进制数据内容
|
||||||
|
"--EOF--Pattern--"" //结束符
|
||||||
|
OK //状态码
|
||||||
|
```
|
||||||
|
|
||||||
|
组合命令与一般AT命令最大的不同体现在命令交互的流程结构上,它们进行一次通信(数据)业务时需要交互2次或多次以上,所以软件设计需要考虑并发冲突的可能,因为在进行某项业务交互时如果需要进行两次AT命令请求才能完成,有可能在进行第一次时过程中就被其它命令穿插打断了,从而造成该项业务执行失败。
|
||||||
|
|
||||||
|
|
||||||
|
对于这个问题,除了利用OS的锁解决之外,还可以利用自定义作业来处理,它允许你在一个AT作业中进行多次命令交互,同时能够让应用层自行控制命令收发流程。
|
||||||
|
|
||||||
|
## 自定义AT作业
|
||||||
|
|
||||||
|
自定义AT作业使用`at_work_t`表示,它实际是一个状态机轮询程序,通过'at_env_t'参数提供了基本的状态变量,数据收发,超时管理等接口。除了能用来收发命令之外,你甚至可以用它来控制硬件IO,例如有时序控制要求开关机操作,这样做也有利于处理设备状态同步的问题。
|
||||||
|
|
||||||
|
**原型定义如下:**
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
*@brief AT作业轮询处理程序
|
||||||
|
*@param env AT作业的公共运行环境,包括一些通用的变量和进行AT命令通信所需的相关接口。
|
||||||
|
*@return 作业处理状态, 它决定了是否在下一个循环中是否继续运行该作业。
|
||||||
|
* @arg true 指示当前作业已经处理完成,可以被中止,同时作业的状态码会被设置为AT_RESP_OK。
|
||||||
|
* @arg false 指示当前作业未处理完成,继续运行。
|
||||||
|
*@note 需要注意的是,如果在当前作业中执行了env->finish()操作,则作业立即终止运行。
|
||||||
|
*/
|
||||||
|
typedef int (*at_work_t)(at_env_t *env);
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
其中:
|
||||||
|
`at_env_t` 定义了一些通信上下文环境相关接口与公共状态变量,通过它你可以实现自己的通信交互逻辑。
|
||||||
|
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief AT作业公共运行环境
|
||||||
|
*/
|
||||||
|
typedef struct at_env {
|
||||||
|
struct at_obj *obj;
|
||||||
|
//公共状态(根据需要添加),每次新作业启动时,这些值会被重置
|
||||||
|
int i, j, state;
|
||||||
|
//附属参数(引用自->at_attr_t)
|
||||||
|
void *params;
|
||||||
|
//设置下一个轮询等待间隔(只生效1次)
|
||||||
|
void (*next_wait)(struct at_env *self, unsigned int ms);
|
||||||
|
//复位计时器
|
||||||
|
void (*reset_timer)(struct at_env *self);
|
||||||
|
//作业超时判断
|
||||||
|
bool (*is_timeout)(struct at_env *self, unsigned int ms);
|
||||||
|
//带换行的格式化打印输出
|
||||||
|
void (*println)(struct at_env *self, const char *fmt, ...);
|
||||||
|
//接收内容包含判断
|
||||||
|
char * (*contains)(struct at_env *self, const char *str);
|
||||||
|
//获取接收缓冲区
|
||||||
|
char * (*recvbuf)(struct at_env *self);
|
||||||
|
//获取接收缓冲区长度
|
||||||
|
unsigned int(*recvlen)(struct at_env *self);
|
||||||
|
//清空接收缓冲区
|
||||||
|
void (*recvclr)(struct at_env *self);
|
||||||
|
//指示当前作业是否已被强行终止
|
||||||
|
bool (*disposing)(struct at_env *self);
|
||||||
|
//结束作业,并设置响应码
|
||||||
|
void (*finish)(struct at_env *self, at_resp_code code);
|
||||||
|
} at_env_t;
|
||||||
|
```
|
||||||
|
|
||||||
|
**示例1:(Sierra 模组发送socket数据)**
|
||||||
|
|
||||||
|
命令格式:
|
||||||
|
```shell
|
||||||
|
主机 =>
|
||||||
|
AT+KTCPSND=<session>,<send_length>
|
||||||
|
从机 <=
|
||||||
|
'CONNECT' //从机回复提示符'CONNECT'
|
||||||
|
主机 =>
|
||||||
|
<data> //发送二进制数据内容
|
||||||
|
"--EOF--Pattern--"" //发送结束符
|
||||||
|
从机 <=
|
||||||
|
OK //从机回复OK
|
||||||
|
```
|
||||||
|
**代码实现:**
|
||||||
|
```c
|
||||||
|
|
||||||
|
//socket定义
|
||||||
|
typedef struct {
|
||||||
|
//....
|
||||||
|
int id;
|
||||||
|
unsigned char *sendptr;
|
||||||
|
int sendcnt;
|
||||||
|
//...
|
||||||
|
}socket_t;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief socket 数据发送处理
|
||||||
|
* @return true - 结束运行 false - 保持运行
|
||||||
|
*/
|
||||||
|
static int socket_send_handler(at_env_t *env)
|
||||||
|
{
|
||||||
|
socket_t *sk = (socket_t *)env->params;
|
||||||
|
switch (env->state) {
|
||||||
|
case 0:
|
||||||
|
env->println(env, "AT+KTCPSND=%d,%d", sk->id, sk->sendcnt);
|
||||||
|
env->reset_timer(env); /*重置定时器*/
|
||||||
|
env->state++;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (env->contains(env, "CONNECT")) {
|
||||||
|
env->obj->adap->write(sk->sendptr, sk->sendcnt); /*发送数据*/
|
||||||
|
env->println(env, "--EOF--Pattern--"); /*发送结束符*/
|
||||||
|
env->reset_timer(env);
|
||||||
|
env->recvclr(env);
|
||||||
|
env->state++;
|
||||||
|
} else if (env->contains(env, "ERROR")) { /*匹配到错误,结束作业*/
|
||||||
|
env->finish(env, AT_RESP_ERROR);
|
||||||
|
} else if (env->is_timeout(env, 1000)) {
|
||||||
|
if (++env->i > 3) {
|
||||||
|
env->finish(env, AT_RESP_ERROR);
|
||||||
|
}
|
||||||
|
env->state--; /*重新发送*/
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (env->contains(env, "OK"))
|
||||||
|
env->finish(env, AT_RESP_OK); /*发送成功,设置状态为OK后退出*/
|
||||||
|
else if (env->contains(env, "ERROR") ||
|
||||||
|
env->is_timeout(env, 1000)) {
|
||||||
|
env->finish(env, AT_RESP_ERROR);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief socket数据发送请求
|
||||||
|
*/
|
||||||
|
static void sock_send_data(socket_t *sock)
|
||||||
|
{
|
||||||
|
at_do_work(at_obj, sock, socket_send_handler);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## URC消息处理
|
||||||
|
|
||||||
|
未经请求主动上报的消息,又称URC(Unsolicited Result Code),在主机方未下发送命令请求的情况下,设备会根据自身的运行状态或者事件主动上报消息给主机。
|
||||||
|
|
||||||
|
根据URC消息格式的不同,可以分为以下几类:
|
||||||
|
1. 对于大多数URC消息,通常是单行输出的,一般是以“+”为前缀,回车换行结束,例如:
|
||||||
|
|
||||||
|
|
||||||
|
```c
|
||||||
|
+SIM: 1 \r\n //SIM卡状态
|
||||||
|
|
||||||
|
+CREG: 1,"24A4","000012CF",1\r\n //网络注册状态更新
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
2. 也有不带前缀'+'的URC:
|
||||||
|
|
||||||
|
```c
|
||||||
|
RDY \r\n //开机就绪
|
||||||
|
```
|
||||||
|
|
||||||
|
```c
|
||||||
|
WIFI DISCONNECTED //WIFI断开
|
||||||
|
```
|
||||||
|
|
||||||
|
3. 非回车换行结束的URC
|
||||||
|
|
||||||
|
socket数据接收(参考sim800 模组)。
|
||||||
|
|
||||||
|
```c
|
||||||
|
+IPD,<socket id>,<data length>:<bin data>
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
可以看到,每个URC消息都有其特定的前缀信息,前两类是以'\n'作为结束符的,最后一种只有前缀,而整个URC消息帧是可变长度的,没有特定的结束符。那么该如何将这几类消息识别并提取出来的呢?实际上URC处理程序也是通过匹配"前缀"+"结束符"的方式来提取URC消息的,对于前两种消息,它们都有特定的结束符('\n'),只要匹配到消息"前缀"+"后缀"就可以将整条消息完整的提取出来;而对于最后一种消息,由于没有固定的结束符,而且消息长度是可变的,所以URC处理程序无法一次性将整条消息匹配并提取出来,往往需要分成多次进行,第一次是匹配它的头部信息,然后再由订阅者(通过回调)告诉它剩余待接收的数据长度,当剩余数据长度为0时,则该则URC消息接收完毕。这种处理方法其实同样也适用于前两类URC,不过这些消息的剩余数据长度为0罢了。
|
||||||
|
|
||||||
|
如下所示,我们可以把第3类URC消息拆分成两部分看待,固定头部+剩余数据。
|
||||||
|
|
||||||
|
![带二进制URC消息](images/urcbin.png)
|
||||||
|
|
||||||
|
由于URC具有一定的随机性,所以URC处理程序会实时读取来自设备端的上报的信息,然后再进行消息匹配处理。至于匹配哪种URC消息,则是由用户通过`at_obj_set_urc`设置的表来决定的。另外,考虑到性能的原因,URC处理程序不会一接收到任何一个字符都会启动匹配程序工作,而是遇到`AT_URC_END_MARKS`中规定的字符才会触发执行。
|
||||||
|
|
||||||
|
下面是`at_obj_set_urc`原型:
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief Set the AT urc table.
|
||||||
|
*/
|
||||||
|
void at_obj_set_urc(at_obj_t *at, const urc_item_t *tbl, int count);
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### URC处理项(urc_item_t)
|
||||||
|
|
||||||
|
URC表的基本单位是`urc_item_t`,它用于描述每一条URC消息的处理规则,包括了消息头,结束标志还有该消息的处理程序。
|
||||||
|
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief urc处理项
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
const char *prefix; /* 需要匹配的帧前缀,如+CSQ:25,*/
|
||||||
|
const char endmark; /* urc结束标志(参考@AT_URC_END_MARKS*/
|
||||||
|
/**
|
||||||
|
* @brief urc处理程序(prefix与endmark满足时触发)
|
||||||
|
* @params ctx - 上下文(Context)
|
||||||
|
* @return 表示当前URC帧剩余未接收字节数
|
||||||
|
* @arg 0 当前URC帧已接收完成,可以接收下一个URC
|
||||||
|
* @arg n 仍需要等待接收n个字节(AT管理器继续接收剩余数据并继续回调此接口)
|
||||||
|
*/
|
||||||
|
int (*handler)(at_urc_ctx_t *ctx);
|
||||||
|
} urc_item_t;
|
||||||
|
|
||||||
|
```
|
||||||
|
其中`at_urc_ctx_t`存储URC的接收状态和数据。
|
||||||
|
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief URC 上下文(Context) 定义
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
urc_recv_state state; /* urc接收状态*/
|
||||||
|
char *urcbuf; /* urc数据缓冲区 */
|
||||||
|
int urclen; /* urc缓冲区已接收数据长度*/
|
||||||
|
} at_urc_ctx_t;
|
||||||
|
```
|
||||||
|
|
||||||
|
**示例1(WIFI断开连接):**
|
||||||
|
|
||||||
|
消息格式:
|
||||||
|
```c
|
||||||
|
WIFI DISCONNECTED <\r\n>
|
||||||
|
```
|
||||||
|
代码实现:
|
||||||
|
```c
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief wifi断开事件
|
||||||
|
*/
|
||||||
|
static int wifi_connected_handler(at_urc_info_t *info)
|
||||||
|
{
|
||||||
|
printf("WIFI connection detected...\r\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
//...
|
||||||
|
/**
|
||||||
|
* @brief urc订阅表
|
||||||
|
*/
|
||||||
|
static const urc_item_t urc_table[] =
|
||||||
|
{
|
||||||
|
//其它URC...
|
||||||
|
{.prefix = "WIFI DISCONNECTED", .endmark = '\n', .handler = wifi_connected_handler}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
**示例2(socket数据接收):**
|
||||||
|
|
||||||
|
URC消息格式:
|
||||||
|
```c
|
||||||
|
+IPD,<socket id>,<data length>:.....
|
||||||
|
```
|
||||||
|
代码实现:
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief socket数据接收处理
|
||||||
|
*/
|
||||||
|
static int urc_socket_data_handler(at_urc_info_t *ctx)
|
||||||
|
{
|
||||||
|
int length, total_length, sockid, i;
|
||||||
|
char *data;
|
||||||
|
if (sscanf(ctx->urcbuf, "+IPD,%d,%d:", &sockid, &length) == 2) { //解析出总数据长度
|
||||||
|
data = strchr(ctx->urcbuf, ':');
|
||||||
|
if (data == NULL)
|
||||||
|
return 0;
|
||||||
|
data++;
|
||||||
|
total_length = (data - ctx->urcbuf) + length; //计算头部长度
|
||||||
|
if (ctx->urclen < total_length) { //未接收全,返回剩余待接收数据
|
||||||
|
printf("Need to receive %d more bytes\r\n", total_length - ctx->urclen);
|
||||||
|
return total_length - ctx->urclen;
|
||||||
|
}
|
||||||
|
printf("%d bytes of data were received form socket %d!\r\n", length, sockid);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//....
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief urc订阅表
|
||||||
|
*/
|
||||||
|
static const urc_item_t urc_table[] =
|
||||||
|
{
|
||||||
|
//其它URC...
|
||||||
|
{.prefix = "+IPD,", .endmark = ':', .handler = urc_socket_data_handler}
|
||||||
|
};
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
## 多实例并存
|
||||||
|
|
||||||
|
AT通信对象并不只限于一个, at_obj_create允许你在同一个系统中创建多个共存的AT通信设备,而且每个都拥有自己独立的用于配置和资源.
|
||||||
|
|
||||||
|
```c
|
||||||
|
|
||||||
|
//wifi 适配器
|
||||||
|
const at_adapter_t adap_wifi = {
|
||||||
|
//...
|
||||||
|
};
|
||||||
|
|
||||||
|
//modem适配器
|
||||||
|
const at_adapter_t adap_modem = {
|
||||||
|
//...
|
||||||
|
};
|
||||||
|
|
||||||
|
//...
|
||||||
|
at_obj_t *at_modem = at_obj_create(&modem_adapter);
|
||||||
|
|
||||||
|
at_obj_t *at_wifi = at_obj_create(&wifi_adapter);
|
||||||
|
|
||||||
|
//...
|
||||||
|
|
||||||
|
//轮询任务
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief AT轮询程序
|
||||||
|
*/
|
||||||
|
void at_device_process(void)
|
||||||
|
{
|
||||||
|
static unsigned int timer = 0;
|
||||||
|
//(为了加快AT命令处理响应速度,建议5ms以内轮询一次)
|
||||||
|
if (at_get_ms() - timer > 5) {
|
||||||
|
timer = at_get_ms();
|
||||||
|
at_obj_process(at_modem);
|
||||||
|
at_obj_process(at_wifi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
## AT作业上下文(at_context_t)
|
||||||
|
|
||||||
|
使用异步的一个弊端是它会让程序执行状态过于分散,增加程序编码和理解难度。比如一些代码需要根据异步的结果来执行下一步动作,一般是在异步回调中添加对应的状态标识,然后主程序根据这些状态标识来控制状态机或者程序分支的跳转,这使得代码间没有明显的流程线,代码执行流不好追踪管理。那么,在不使用同步或者不支持OS的情况下,如何避免异步带来的状态分散问题? 一种比较常用的方式是使用状态机轮询法,通过实时查询每一个异步请求的状态,并根据根据上一个结果执行下一个请求,这样代码执行上下文就紧密衔接在一块了,达到类似同步的效果。
|
||||||
|
|
||||||
|
对于异步AT请求,可以使用`at_context_t`获取其实时信息,包含当前的作业运行状态,命令执行结果及命令响应信息。使用AT上下文相关功能需要先启用`AT_WORK_CONTEXT_EN`宏, 相关API定义如下:
|
||||||
|
|
||||||
|
| 函数原型 | 说明 |
|
||||||
|
| ------------------------------------------------------------ | ------------------------------------------------ |
|
||||||
|
| void at_context_init(at_context_t *ctx, void *respbuf, unsigned bufsize); | 初始化一个`at_context_t`同时设置命令接收缓冲区。 |
|
||||||
|
| void at_context_attach(at_attr_t *attr, at_context_t *ctx); | 将`at_context_t`绑定到AT属性中。 |
|
||||||
|
| at_work_state at_work_get_state(at_context_t *ctx); | 通过`at_context_t`获取AT作业运行状态。 |
|
||||||
|
| bool at_work_is_finish(at_context_t *ctx); | 通过`at_context_t`获取AT作业完成状态。 |
|
||||||
|
| at_resp_code at_work_get_result(at_context_t *ctx); | 通过`at_context_t`获取AT请求状态码。 |
|
||||||
|
|
||||||
|
## OS应用之异步转同步
|
||||||
|
|
||||||
|
如果是在OS环境下使用,很多时候我们更希望采用同步的方式执行AT命令请求,即原地等待命令执行完成,下面介绍两种异步转同步的方式。
|
||||||
|
### 轮询方式
|
||||||
|
|
||||||
|
轮询方式主要是基于`at_context_t`实现的,发送请求前通过绑定一个`at_context_t`实时监视命令的执行状态,然后循环检测命令是否执行完成。
|
||||||
|
|
||||||
|
示例:
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief 发送命令(同步方式)
|
||||||
|
* @param respbuf 响应缓冲区
|
||||||
|
* @param bufsize 缓冲区大小
|
||||||
|
* @param timeout 超时时间
|
||||||
|
* @param cmd 命令
|
||||||
|
* @retval 命令执行状态
|
||||||
|
*/
|
||||||
|
static at_resp_code at_send_cmd_sync(char *respbuf, int bufsize, int timeout, const char *cmd, ...)
|
||||||
|
{
|
||||||
|
at_attr_t attr;
|
||||||
|
at_context_t ctx;
|
||||||
|
va_list args;
|
||||||
|
bool ret;
|
||||||
|
//属性初始化
|
||||||
|
at_attr_deinit(&attr);
|
||||||
|
attr.timeout = timeout;
|
||||||
|
attr.retry = 1;
|
||||||
|
//初始化context,并设置响应缓冲区
|
||||||
|
at_context_init(&ctx, respbuf, bufsize);
|
||||||
|
//为工作项绑定context
|
||||||
|
at_context_attach(&attr, &ctx);
|
||||||
|
|
||||||
|
va_start(args, cmd);
|
||||||
|
ret = at_exec_vcmd(at_obj, &attr, cmd, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
if (!ret) {
|
||||||
|
return AT_RESP_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
//等待命令执行完毕
|
||||||
|
while (!at_work_is_finish(&ctx)) {
|
||||||
|
usleep(1000);
|
||||||
|
}
|
||||||
|
return at_work_get_result(&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### 信号量方式
|
||||||
|
|
||||||
|
使用轮询方式会造成CPU空转,可以通过使用信号量来优化,不过实现起来比轮询方式要稍微复杂一些,
|
||||||
|
|
||||||
|
示例:
|
||||||
|
```c
|
||||||
|
//...
|
||||||
|
#include "at_chat.h"
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <semaphore.h>
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
pthread_mutex_t cmd_lock; //命令锁
|
||||||
|
sem_t sem_finish; //完成信号
|
||||||
|
char *recvbuf; //命令接收缓冲区
|
||||||
|
unsigned short bufsize; //缓冲区大小
|
||||||
|
unsigned short recvcnt; //接收计数器
|
||||||
|
at_resp_code resp_code; //命令响应码
|
||||||
|
} at_watch_t;
|
||||||
|
|
||||||
|
static at_watch_t at_watch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 命令锁及信号相关初始化
|
||||||
|
*/
|
||||||
|
void at_sync_init(void)
|
||||||
|
{
|
||||||
|
sem_init(&at_watch.sem_finish, 0, 0);
|
||||||
|
pthread_mutex_init(&at_watch.cmd_lock, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief AT命令响应处理
|
||||||
|
*/
|
||||||
|
static void at_callback_handler(at_response_t *r)
|
||||||
|
{
|
||||||
|
int cnt = r->recvcnt;
|
||||||
|
at_watch.resp_code = r->code;
|
||||||
|
if (at_watch.recvbuf != NULL) {
|
||||||
|
if (cnt > at_watch.bufsize) {
|
||||||
|
//接收缓存不足
|
||||||
|
cnt = at_watch.bufsize;
|
||||||
|
}
|
||||||
|
memcpy(at_watch.recvbuf, r->recvbuf, cnt);
|
||||||
|
at_watch.recvcnt = cnt;
|
||||||
|
}
|
||||||
|
//通知命令已执行完毕
|
||||||
|
sem_post(&at_watch.sem_finish);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 发送命令(同步方式)
|
||||||
|
* @param respbuf 响应缓冲区
|
||||||
|
* @param bufsize 缓冲区大小
|
||||||
|
* @param timeout 超时时间
|
||||||
|
* @param cmd 命令
|
||||||
|
* @retval 命令执行状态
|
||||||
|
*/
|
||||||
|
static at_resp_code at_send_cmd_sync(char *respbuf, int bufsize, int timeout, const char *cmd, ...)
|
||||||
|
{
|
||||||
|
at_attr_t attr;
|
||||||
|
va_list args;
|
||||||
|
bool ret;
|
||||||
|
//属性初始化
|
||||||
|
at_attr_deinit(&attr);
|
||||||
|
attr.timeout = timeout;
|
||||||
|
attr.retry = 1;
|
||||||
|
attr.cb = at_callback_handler;
|
||||||
|
va_start(args, cmd);
|
||||||
|
|
||||||
|
pthread_mutex_lock(&gw.sync_cmd_lock);
|
||||||
|
//设置接收缓冲区
|
||||||
|
at_watch.recvbuf = respbuf;
|
||||||
|
at_watch.bufsize = bufsize;
|
||||||
|
at_watch.recvcnt = 0;
|
||||||
|
at_watch.resp_code = AT_RESP_ERROR;
|
||||||
|
if (at_exec_vcmd(at_obj, &attr, cmd, args)) {
|
||||||
|
sem_wait(&at_watch.sem_finish); //等待命令执行完成
|
||||||
|
}
|
||||||
|
pthread_mutex_unlock(&gw.sync_cmd_lock);
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
return at_watch.resp_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
## 内存监视器
|
||||||
|
嵌入式系统的内存资源极其有限,不当的使用动态内存,除了产生内存碎片、内存泄露这些问题外,严重时会导致死机,崩溃等事故,所以在使用动态内存时有必要加上一定限制手段,确保系统在一定安全边际下正常运行。`AT_MEM_LIMIT_SIZE`规定了AT请求所用的最大内存数量,这样可以避免程序异常执行时过度执行AT请求导致内存不足的问题。至于分配多少主要取决于你的应用,如果你一开始并不确定用多少比较合适,可以先设置一个相对来说大一些的值,然后让程序运行一段时间观察使用情况再设置,通过`at_max_used_memory`和`at_cur_used_memory`可以获取历史最大内存使用量和当前内存使用量。
|
112
docs/Porting.md
Normal file
@ -0,0 +1,112 @@
|
|||||||
|
|
||||||
|
# 平台移植及配置
|
||||||
|
|
||||||
|
在使用前,你需要先进行平台移植,下面是下整个组件的目录结构:
|
||||||
|
```shell
|
||||||
|
|
||||||
|
at_chat
|
||||||
|
│
|
||||||
|
|───docs 使用文档
|
||||||
|
|───samples 演示案例
|
||||||
|
|───inlcude 头文件目录
|
||||||
|
| │───at_chat.h
|
||||||
|
| │───at_port.h
|
||||||
|
| │───linux_list.h
|
||||||
|
└───src
|
||||||
|
│───at_port.c
|
||||||
|
│───at_chat.c
|
||||||
|
```
|
||||||
|
|
||||||
|
## 平台移植
|
||||||
|
|
||||||
|
移植只涉及到3个接口实现及若干配置定义(at_port.h中声明了这些需要实现的接口及配置).
|
||||||
|
|
||||||
|
```c
|
||||||
|
|
||||||
|
//内存申请,释放
|
||||||
|
void *at_malloc(unsigned int nbytes);
|
||||||
|
|
||||||
|
void at_free(void *ptr);
|
||||||
|
//获取系统毫秒数(从开机开始)
|
||||||
|
unsigned int at_get_ms(void);
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### 内存相关接口实现
|
||||||
|
|
||||||
|
```C
|
||||||
|
|
||||||
|
void *at_malloc(unsigned int nbytes)
|
||||||
|
{
|
||||||
|
return malloc(nbytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
void at_free(void *ptr)
|
||||||
|
{
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
### 系统时间获取接口实现
|
||||||
|
|
||||||
|
|
||||||
|
**如果你使用的是MCU,可以通过定时器计数方式实现,参考下面的例程:**
|
||||||
|
|
||||||
|
```c
|
||||||
|
/* 滴答计数器*/
|
||||||
|
static volatile unsigned int tick = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 定时器中断服务程序(1ms 1次)
|
||||||
|
*/
|
||||||
|
void timer_handler(void)
|
||||||
|
{
|
||||||
|
tick++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取系统毫秒数
|
||||||
|
*/
|
||||||
|
unsigned int at_get_ms(void)
|
||||||
|
{
|
||||||
|
return tick;
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
**对于linux系统,可以参考下面方式获取:**
|
||||||
|
|
||||||
|
```C
|
||||||
|
/**
|
||||||
|
* @brief 获取系统毫秒数
|
||||||
|
*/
|
||||||
|
unsigned int at_get_ms(void)
|
||||||
|
{
|
||||||
|
struct timeval tv_now;
|
||||||
|
//这里需要注意的是,当系统时间被更改后,会获取到一个错误的值,造成命令超时(代码仅做的演示)。
|
||||||
|
gettimeofday(&tv_now, NULL);
|
||||||
|
return (tv_now.tv_sec * 1000000 + tv_now.tv_usec) / 1000;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 配置说明
|
||||||
|
|
||||||
|
这些配置项主用于命令交互响应设置,内存使用限制及模块开关等,实际应用时需要考虑你所在系统的资源情况,对于大多数情况,默认值已经够用。
|
||||||
|
|
||||||
|
| 配置项 | 默认值 | 配置说明 |
|
||||||
|
| ------------------ | ---------- | ---------------------------------------------------------- |
|
||||||
|
| AT_DEF_RESP_OK | "OK" | 默认AT命令正确响应,当匹配到此值到,状态码返回AT_RESP_OK |
|
||||||
|
| AT_DEF_RESP_ERR | "ERROR" | 默认AT命令错误响应,当匹配到此值到,状态码返回AT_RESP_ERR |
|
||||||
|
| AT_DEF_TIMEOUT | 500 | 默认AT响应超时时间(ms),当命令超时时,状态码返回AT_RESP_TIMEOUT |
|
||||||
|
| AT_DEF_RETRY | 2 | 当发生AT响应错误或者超时时重发次数 |
|
||||||
|
| AT_URC_TIMEOUT | 1000 | 默认URC帧超时时间(ms) |
|
||||||
|
| AT_MAX_CMD_LEN | 256 | 最大命令长度(用于可变参数命令内存限制). |
|
||||||
|
| AT_LIST_WORK_COUNT | 32 | 它规定了同时能够支持的AT异步请求个数, 他可以限制应用程序(使用不当时)短时间内大量突发请求造成内存不足的问题,一般来说8-16已经够用了. |
|
||||||
|
| AT_URC_WARCH_EN | 1 | URC消息监视使能 |
|
||||||
|
| AT_URC_END_MARKS | ":,\n" | URC结束标记列表,越少越好,因为URC匹配程序会根据此列表对接收到的字符做URC结束帧匹配处理,列表太大会影响程序性能. |
|
||||||
|
| AT_MEM_WATCH_EN | 1u | 内存监视使能 |
|
||||||
|
| AT_MEM_LIMIT_SIZE | (3 * 1024) | 内存使用限制 |
|
||||||
|
| AT_WORK_CONTEXT_EN | 1u | AT作业上下文相关接口 |
|
||||||
|
|
||||||
|
|
13
docs/cover.md
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
<!-- coverpage.md -->
|
||||||
|
|
||||||
|
![logo](images/logo.png)
|
||||||
|
|
||||||
|
> **AT命令通信组件(V2)**
|
||||||
|
|
||||||
|
- 异步方式实现,无操作系统也能运行
|
||||||
|
- 支持不定长度URC捕获
|
||||||
|
- 多实例并存
|
||||||
|
|
||||||
|
|
||||||
|
[Gitee](https://gitee.com/moluo-tech/AT)
|
||||||
|
[GitHub](https://gitee.com/moluo-tech/AT)
|
BIN
docs/images/atfsm.png
Normal file
After Width: | Height: | Size: 43 KiB |
BIN
docs/images/atresp.png
Normal file
After Width: | Height: | Size: 9.0 KiB |
BIN
docs/images/logo.png
Normal file
After Width: | Height: | Size: 7.2 KiB |
BIN
docs/images/urcbin.png
Normal file
After Width: | Height: | Size: 9.9 KiB |
BIN
docs/images/urcflow.png
Normal file
After Width: | Height: | Size: 3.7 KiB |
BIN
docs/images/wifi.png
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
docs/images/workfsm.png
Normal file
After Width: | Height: | Size: 30 KiB |
42
docs/index.html
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Document</title>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
|
||||||
|
<meta name="description" content="Description">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0">
|
||||||
|
<link rel="stylesheet" href="//cdn.jsdelivr.net/npm/docsify@4/lib/themes/vue.css">
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<nav>
|
||||||
|
<a href="#/">中文</a>
|
||||||
|
<a href="#/">English</a>
|
||||||
|
</nav>
|
||||||
|
<div data-app id="app">Loading...</div>
|
||||||
|
<script>
|
||||||
|
window.$docsify = {
|
||||||
|
name: 'AT Command(V2)',
|
||||||
|
repo: 'https://gitee.com/moluo-tech/AT-Command',
|
||||||
|
subMaxLevel: 3,
|
||||||
|
coverpage: true,
|
||||||
|
// Custom file name
|
||||||
|
coverpage: 'cover.md',
|
||||||
|
// multiple covers and custom file name
|
||||||
|
coverpage: {
|
||||||
|
'/': 'cover.md',
|
||||||
|
'/en/': 'cover.md',
|
||||||
|
},
|
||||||
|
loadSidebar: true,
|
||||||
|
loadSidebar: 'sidebar.md',
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
<!-- Docsify v4 -->
|
||||||
|
<script src="//cdn.jsdelivr.net/npm/docsify@4"></script>
|
||||||
|
<script src="//unpkg.com/docsify-copy-code"></script>
|
||||||
|
<!-- 代码高亮 -->
|
||||||
|
<script src="//cdn.jsdelivr.net/npm/prismjs@1/components/prism-c.min.js"></script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
4437
docs/package-lock.json
generated
Normal file
5
docs/package.json
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
{
|
||||||
|
"dependencies": {
|
||||||
|
"docsify-pdf-converter": "^2.0.7"
|
||||||
|
}
|
||||||
|
}
|
561
docs/quickStart.md
Normal file
@ -0,0 +1,561 @@
|
|||||||
|
# 快速上手
|
||||||
|
|
||||||
|
有了对整个框架的基本认识之后,接下来我们看一下如何在你的平台下使用。
|
||||||
|
|
||||||
|
## 准备工作
|
||||||
|
在使用前,您需要做一些准备工作,包括:
|
||||||
|
- 工程配置与移植
|
||||||
|
- 驱动接口适配
|
||||||
|
- 创建AT通信对象
|
||||||
|
- 加入轮询任务
|
||||||
|
|
||||||
|
### 工程配置与移植
|
||||||
|
|
||||||
|
如下所示,使用前您需要先将AT通信组件添加到你的项目中, 涉及的文件只有inlcude及src这两个目录,另外根据你所有平台不同,还需要进行简单的移植配置才能正常使用,有关这部分可以参考[平台移植指南](Porting.md#平台移植)平台移植及配置.
|
||||||
|
|
||||||
|
```shell
|
||||||
|
|
||||||
|
at_chat
|
||||||
|
│
|
||||||
|
|───docs 使用文档
|
||||||
|
|───samples 演示案例
|
||||||
|
|───inlcude 头文件目录
|
||||||
|
| │───at_chat.h
|
||||||
|
| │───at_port.h
|
||||||
|
| │───linux_list.h
|
||||||
|
└───src
|
||||||
|
│───at_port.c
|
||||||
|
│───at_chat.c
|
||||||
|
```
|
||||||
|
|
||||||
|
### 驱动接口适配
|
||||||
|
|
||||||
|
完成平台移植这些工作之后,为了能够使AT通信对象与硬件关联起来,你需要提供相关的驱动接口进行适配对接,包括:
|
||||||
|
|
||||||
|
1. 串口读写接口
|
||||||
|
|
||||||
|
因为通常使用是串口进行AT通信,所以只需要提供串口中读写驱动接口即可,不过这里需要注意的是,串口驱动接口必须是带缓冲区**非阻塞**的,对于LINUX的平台,需要将串口文件IO设置为O_NONBLOCK;而如果你使用的是MCU,可以使用队列或者环形缓存区实现(死等收发不保证能正常工作),有经验的工程师对这个应该已经比较熟悉了,对于刚入门不久的小伙,可以参考‘samples/none_os’中的例子。
|
||||||
|
|
||||||
|
2. 互斥锁接口
|
||||||
|
|
||||||
|
如果你是在OS环境下使用并且跨线程执行了AT请求,你需要提供上锁/解锁接口,如果你都是在单线程中运行的则直接填NULL即可。
|
||||||
|
|
||||||
|
3. 缓冲区大小设置
|
||||||
|
|
||||||
|
包括接收缓冲与URC缓冲区,接收缓冲区用于缓存命令请求时设备端响应的数据,它取决于你的设备最大响应内容长度;URC缓冲区也是取决于最长上报的URC数据长度。
|
||||||
|
|
||||||
|
4. 日志打印与异常接口
|
||||||
|
|
||||||
|
如果你需要查看所有AT命令通信的细节,你需要实现debug接口,在进行AT命令通信过程中,他会将所有收发消息输出出来,如果执行过中出现异常(出错,超时),则可以通过实现error接口来进行监视。
|
||||||
|
|
||||||
|
完整的适配器定义如下:
|
||||||
|
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief AT interface adapter
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
//Lock, used in OS environment, fill in NULL if not required.
|
||||||
|
void (*lock)(void);
|
||||||
|
//Unlock, used in OS environment, fill in NULL if not required.
|
||||||
|
void (*unlock)(void);
|
||||||
|
//Data write operation (non-blocking)
|
||||||
|
unsigned int (*write)(const void *buf, unsigned int len);
|
||||||
|
//Data read operation (non-blocking)
|
||||||
|
unsigned int (*read)(void *buf, unsigned int len);
|
||||||
|
//AT error event ( if not required, fill in NULL)
|
||||||
|
void (*error)(at_response_t *);
|
||||||
|
//Log output interface, which can print the complete AT interaction process, fill in NULL if not required.
|
||||||
|
void (*debug)(const char *fmt, ...);
|
||||||
|
#if AT_URC_WARCH_EN
|
||||||
|
//URC buffer size, set according to the actual maximum URC frame when used.
|
||||||
|
unsigned short urc_bufsize;
|
||||||
|
#endif
|
||||||
|
//Command response receiving buffer size, set according to the actual maximum command response length
|
||||||
|
unsigned short recv_bufsize;
|
||||||
|
} at_adapter_t;
|
||||||
|
```
|
||||||
|
|
||||||
|
示例:
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief AT适配器
|
||||||
|
*/
|
||||||
|
static const at_adapter_t at_adapter = {
|
||||||
|
.lock = at_mutex_lock, //多任务上锁(非OS下填NULL)
|
||||||
|
.unlock = at_mutex_unlock, //多任务解锁(非OS下填NULL)
|
||||||
|
.write = at_device_write, //数据写接口
|
||||||
|
.read = at_device_read, //数据读接口)
|
||||||
|
.debug = at_debug, //调试打印接口
|
||||||
|
.recv_bufsize = 256, //接收缓冲区大小
|
||||||
|
.urc_bufsize = 512
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
### 创建AT通信对象
|
||||||
|
下一步就是使用刚刚创建好的驱动接口来创建AT通信对象。
|
||||||
|
|
||||||
|
原型如下:
|
||||||
|
```c
|
||||||
|
at_obj_t *at_obj_create(const at_adapter_t *);
|
||||||
|
```
|
||||||
|
!> 这里有一点需要特别注意,为了节省内存使用,AT组件只存储了`at_adapter_t`对象的指针,而不是对象本身,所以`at_adapter_t`定义的对象必须是常驻内存的,建议使用`const`进行修饰,这样可以存储在ROM中,减少内存使用。
|
||||||
|
|
||||||
|
示例:
|
||||||
|
```c
|
||||||
|
at_obj_t *at_obj;
|
||||||
|
//....
|
||||||
|
at_obj = at_obj_create(&at_adapter);
|
||||||
|
if (at_obj == NULL) {
|
||||||
|
printf("at object create failed\r\n");
|
||||||
|
}
|
||||||
|
//...
|
||||||
|
```
|
||||||
|
### 加入轮询任务
|
||||||
|
最后,你需要再提供一个任务定时轮询,以便它能够及时处理AT请求以及URC消息,轮询时间越短越好,原型如下:
|
||||||
|
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief AT轮询处理程序
|
||||||
|
*/
|
||||||
|
void at_obj_process(at_obj_t *at);
|
||||||
|
```
|
||||||
|
|
||||||
|
示例:
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief AT轮询程序
|
||||||
|
*/
|
||||||
|
void at_device_process(void)
|
||||||
|
{
|
||||||
|
static unsigned int timer = 0;
|
||||||
|
//(为了加快AT命令处理响应速度,建议5ms以内轮询一次)
|
||||||
|
if (at_get_ms() - timer > 5) {
|
||||||
|
timer = at_get_ms();
|
||||||
|
at_obj_process(&at_obj);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
||||||
|
## 基础应用
|
||||||
|
|
||||||
|
完成上面几个步骤之后,你就可以使用AT命令请求相关接口了,不过在开始使用之前,我先带你了解一下有关一般AT命令格式和使用过程中涉及到的一些基本概念,了解这些有助深入理解整个AT组件是如何针对各种不同场景处理那些业务交互的实现原理。
|
||||||
|
|
||||||
|
### 一般AT命令类型与处理
|
||||||
|
|
||||||
|
以常见的GPRS/WIFI模组AT命令为例,它们常用格式的可分以下几种类型:
|
||||||
|
1. **测试命令**
|
||||||
|
命令格式为AT+<x>=?,用于查询设置命令设置的参数以及其取值范围。
|
||||||
|
|
||||||
|
2. **查询命令**
|
||||||
|
命令格式为AT+<x>?,用于返回参数的当前值。
|
||||||
|
3. **设置命令**
|
||||||
|
命令格式为AT+<x>=<...>,用于设置用户配置参数。
|
||||||
|
4. **执行命令**
|
||||||
|
命令格式为AT+<x>,不带参数,常用于执行系统相关操作,如查询系统信息,读取IMEI号等。
|
||||||
|
|
||||||
|
上面列举的4种格式基本上覆盖了常见AT通信场景,通信双方都是一问一答式的,主机发送1行命令请求,从机响应数据及状态,双方只交互一次。由于流程结构一样,所以在软件设计时比较容易统一设计成一种类型接口。
|
||||||
|
|
||||||
|
```shell
|
||||||
|
主机:
|
||||||
|
=> AT+XXX...
|
||||||
|
从机:
|
||||||
|
<= +XXX
|
||||||
|
<= OK/ERROR
|
||||||
|
```
|
||||||
|
|
||||||
|
对主机端来说,命令都是以行为单位执行的,只是携带的参数类型或者个数不同,唯一需要特殊处理的是数据响应信息解析,因为各个命令响应并没有统一格式,所以无法在底层实现一个通用解析模块,这需要上层应用根据不同的命令类型进行分别处理。我们可以按照谁发的命令谁来处理的原则,将命令响应内容返还给命令发送者,由它来进行处理。但是在此之前,需要鉴别响应内容从哪开始到哪结束,这就涉及到内容匹配提取的问题,归纳起来如有下两种情况:
|
||||||
|
- 对于设置类命令,命令响应全是以"OK"状态返回。
|
||||||
|
- 对于查询类命令,返回的内容包含数据+状态,命令状态也是以"OK"返回,而数据部分对于不同命令有不一样的信息格式。
|
||||||
|
|
||||||
|
由此可以通过统一为匹配"前缀+后缀"的方式提取到AT命令响应的内容,这也是这个组件处理AT命令请求的基本实现原理,它通过可以为每个命令附带一个属性信息(包含响应前缀,响应后缀)用于告诉AT解析器如何正确提取响应的内容。
|
||||||
|
|
||||||
|
以无线模组查询信号质量命令为例,如下图所示,"+CSQ:"作为响应内容前缀,"OK"作为响应内容后缀。
|
||||||
|
|
||||||
|
![命令发送-响应示意图](images/atresp.png)
|
||||||
|
|
||||||
|
### 命令属性
|
||||||
|
|
||||||
|
AT命令属性使用**at_attr_t**描述,在发送AT请求之前,你可以为每个AT请求设置一个属性,它可以控制AT状态机的行为,如控制命令响应内容匹配规则、超时时间、错误重试等。所有AT作业对象都共享以下属性:
|
||||||
|
|
||||||
|
- 用户私有参数(params)
|
||||||
|
- 响应内容前后缀(prefix,suffix)
|
||||||
|
- 回调处理程序(cb)
|
||||||
|
- 响应超时时间(timeout)
|
||||||
|
- 重次次数(retry)
|
||||||
|
- 优先级(priority)
|
||||||
|
|
||||||
|
**AT属性数据结构定义如下:**
|
||||||
|
|
||||||
|
```c
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@brief AT Command attributes.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
void *params; /* User parameter, fill in NULL if not required. */
|
||||||
|
const char *prefix; /* Response prefix, fill in NULL if not required. */
|
||||||
|
const char *suffix; /* Response suffix, fill in NULL if not required. */
|
||||||
|
at_callback_t cb; /* Response callback handler, fill in NULL if not needed. */
|
||||||
|
unsigned short timeout; /* Response timeout(ms). */
|
||||||
|
unsigned char retry; /* Response error retries. */
|
||||||
|
at_cmd_priority priority; /* Command execution priority. */
|
||||||
|
} at_attr_t;
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
在使用AT属性之前,你需要为它的每个字段都进行初始化设置,但每次发送请求都将所有属性设置一遍太过繁琐,大多数情况下命令的属性都差不多,您可以先使用**at_attr_deinit**进行默认设置,然后再设置关注的属性即可。
|
||||||
|
|
||||||
|
**示例1:**
|
||||||
|
```c
|
||||||
|
at_attr_t attr;
|
||||||
|
//设置属性为默认值
|
||||||
|
at_attr_deinit(&attr);
|
||||||
|
attr.cb = my_handler; //设置回调处理程序
|
||||||
|
```
|
||||||
|
**示例2:**
|
||||||
|
```c
|
||||||
|
at_attr_t attr;
|
||||||
|
//设置属性为默认值
|
||||||
|
at_attr_deinit(&attr);
|
||||||
|
attr.cb = my_handler; //设置回调处理程序
|
||||||
|
attr.prefix = "+CSQ:" //设置响应内容前缀
|
||||||
|
attr.suffix = "OK"; //设置响应内容后缀
|
||||||
|
...
|
||||||
|
|
||||||
|
```
|
||||||
|
### AT回调与响应
|
||||||
|
|
||||||
|
对于是异步的命令,所有请求的结果都是通过回调方式通知应用程序的,同时它会返回命令响应的相关信息,你可以在AT属性中指定相应的回调处理程序。
|
||||||
|
|
||||||
|
**回调程序原型如下:**
|
||||||
|
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
*@brief AT 执行回调
|
||||||
|
*@param r AT响应信息(包含执行结果,设备端返回的内容信息)
|
||||||
|
*/
|
||||||
|
typedef void (*at_callback_t)(at_response_t *r);
|
||||||
|
```
|
||||||
|
其中`at_response_t`包含了所有请求响应相关的信息,它包含了请求命令的执行状态和命令响应内容。
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief AT响应信息
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
struct at_obj *obj; /* 所属AT通信对象*/
|
||||||
|
void *params; /* 附属参数*/
|
||||||
|
at_resp_code code; /* AT命令响应码*/
|
||||||
|
unsigned short recvcnt; /* 接收数据长度*/
|
||||||
|
char *recvbuf; /* 接收缓冲区(原始数据)*/
|
||||||
|
/* 接收内容前缀,当code=AT_RESP_OK时有效,如果未指定匹配前缀则它指向recvbuf*/
|
||||||
|
char *prefix;
|
||||||
|
/* 接收内容后缀,当code=AT_RESP_OK时有效,如果未指定匹配后缀则它指向recvbuf*/
|
||||||
|
char *suffix;
|
||||||
|
} at_response_t;
|
||||||
|
|
||||||
|
```
|
||||||
|
- obj:所属AT通信对象,你可以通过它在响应处理程序中根据状态发送下一个请求。
|
||||||
|
- param:附属参数,对应`at_attr_t`中的params。
|
||||||
|
- code:AT命令响应码
|
||||||
|
- recvcnt:指示了接收缓冲区recvbuf有效接收数据长度。
|
||||||
|
- recvbuf:缓存了此次命令请求时返回的数据。
|
||||||
|
- prefix:接收内容前缀,例如当你期望接收到'+CSQ:'开始的数据时,当code==AT_RESP_OK,则prefix就是指向了'recvbuf'中'+CSQ:'的开始位置。
|
||||||
|
- suffix:接收内容后缀。
|
||||||
|
|
||||||
|
|
||||||
|
了解完上面的几个基本概念之后,下面看一下如何使用。
|
||||||
|
|
||||||
|
### 单行命令发送(at_send_singlline)
|
||||||
|
通过`at_send_singlline`函数可以执行单行命令请求,其原型如下:
|
||||||
|
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief Send a single -line command
|
||||||
|
* @param cb Response callback handler, Fill in NULL if not required
|
||||||
|
* @param timeout command execution timeout(ms)
|
||||||
|
* @param retry command retries( >= 0)
|
||||||
|
* @param singlline command
|
||||||
|
* @retval Indicates whether the asynchronous work was enqueued successfully.
|
||||||
|
* @note Only the address is saved, so the 'singlline' can not be a local variable which will be destroyed.
|
||||||
|
*/
|
||||||
|
bool at_send_singlline(at_obj_t *at, at_callback_t cb, int timeout, int retry, const char *singlline);
|
||||||
|
```
|
||||||
|
**返回值:**
|
||||||
|
当请求成功返回true,否则返回false。
|
||||||
|
|
||||||
|
**参数说明:**
|
||||||
|
|
||||||
|
- at : AT对象
|
||||||
|
- cb : 回调处理程序,当命令执行完成之后,将以这个接口通知上层应用,并携带命令响应内容及状态。
|
||||||
|
- timeout:命令执行超时时间,单位为ms。
|
||||||
|
- retry:命令出错或者超时重试次数。
|
||||||
|
- singlline:命令名称。
|
||||||
|
|
||||||
|
>注:AT作业只会缓存singlline的指针,这意味者它指向的命令不能是局部数据。
|
||||||
|
|
||||||
|
**示例1,查询网络注册状态(SIM900模块):**
|
||||||
|
|
||||||
|
命令格式:
|
||||||
|
|
||||||
|
```c
|
||||||
|
=> AT+CREG?
|
||||||
|
|
||||||
|
<= +CREG:<mode>,<stat>[,< lac>,< ci>]
|
||||||
|
|
||||||
|
<= OK
|
||||||
|
```
|
||||||
|
代码实现:
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief 命令响应处理程序
|
||||||
|
*/
|
||||||
|
static void read_creg_callback(at_response_t *r)
|
||||||
|
{
|
||||||
|
int mode, state;
|
||||||
|
if (r->code == AT_RESP_OK) {
|
||||||
|
//提取出工作模式及注册状态
|
||||||
|
if (sscanf(r->prefix, "+CREG:%d,%d", &mode, &state) == 2) {
|
||||||
|
printf("Mode:%d, state:%d\r\n", mode, state);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("'CREG' command response failed!\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 读网络注册状态
|
||||||
|
*/
|
||||||
|
static void read_creg(void)
|
||||||
|
{
|
||||||
|
//发送CREG查询命令,超时时间为1000ms,重发次数为0
|
||||||
|
at_send_singlline(at_obj, read_creg_callback, 500, 1, "AT+CREG?");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**示例2,IO控制:**
|
||||||
|
|
||||||
|
如果你不关心命令响应结果,直接可以这样使用。
|
||||||
|
```c
|
||||||
|
at_send_singlline(at_obj, NULL, 500, 0, "AT+SETIO=1,FF"); //设置设备IO类型
|
||||||
|
at_send_singlline(at_obj, NULL, 500, 0, "AT+OUTIO=1,55"); //设置IO电平
|
||||||
|
```
|
||||||
|
|
||||||
|
### 多行命令发送(at_send_multiline)
|
||||||
|
实际工程应用中,特别是进行设备初始化配置时,往往一次需要发送大量命令,一种实现方式是通过`at_send_singlline`在每个命令的回调中根据命令状态进行下一条命令的请求,命令较少时还可以接受,命令一多就会形成恐怖的回调地狱链,造成代码难以理解和维护,现实中应尽量避免这种写法。这里提供了一个支持批量发送的接口来应对这种情况,其原型如下:
|
||||||
|
```c
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Send multiline commands
|
||||||
|
* @param attr AT attributes(NULL to use the default value)
|
||||||
|
* @param multiline Command table, with the last item ending in NULL.
|
||||||
|
* @example :
|
||||||
|
* const char *multiline = {
|
||||||
|
* "AT+XXX",
|
||||||
|
* "AT+XXX",
|
||||||
|
* NULL
|
||||||
|
* };
|
||||||
|
* at_send_multiline(at_dev, NULL, multiline);
|
||||||
|
*
|
||||||
|
* @retval Indicates whether the asynchronous work was enqueued successfully.
|
||||||
|
* @note Only the address is saved, so the array can not be a local variable which will be destroyed.
|
||||||
|
*/
|
||||||
|
bool at_send_multiline(at_obj_t *at, const at_attr_t *attr, const char **multiline);
|
||||||
|
```
|
||||||
|
**返回值:**
|
||||||
|
当请求成功返回true,否则返回false。
|
||||||
|
|
||||||
|
**参数说明:**
|
||||||
|
|
||||||
|
- at : AT对象
|
||||||
|
- attr : 命令属性,通过它可以设置命令回调程序,超时时间等。
|
||||||
|
- multiline:命令表,以NULL结尾。
|
||||||
|
|
||||||
|
**示例(SIM800C 模组初始化):**
|
||||||
|
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief 命令响应处理程序
|
||||||
|
*/
|
||||||
|
static void simcom_init_callback(at_response_t *r)
|
||||||
|
{
|
||||||
|
printf("SIM800C Init %s!\r\n",r->code == AT_RESP_OK ? "ok" : "error");
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* @brief 模块初始化
|
||||||
|
*/
|
||||||
|
static void simcom_init(void)
|
||||||
|
{
|
||||||
|
at_attr_t attr;
|
||||||
|
static const char *cmds[] = {
|
||||||
|
"AT+CSCLK=0",
|
||||||
|
"AT+CIPHEAD=1", //+RECEIVE,<n>,<data length>:
|
||||||
|
"AT+CIPQSEND=1", //快发模式
|
||||||
|
"AT+CIPMUX=1", //多IP支持
|
||||||
|
"AT+CIPSPRT=>",
|
||||||
|
"AT+CIPSRIP=0",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
at_attr_deinit(&attr);
|
||||||
|
attr.cb = simcom_init_callback; //设置命令回调
|
||||||
|
at_send_multiline(at_obj, &attr, cmds);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
!> 批量命令表中最后一项必须是NULL,且整个命令表不能是局部变量。
|
||||||
|
### 可变参数命令(at_exec_cmd)
|
||||||
|
前面讲的单行命令与多行命令都是用于发送固定参数的命令的,如果你的命令参数(如设置类命令)是可变的,可以通过 `at_exec_cmd`执行请求,其原型如下:
|
||||||
|
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief Execute one command
|
||||||
|
* @param attr AT attributes(NULL to use the default value)
|
||||||
|
* @param cmd Formatted arguments
|
||||||
|
* @param ... Variable argument list (same usage as printf)
|
||||||
|
* @retval Indicates whether the asynchronous work was enqueued successfully
|
||||||
|
*/
|
||||||
|
bool at_exec_cmd(at_obj_t *at, const at_attr_t *attr, const char *cmd, ...);
|
||||||
|
```
|
||||||
|
**返回值:**
|
||||||
|
当请求成功返回true,否则返回false。
|
||||||
|
|
||||||
|
**参数说明:**
|
||||||
|
|
||||||
|
- at : AT对象
|
||||||
|
- attr : 命令属性,通过它可以设置命令回调程序,超时时间等。
|
||||||
|
- cmd : 格式化命令,用法与printf一样。
|
||||||
|
|
||||||
|
**示例1,EC20设置APN:**
|
||||||
|
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief 命令响应处理程序
|
||||||
|
*/
|
||||||
|
static void set_apn_callback(at_response_t *r)
|
||||||
|
{
|
||||||
|
printf("Setting APN %s!\r\n",r->code == AT_RESP_OK ? "ok" : "error");
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief 设置APN
|
||||||
|
*/
|
||||||
|
static bool set_apn(const char *apn, const char *username, const char *pwd)
|
||||||
|
{
|
||||||
|
at_attr_t attr;
|
||||||
|
at_attr_deinit(&attr);
|
||||||
|
attr.cb = set_apn_callback; //设置命令回调
|
||||||
|
at_exec_cmd(at_obj, &attr, "AT+QICSGP=1,1,\"%s\",\"%s\",\"%s\",0", apn, username, pwd);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### 可变参数列表(at_exec_vcmd)
|
||||||
|
通常`at_obj_t`对象并不会直接公开给第第三方模块使用,为了能够使其它模块也能进行AT请求,你可能需要对命令请求的接口进行2次封装,当需要支持可变参数时,可以使用`at_exec_vcmd`,它支持传递变参列表,其原型如下:
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief execute command (with variable argument list)
|
||||||
|
* @param attr AT attributes(NULL to use the default value)
|
||||||
|
* @param cmd Format the command.
|
||||||
|
* @param va Variable parameter list
|
||||||
|
* @return Indicates whether the asynchronous work was enqueued successfully
|
||||||
|
*/
|
||||||
|
bool at_exec_vcmd(at_obj_t *at, const at_attr_t *attr, const char *cmd, va_list va);
|
||||||
|
```
|
||||||
|
**返回值:**
|
||||||
|
当请求成功返回true,否则返回false。
|
||||||
|
|
||||||
|
**参数说明:**
|
||||||
|
|
||||||
|
- at : AT对象
|
||||||
|
- attr : 命令属性,通过它可以设置命令回调程序,超时时间等。
|
||||||
|
- cmd : 格式化命令
|
||||||
|
- va : 参数列表
|
||||||
|
|
||||||
|
**示例:**
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief 发送AT命令
|
||||||
|
* @param attr 命令属性
|
||||||
|
* @param cmd,.. 格式化命令参数,用法与printf一样
|
||||||
|
*/
|
||||||
|
bool at_send_cmd(const at_attr_t *attr, const char *cmd, ...)
|
||||||
|
{
|
||||||
|
bool ret;
|
||||||
|
va_list args;
|
||||||
|
va_start(args, cmd);
|
||||||
|
ret = at_exec_vcmd(at_obj, attr, cmd, args);
|
||||||
|
va_end(args);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
```
|
||||||
|
### 发送原始数据(at_send_data)
|
||||||
|
当命令类型非纯文本或者格式化的命令无法满足要求时,可以使用`at_send_data`接口,以原始数据的方式发送。
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief Send (binary) data
|
||||||
|
* @param attr AT attributes(NULL to use the default value)
|
||||||
|
* @param databuf Binary data
|
||||||
|
* @param bufsize Binary data length
|
||||||
|
* @retval Indicates whether the asynchronous work was enqueued successfully
|
||||||
|
*/
|
||||||
|
bool at_send_data(at_obj_t *at, const at_attr_t *attr, const void *databuf, unsigned int bufsize);
|
||||||
|
```
|
||||||
|
**返回值:**
|
||||||
|
当请求成功返回true,否则返回false。
|
||||||
|
|
||||||
|
**参数说明:**
|
||||||
|
- at : AT对象
|
||||||
|
- attr : 命令属性,通过它可以设置命令回调程序,超时时间等。
|
||||||
|
- databuf : 原始数据
|
||||||
|
- bufsize : 数据长度
|
||||||
|
|
||||||
|
### 自定义命令(at_custom_cmd)
|
||||||
|
在进行变参命令或者原始数据发送时,系统会他们单独分配一块区域进行暂存,然后跟随AT作业一块缓存到队列中,如果短期需要发送大量的数据,或者命令队列不能及时被处理,那么那段时间内命令队列占用的总内存会激增,严重时导致无可用内存。即使在内存使用的上做限制,但是遇到这种情况也会造成命令请求失败,使用自定义命令的方式可以在一定程度缓解这个问题,它不直接缓存调用者的任何数据,而只暂存一个发送器指针,当真正发送命令时,再上调用者请求数据,其原型如下:
|
||||||
|
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief Execute custom command
|
||||||
|
* @param attr AT attributes(NULL to use the default value)
|
||||||
|
* @param sender Command sending handler (such as sending any type of data through the env->obj->adap-write interface)
|
||||||
|
* @retval Indicates whether the asynchronous work was enqueued successfully
|
||||||
|
*/
|
||||||
|
bool at_custom_cmd(at_obj_t *at, const at_attr_t *attr, void (*sender)(at_env_t *env));
|
||||||
|
```
|
||||||
|
|
||||||
|
**返回值:**
|
||||||
|
当请求成功返回true,否则返回false。
|
||||||
|
|
||||||
|
**参数说明:**
|
||||||
|
- at : AT对象
|
||||||
|
- attr : 命令属性,通过它可以设置命令回调程序,超时时间等。
|
||||||
|
- sender : 数据发送器,调用者可以通过env->obj->write接口发送任何形式的数据。
|
||||||
|
|
||||||
|
**示例:(ESP8266创建TCP socket)**
|
||||||
|
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief 命令响应处理程序
|
||||||
|
*/
|
||||||
|
static void create_socket_callback(at_response_t *r)
|
||||||
|
{
|
||||||
|
printf("Create socket %s!\r\n",r->code == AT_RESP_OK ? "ok" : "error");
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief 发送创建socket命令
|
||||||
|
*/
|
||||||
|
void create_socket_sender(at_env_t *env)
|
||||||
|
{
|
||||||
|
socket_t *sock = (socket_t *)env->params;
|
||||||
|
env->println(env, "AT+CIPSTART=\"TCP\",\"%s\",%d", sock->ip, sock->port);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 创建socket
|
||||||
|
*/
|
||||||
|
static bool create_socket(socket_t *sock)
|
||||||
|
{
|
||||||
|
at_attr_t attr;
|
||||||
|
at_attr_deinit(&attr);
|
||||||
|
attr.params = sock; //用户参数(里面存储了socket id,目标IP,端口)
|
||||||
|
attr.cb = create_socket_callback; //设置命令回调
|
||||||
|
attr.suffix = "CONNECT OK"; //设置响应后缀
|
||||||
|
return at_custom_cmd(at_obj, &attr, create_socket_sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
```
|
66
docs/readme.md
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
# 简介
|
||||||
|
AT command(V2) 一款管理AT命令通信交互组件, 适用于Modem、WIFI模块、蓝牙等使用AT命令或者ASCII命令行通信的场景,它涵盖了大部分AT通信形式,如参数设置,查询,二进制数据发送等,同时也支持自定义命令交互管理,由于它的每个命令请求都是异步的,所以对于无操作系统的环境也支持。相对于V1版本,新版本在命令接收匹配,URC不定长度数据捕获以及内存安全上做了大量优化,让它可以应对更多复杂产品应用。
|
||||||
|
|
||||||
|
|
||||||
|
下面是一个最基本使用的演示:
|
||||||
|
```c
|
||||||
|
/**
|
||||||
|
* @brief 命令响应处理程序
|
||||||
|
*/
|
||||||
|
static void read_csq_callback(at_response_t *r)
|
||||||
|
{
|
||||||
|
int rssi, ber;
|
||||||
|
//+CSQ: <rssi>,<ber>
|
||||||
|
if (r->code == AT_RESP_OK) {
|
||||||
|
//命令响应成功后,解析出rssi,ber.
|
||||||
|
if (sscanf(r->prefix, "+CSQ:%d,%d", &rssi, &ber) == 2) {
|
||||||
|
printf("rssi:%d, ber:%d\r\n", rssi, ber);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
printf("'CSQ' command response failed!\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 读CSQ值请求
|
||||||
|
*/
|
||||||
|
static void read_csq(void)
|
||||||
|
{
|
||||||
|
//发送CSQ查询命令,超时时间为1000ms,重发次数为0
|
||||||
|
at_send_singlline(at_obj, read_csq_callback, 1000, 0, "AT+CSQ");
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
上面的示例展示了AT命令通信的基本使用方式:
|
||||||
|
- 命令请求:执行命令发送之后,命令并不会立即从数据通道发送出去,而是先进入命令队列。
|
||||||
|
- 异步通知:无论命令执行成功与否,都会以异步方式通知请求者。
|
||||||
|
|
||||||
|
|
||||||
|
# 框架介绍
|
||||||
|
整个组件由两部分内容组成:
|
||||||
|
- AT 作业管理, 管理所有AT异步请求及命令收发工作。
|
||||||
|
- URC(主动上报) 处理模块,实时捕获URC消息并上报事件,它跟AT作业是并行的,是一个可选的模块。
|
||||||
|
|
||||||
|
## AT 作业
|
||||||
|
|
||||||
|
'AT Command'组件的基本处理单元是AT作业, 它实际上是一个状态机轮询程序,不仅仅可以处理单个命令收发,还可以是批量命令,自定义命令等,应用程序在进行AT通信请求时,系统会根据请求类型生成一个新的作业对象,然后将对象按照执行优先级预先缓存到队列中,接着系统会从队列逐个取出并选择相应的状态机处理程序进行处理,处理完毕之后再以回调方式将结果上报给应用程序,整个环节跟流水作业生产产品一样,它的基本处理流程图如下所示:
|
||||||
|
|
||||||
|
![AT处理框架](images/atfsm.png)
|
||||||
|
|
||||||
|
### AT作业生命周期
|
||||||
|
|
||||||
|
AT作业生命周期可以简单分为五个阶段:创建阶段、就绪阶段、运行阶段、完成/终止阶段、销毁阶段。
|
||||||
|
|
||||||
|
<img src="images/workfsm.png" alt="AT作业" style="zoom:75%;" />
|
||||||
|
|
||||||
|
- **创建阶段:** 根据请求类型生成作业项,这个阶段可以为新作业项绑定一个上下文,用来监视作业的整个工作过程,包含运行状态,AT命令响应信息等.
|
||||||
|
- **就绪阶段:** 作业被提交入队列之后就进入了就绪状态,系统按队列顺序一个接着一个取出来并运行.
|
||||||
|
- **运行阶段:** 此时进入运行一个状态机,以一般AT命令为例,它包含了命令发送,数据接收匹配,超时重试等处理.
|
||||||
|
- **完成/终止阶段:** 当命令请求的响应信息匹配成功之后,则进入完成状态,如果在这之前命令请求被提示终止,则进入终止状态。
|
||||||
|
- **销毁阶段:** 在这个阶段系统会将作业从队列中移出同时将相关内存释放.
|
||||||
|
|
||||||
|
## URC 处理模块
|
||||||
|
|
||||||
|
URC 处理模块可以实时捕获URC消息,上层应用需要提供URC消息的匹配规则(消息前后缀)及事件处理入口,它们共同组成了URC订阅表,一旦URC解析器匹配到表中某项规则时,立即以事件方式返回给订阅者进行处理(有关这部分的使用可以参考[URC消息处理](Expert.md#URC消息处理))。
|
||||||
|
|
||||||
|
![AT作业](images/urcflow.png)
|
6
docs/sidebar.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
<!-- navbar.md -->
|
||||||
|
|
||||||
|
* [介绍](readme#简介)
|
||||||
|
* [快速上手](quickStart#基础应用)
|
||||||
|
* [高级教程](Expert#高级教程)
|
||||||
|
* [平台移植](Porting#平台移植)
|
BIN
docs/图表.eddx
Normal file
1302
docs/异步AT框架说明.md
Normal file
BIN
images/wifi.jpg
Before Width: | Height: | Size: 28 KiB |
279
include/at_chat.h
Normal file
@ -0,0 +1,279 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* @brief AT command communication management V2
|
||||||
|
*
|
||||||
|
* Copyright (c) 2020~2022, <morro_luo@163.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apathe-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
* 2020-01-02 roger.luo Initial version
|
||||||
|
* 2021-01-20 roger.luo Add debugging interface, and at the same time solve
|
||||||
|
* the problem of uninitialized linked list leading to
|
||||||
|
* segment fault.
|
||||||
|
* 2021-03-03 roger.luo Fix the problem of frequent print receive timeout caused by not clearing the URC counter.
|
||||||
|
* 2022-10-01 roger.luo Redesign the entire AT framework and release V2.0.
|
||||||
|
******************************************************************************/
|
||||||
|
#ifndef _AT_CHAT_H_
|
||||||
|
#define _AT_CHAT_H_
|
||||||
|
|
||||||
|
#include "at_port.h"
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
struct at_obj;
|
||||||
|
struct at_adapter;
|
||||||
|
struct at_response;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@brief AT work running state.
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
AT_WORK_STAT_IDLE,
|
||||||
|
AT_WORK_STAT_READY,
|
||||||
|
AT_WORK_STAT_RUN,
|
||||||
|
AT_WORK_STAT_FINISH,
|
||||||
|
AT_WORK_STAT_ABORT,
|
||||||
|
} at_work_state;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@brief AT command response code
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
AT_RESP_OK = 0,
|
||||||
|
AT_RESP_ERROR,
|
||||||
|
AT_RESP_TIMEOUT,
|
||||||
|
AT_RESP_ABORT
|
||||||
|
} at_resp_code;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@brief AT command request priority
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
AT_PRIORITY_LOW = 0,
|
||||||
|
AT_PRIORITY_HIGH
|
||||||
|
} at_cmd_priority;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@brief URC frame receiving status
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
URC_RECV_OK = 0, /* URC frame received successfully. */
|
||||||
|
URC_RECV_TIMEOUT /* Receive timeout (The frame prefix is matched but the suffix is not matched within AT_URC_TIMEOUT) */
|
||||||
|
} urc_recv_status;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief URC frame info.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
urc_recv_status status; /* URC frame receiving status.*/
|
||||||
|
char *urcbuf; /* URC frame buffer*/
|
||||||
|
int urclen; /* URC frame buffer length*/
|
||||||
|
} at_urc_info_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief URC subscription item.
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
const char *prefix; /* URC frame prefix,such as '+CSQ:'*/
|
||||||
|
const char endmark; /* URC frame end mark (can only be selected from AT_URC_END_MARKS)*/
|
||||||
|
/**
|
||||||
|
* @brief URC handler (triggered when matching prefix and mark are match)
|
||||||
|
* @params info - URC frame info.
|
||||||
|
* @return Indicates the remaining unreceived bytes of the current URC frame.
|
||||||
|
* @retval 0 Indicates that the current URC frame has been completely received
|
||||||
|
* @retval n It still needs to wait to receive n bytes (AT manager continues
|
||||||
|
* to receive the remaining data and continues to call back this interface).
|
||||||
|
*/
|
||||||
|
int (*handler)(at_urc_info_t *info);
|
||||||
|
} urc_item_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief AT response information
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
struct at_obj *obj; /* AT object*/
|
||||||
|
void *params; /* User parameters (referenced from ->at_attr_t.params)*/
|
||||||
|
at_resp_code code; /* AT command response code.*/
|
||||||
|
unsigned short recvcnt; /* Receive data length*/
|
||||||
|
char *recvbuf; /* Receive buffer (raw data)*/
|
||||||
|
/* Pointer to the receiving content prefix, valid when code=AT_RESP_OK,
|
||||||
|
if no prefix is specified, it pointer to recvbuf
|
||||||
|
*/
|
||||||
|
char *prefix;
|
||||||
|
/* Pointer to the receiving content suffix, valid when code=AT_RESP_OK,
|
||||||
|
if no suffix is specified, it pointer to recvbuf
|
||||||
|
*/
|
||||||
|
char *suffix;
|
||||||
|
} at_response_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief AT interface adapter
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
//Lock, used in OS environment, fill in NULL if not required.
|
||||||
|
void (*lock)(void);
|
||||||
|
//Unlock, used in OS environment, fill in NULL if not required.
|
||||||
|
void (*unlock)(void);
|
||||||
|
//Data write operation (non-blocking)
|
||||||
|
unsigned int (*write)(const void *buf, unsigned int len);
|
||||||
|
//Data read operation (non-blocking)
|
||||||
|
unsigned int (*read)(void *buf, unsigned int len);
|
||||||
|
//AT error event ( if not required, fill in NULL)
|
||||||
|
void (*error)(at_response_t *);
|
||||||
|
//Log output interface, which can print the complete AT interaction process, fill in NULL if not required.
|
||||||
|
void (*debug)(const char *fmt, ...);
|
||||||
|
#if AT_URC_WARCH_EN
|
||||||
|
//URC buffer size, set according to the actual maximum URC frame when used.
|
||||||
|
unsigned short urc_bufsize;
|
||||||
|
#endif
|
||||||
|
//Command response receiving buffer size, set according to the actual maximum command response length
|
||||||
|
unsigned short recv_bufsize;
|
||||||
|
} at_adapter_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Public environment for AT work
|
||||||
|
*/
|
||||||
|
typedef struct at_env {
|
||||||
|
struct at_obj *obj;
|
||||||
|
//Public variables (add as needed), these values are reset every time a new work starts.
|
||||||
|
int i, j, state;
|
||||||
|
//User parameters (referenced from ->at_attr_t.params)
|
||||||
|
void *params;
|
||||||
|
//Set the next polling wait interval (only takes effect once)
|
||||||
|
void (*next_wait)(struct at_env *self, unsigned int ms);
|
||||||
|
//Reset timer
|
||||||
|
void (*reset_timer)(struct at_env *self);
|
||||||
|
//Timeout indication
|
||||||
|
bool (*is_timeout)(struct at_env *self, unsigned int ms);
|
||||||
|
//Formatted printout with newlines
|
||||||
|
void (*println)(struct at_env *self, const char *fmt, ...);
|
||||||
|
//Find a keyword from the received content
|
||||||
|
char * (*contains)(struct at_env *self, const char *str);
|
||||||
|
//Get receives buffer
|
||||||
|
char * (*recvbuf)(struct at_env *self);
|
||||||
|
//Get receives buffer length
|
||||||
|
unsigned int(*recvlen)(struct at_env *self);
|
||||||
|
//Clear the receives buffer
|
||||||
|
void (*recvclr)(struct at_env *self);
|
||||||
|
//Indicates whether the current work has been abort
|
||||||
|
bool (*disposing)(struct at_env *self);
|
||||||
|
//End the work and set the response code
|
||||||
|
void (*finish)(struct at_env *self, at_resp_code code);
|
||||||
|
} at_env_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@brief AT execution callback
|
||||||
|
*@param r AT response information (including execution results, content information returned by the device)
|
||||||
|
*/
|
||||||
|
typedef void (*at_callback_t)(at_response_t *r);
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@brief AT work polling handler
|
||||||
|
*@param env The public operating environment for AT work, including some common
|
||||||
|
* variables and relevant interfaces needed to communicate AT commands.
|
||||||
|
*@return Work processing status, which determines whether to continue running the
|
||||||
|
* work on the next polling cycle.
|
||||||
|
*
|
||||||
|
* @retval true Indicates that the current work processing has been finished,
|
||||||
|
* and the work response code is set to AT_RESP_OK
|
||||||
|
* @retval false Indicates unfinished work processing, keep running.
|
||||||
|
*@note It must be noted that if the env->finish() operation is invoked in the
|
||||||
|
* current work, the work will be forcibly terminated regardless of the return value.
|
||||||
|
*/
|
||||||
|
typedef int (*at_work_t)(at_env_t *env);
|
||||||
|
|
||||||
|
#if AT_WORK_CONTEXT_EN
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@brief AT work item context (used to monitor the entire life cycle of AT work item)
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
at_work_state work_state; /* Indicates the state at which the AT work item is running. */
|
||||||
|
at_resp_code code; /* Indicates the response code after the AT command has been run.*/
|
||||||
|
unsigned short bufsize; /* Indicates receive buffer size*/
|
||||||
|
unsigned short resplen; /* Indicates the actual response valid data length*/
|
||||||
|
unsigned char *respbuf; /* Point to the receive buffer*/
|
||||||
|
} at_context_t;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@brief AT attributes
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
#if AT_WORK_CONTEXT_EN
|
||||||
|
at_context_t *ctx; /* Pointer to the Work context. */
|
||||||
|
#endif
|
||||||
|
void *params; /* User parameter, fill in NULL if not required. */
|
||||||
|
const char *prefix; /* Response prefix, fill in NULL if not required. */
|
||||||
|
const char *suffix; /* Response suffix, fill in NULL if not required. */
|
||||||
|
at_callback_t cb; /* Response callback handler, Fill in NULL if not required. */
|
||||||
|
unsigned short timeout; /* Response timeout(ms).. */
|
||||||
|
unsigned char retry; /* Response error retries. */
|
||||||
|
at_cmd_priority priority; /* Command execution priority. */
|
||||||
|
} at_attr_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@brief AT object.
|
||||||
|
*/
|
||||||
|
typedef struct at_obj {
|
||||||
|
const at_adapter_t *adap;
|
||||||
|
void *user_data;
|
||||||
|
} at_obj_t;
|
||||||
|
|
||||||
|
at_obj_t *at_obj_create(const at_adapter_t *);
|
||||||
|
|
||||||
|
void at_obj_destroy(at_obj_t *at);
|
||||||
|
|
||||||
|
bool at_obj_busy(at_obj_t *at);
|
||||||
|
|
||||||
|
void at_obj_set_user_data(at_obj_t *at, void *user_data);
|
||||||
|
|
||||||
|
void *at_obj_get_user_data(at_obj_t *at);
|
||||||
|
#if AT_URC_WARCH_EN
|
||||||
|
void at_obj_set_urc(at_obj_t *at, const urc_item_t *tbl, int count);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
void at_obj_process(at_obj_t *at);
|
||||||
|
|
||||||
|
void at_attr_deinit(at_attr_t *attr);
|
||||||
|
|
||||||
|
bool at_exec_cmd(at_obj_t *at, const at_attr_t *attr, const char *cmd, ...);
|
||||||
|
|
||||||
|
bool at_exec_vcmd(at_obj_t *at, const at_attr_t *attr, const char *cmd, va_list va);
|
||||||
|
|
||||||
|
bool at_send_singlline(at_obj_t *at, at_callback_t cb, int timeout, int retry, const char *singlline);
|
||||||
|
|
||||||
|
bool at_send_multiline(at_obj_t *at, const at_attr_t *attr, const char **multiline);
|
||||||
|
|
||||||
|
bool at_send_data(at_obj_t *at, const at_attr_t *attr, const void *databuf, unsigned int bufsize);
|
||||||
|
|
||||||
|
bool at_custom_cmd(at_obj_t *at, const at_attr_t *attr, void (*sender)(at_env_t *env));
|
||||||
|
|
||||||
|
bool at_do_work(at_obj_t *at, void *params, at_work_t work);
|
||||||
|
|
||||||
|
void at_work_abort_all(at_obj_t *at);
|
||||||
|
|
||||||
|
#if AT_MEM_WATCH_EN
|
||||||
|
unsigned int at_max_used_memory(void);
|
||||||
|
|
||||||
|
unsigned int at_cur_used_memory(void);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if AT_WORK_CONTEXT_EN
|
||||||
|
|
||||||
|
void at_context_init(at_context_t *ctx, void *respbuf, unsigned bufsize);
|
||||||
|
|
||||||
|
void at_context_attach(at_attr_t *attr, at_context_t *ctx);
|
||||||
|
|
||||||
|
at_work_state at_work_get_state(at_context_t *ctx);
|
||||||
|
|
||||||
|
bool at_work_is_finish(at_context_t *ctx);
|
||||||
|
|
||||||
|
at_resp_code at_work_get_result(at_context_t *ctx);
|
||||||
|
|
||||||
|
#endif //End of AT_WORK_CONTEXT_EN
|
||||||
|
|
||||||
|
#endif //End of _AT_CHAT_H_
|
||||||
|
|
76
include/at_port.h
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
/**
|
||||||
|
* @Brief: The AT component drives the interface implementation
|
||||||
|
* @Author: roger.luo
|
||||||
|
* @Date: 2021-04-04
|
||||||
|
* @Last Modified by: roger.luo
|
||||||
|
* @Last Modified time: 2021-11-27
|
||||||
|
*/
|
||||||
|
#ifndef __AT_PORT_H__
|
||||||
|
#define __AT_PORT_H__
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@brief Default correct response identifier.
|
||||||
|
*/
|
||||||
|
#define AT_DEF_RESP_OK "OK"
|
||||||
|
/**
|
||||||
|
*@brief Default error response identifier.
|
||||||
|
*/
|
||||||
|
#define AT_DEF_RESP_ERR "ERROR"
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@brief Default command timeout (ms)
|
||||||
|
*/
|
||||||
|
#define AT_DEF_TIMEOUT 500
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@brief Number of retries when a command timeout/error occurs.
|
||||||
|
*/
|
||||||
|
#define AT_DEF_RETRY 2
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@brief Default URC frame receive timeout (ms).
|
||||||
|
*/
|
||||||
|
#define AT_URC_TIMEOUT 500
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@brief Maximum AT command send data length (only for variable parameter commands).
|
||||||
|
*/
|
||||||
|
#define AT_MAX_CMD_LEN 256
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@brief Maximum number of work in queue (limit memory usage).
|
||||||
|
*/
|
||||||
|
#define AT_LIST_WORK_COUNT 32
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@brief Enable URC watcher.
|
||||||
|
*/
|
||||||
|
#define AT_URC_WARCH_EN 1
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@brief A list of specified URC end marks (fill in as needed, the fewer the better).
|
||||||
|
*/
|
||||||
|
#define AT_URC_END_MARKS ":,\n"
|
||||||
|
/**
|
||||||
|
*@brief Enable memory watcher.
|
||||||
|
*/
|
||||||
|
#define AT_MEM_WATCH_EN 1u
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@brief Maximum memory usage limit (Valid when AT_MEM_WATCH_EN is enabled)
|
||||||
|
*/
|
||||||
|
#define AT_MEM_LIMIT_SIZE (3 * 1024)
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@brief Enable AT work context interfaces.
|
||||||
|
*/
|
||||||
|
#define AT_WORK_CONTEXT_EN 1u
|
||||||
|
|
||||||
|
|
||||||
|
void *at_malloc(unsigned int nbytes);
|
||||||
|
|
||||||
|
void at_free(void *ptr);
|
||||||
|
|
||||||
|
unsigned int at_get_ms(void);
|
||||||
|
|
||||||
|
#endif
|
24
samples/linux/.vscode/c_cpp_properties.json
vendored
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "Linux",
|
||||||
|
"includePath": [
|
||||||
|
"${workspaceFolder}/../**",
|
||||||
|
"${workspaceFolder}/../../**"
|
||||||
|
],
|
||||||
|
"defines": [],
|
||||||
|
"intelliSenseMode": "gcc-x64",
|
||||||
|
"browse": {
|
||||||
|
"path": [
|
||||||
|
"${workspaceFolder}/**"
|
||||||
|
],
|
||||||
|
"limitSymbolsToIncludedHeaders": true,
|
||||||
|
"databaseFilename": ""
|
||||||
|
},
|
||||||
|
"compilerPath": "/usr/bin/gcc",
|
||||||
|
"cStandard": "c11",
|
||||||
|
"cppStandard": "c++17"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"version": 4
|
||||||
|
}
|
3
samples/linux/.vscode/extensions.json
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
{
|
||||||
|
"recommendations": ["ms-vscode.cpptools"]
|
||||||
|
}
|
25
samples/linux/.vscode/launch.json
vendored
Normal file
@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"version": "0.2.0",
|
||||||
|
"configurations": [
|
||||||
|
{
|
||||||
|
"name": "g++ build and debug active file",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/output/demo",
|
||||||
|
"args": [],
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"cwd": "${workspaceFolder}",
|
||||||
|
"environment": [],
|
||||||
|
"externalConsole": false,
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"description": "Enable pretty-printing for gdb",
|
||||||
|
"text": "-enable-pretty-printing",
|
||||||
|
"ignoreFailures": true
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"preLaunchTask": "Build"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
9
samples/linux/.vscode/settings.json
vendored
Normal file
@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"makefile.launchConfigurations": [
|
||||||
|
{
|
||||||
|
"cwd": "${workspaceFolder}/output",
|
||||||
|
"binaryPath": "${workspaceFolder}/output/demo",
|
||||||
|
"binaryArgs": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
38
samples/linux/.vscode/tasks.json
vendored
Normal file
@ -0,0 +1,38 @@
|
|||||||
|
{
|
||||||
|
"version": "2.0.0",
|
||||||
|
"tasks": [
|
||||||
|
{
|
||||||
|
"type": "shell",
|
||||||
|
"label": "Build",
|
||||||
|
"command": "make clean & make",
|
||||||
|
"options": {
|
||||||
|
"cwd": "${workspaceFolder}"
|
||||||
|
},
|
||||||
|
"presentation": {
|
||||||
|
"echo": true,
|
||||||
|
"reveal": "always",
|
||||||
|
"focus": false,
|
||||||
|
"panel": "shared"
|
||||||
|
},
|
||||||
|
"problemMatcher": {
|
||||||
|
"owner": "cpp",
|
||||||
|
"fileLocation": [
|
||||||
|
"relative",
|
||||||
|
"${workspaceFolder}"
|
||||||
|
],
|
||||||
|
"pattern": {
|
||||||
|
"regexp": "^(.*):(\\d+):(\\d+):\\s+(warning|error):\\s+(.*)$",
|
||||||
|
"file": 1,
|
||||||
|
"line": 2,
|
||||||
|
"column": 3,
|
||||||
|
"severity": 4,
|
||||||
|
"message": 5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"group": {
|
||||||
|
"kind": "build",
|
||||||
|
"isDefault": true
|
||||||
|
},
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
128
samples/linux/cmd/cmd_gsm.c
Normal file
@ -0,0 +1,128 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* @brief GSM 模块AT命令模拟器
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
* 2022-04-01 Roger.luo 初版
|
||||||
|
******************************************************************************/
|
||||||
|
#include "cli.h"
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <time.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief AT测试
|
||||||
|
*/
|
||||||
|
static int do_cmd_at(struct cli_obj *obj, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
cmd_register("AT", do_cmd_at, NULL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 查询SIM卡状态
|
||||||
|
*/
|
||||||
|
static int do_cmd_cpin(struct cli_obj *obj, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
obj->print(obj, "+CPIN:READY\r\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
cmd_register("CPIN", do_cmd_cpin, NULL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 查询信号质量
|
||||||
|
*/
|
||||||
|
static int do_cmd_csq(struct cli_obj *obj, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
obj->print(obj, "+CSQ:31,99\r\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
cmd_register("CSQ",do_cmd_csq, NULL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 网络注册状态
|
||||||
|
*/
|
||||||
|
static int do_cmd_creg(struct cli_obj *obj, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
obj->print(obj, "+CREG: 2,1,\"1052\",\"D619\",0\r\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
cmd_register("CREG", do_cmd_creg, NULL);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 查询模块IMEI
|
||||||
|
*/
|
||||||
|
static int do_cmd_cgsn(struct cli_obj *obj, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
obj->print(obj, "123456789012345\r\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
cmd_register("CGSN", do_cmd_cgsn, NULL);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 查询模块版本号
|
||||||
|
*/
|
||||||
|
static int do_cmd_ver(struct cli_obj *obj, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
obj->print(obj, "+VER:V1.02\r\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
cmd_register("VER", do_cmd_ver, NULL);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 配置参数设置
|
||||||
|
*/
|
||||||
|
static int do_cmd_param(struct cli_obj *obj, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
static int a = 0, b = 0;
|
||||||
|
char *p;
|
||||||
|
if (obj->type == CLI_CMD_TYPE_QUERY) { //参数查询
|
||||||
|
obj->print(obj, "+PARAM=%d,%d\r\n" ,a, b);
|
||||||
|
return true;
|
||||||
|
} else { //参数设置
|
||||||
|
p = strchr(obj->recvbuf, '=');
|
||||||
|
if (argc == 2 && p != NULL) {
|
||||||
|
a = atoi(p + 1);
|
||||||
|
b = atoi(argv[1]);
|
||||||
|
obj->print(obj, "Parameter setting is successfully, a=%d, b=%d\r\n", a, b);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
cmd_register("PARAM", do_cmd_param, NULL);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 读取二进制数据命令
|
||||||
|
*/
|
||||||
|
static int do_cmd_read_bin(struct cli_obj *obj, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned char check; //数据校验码
|
||||||
|
int len;
|
||||||
|
char buf[256];
|
||||||
|
srand((unsigned)time(NULL));
|
||||||
|
len = rand() % sizeof(buf);
|
||||||
|
for (i = 1, check = 0; i < len; i++) {
|
||||||
|
|
||||||
|
buf[i] = rand() % 128;
|
||||||
|
check ^= buf[i]; //计算校验码
|
||||||
|
}
|
||||||
|
buf[0] = check;
|
||||||
|
//=> AT+RDBIN=<socket id>,<read size>
|
||||||
|
//
|
||||||
|
//<= +BINDAT:<socket id>,<real size>\r\n<raw data......>
|
||||||
|
//
|
||||||
|
//<= OK
|
||||||
|
|
||||||
|
obj->print(obj, "+BINDAT:%d,%d\r\n" ,1, len);
|
||||||
|
obj->write(buf, len);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
cmd_register("BINDAT", do_cmd_read_bin, NULL);
|
22
samples/linux/include/at_device.h
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* @brief AT命令模拟器
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
* 2022-04-01 Roger.luo 初版
|
||||||
|
******************************************************************************/
|
||||||
|
#ifndef __AT_DEVICE_H__
|
||||||
|
#define __AT_DEVICE_H__
|
||||||
|
|
||||||
|
void at_device_init(void);
|
||||||
|
|
||||||
|
void at_device_open(void);
|
||||||
|
|
||||||
|
void at_device_close(void);
|
||||||
|
|
||||||
|
unsigned int at_device_write(const void *buf, unsigned int size);
|
||||||
|
|
||||||
|
unsigned int at_device_read(void *buf, unsigned int size);
|
||||||
|
|
||||||
|
void at_device_emit_urc(const void *urc, int size);
|
||||||
|
|
||||||
|
#endif
|
115
samples/linux/include/cli.h
Normal file
@ -0,0 +1,115 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* @brief 命令行处理
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015-2022, <master_roger@sina.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
* 2015-06-09 Morro 初版
|
||||||
|
*
|
||||||
|
* 2017-07-04 Morro 优化字段分割处理
|
||||||
|
*
|
||||||
|
* 2020-07-05 roger.luo 使用cli_obj_t对象, 支持多个命令源处理
|
||||||
|
* 2021-08-29 roger.luo 支持AT指令解析及回显控制
|
||||||
|
* 2022-02-16 roger.luo 添加命令行守卫处理程序
|
||||||
|
******************************************************************************/
|
||||||
|
#ifndef _CMDLINE_H_
|
||||||
|
#define _CMDLINE_H_
|
||||||
|
|
||||||
|
#include "comdef.h"
|
||||||
|
|
||||||
|
#define CLI_MAX_CMD_LEN 256 /*命令行长度*/
|
||||||
|
#define CLI_MAX_ARGS 16 /*最大参数个数*/
|
||||||
|
#define CLI_MAX_CMDS 64 /*最大允许定义的命令个数*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief CLI作为AT解析器使用,在接收匹配时自动过滤"AT+",
|
||||||
|
*/
|
||||||
|
#define CLI_AT_ENABLE 1
|
||||||
|
|
||||||
|
/*命令类型 */
|
||||||
|
#define CLI_CMD_TYPE_EXEC 0 /* 普通执行命令*/
|
||||||
|
#define CLI_CMD_TYPE_QUERY 1 /* 查询命令 (XXX?)*/
|
||||||
|
#define CLI_CMD_TYPE_SET 2 /* 设备命令 (XXX=YY)*/
|
||||||
|
|
||||||
|
struct cli_obj;
|
||||||
|
|
||||||
|
/*命令项定义*/
|
||||||
|
typedef struct {
|
||||||
|
char *name; /*命令名*/
|
||||||
|
/**
|
||||||
|
* @brief 命令处理程序,类型
|
||||||
|
* @params o - cli 对象
|
||||||
|
* @params argc - 命令参数个数
|
||||||
|
* @params argv - 命令参数表
|
||||||
|
* @return 命令执行结果, 对于AT指令, 返回true时会自动响应OK,返回false时则
|
||||||
|
* 响应ERROR
|
||||||
|
*/
|
||||||
|
int (*handler)(struct cli_obj *o, int argc, char *argv[]);
|
||||||
|
const char *brief; /*命令简介*/
|
||||||
|
void *reserved;
|
||||||
|
}cmd_item_t;
|
||||||
|
|
||||||
|
#define __cmd_register(name,handler,brief)\
|
||||||
|
USED ANONY_TYPE(const cmd_item_t,__cli_cmd_##handler)\
|
||||||
|
SECTION("cli.cmd.1") = {name, handler, brief}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* @brief 命令注册
|
||||||
|
* @params name - 命令名
|
||||||
|
* @params handler - 命令处理程序
|
||||||
|
* 类型:int (*handler)(struct cli_obj *s, int argc, char *argv[]);
|
||||||
|
* @params brief - 使用说明
|
||||||
|
*/
|
||||||
|
#define cmd_register(name,handler,brief)\
|
||||||
|
__cmd_register(name,handler,brief)
|
||||||
|
|
||||||
|
/*cli 接口定义 -------------------------------------------------------------*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* @brief 通信数据(串口)写接口
|
||||||
|
*/
|
||||||
|
unsigned int (*write)(const void *buf, unsigned int len);
|
||||||
|
/**
|
||||||
|
* @brief 通信数据(串口)读接口
|
||||||
|
*/
|
||||||
|
unsigned int (*read) (void *buf, unsigned int len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 命令行守卫程序(不需要则填写NULL,允许所有命令执行)
|
||||||
|
* @retval true - 允许执行, false - 忽略此命令
|
||||||
|
*/
|
||||||
|
int (*cmd_guard)(char *cmdline);
|
||||||
|
|
||||||
|
}cli_port_t;
|
||||||
|
|
||||||
|
/*命令行对象*/
|
||||||
|
typedef struct cli_obj {
|
||||||
|
int (*guard)(char *cmdline);
|
||||||
|
unsigned int (*write)(const void *buf, unsigned int len);
|
||||||
|
unsigned int (*read) (void *buf, unsigned int len);
|
||||||
|
void (*print)(struct cli_obj *this, const char *fmt, ...);
|
||||||
|
int (*get_val)(struct cli_obj *this);
|
||||||
|
char recvbuf[CLI_MAX_CMD_LEN + 1]; /* 命令接收缓冲区*/
|
||||||
|
unsigned short recvcnt; /* 最大接收长度*/
|
||||||
|
unsigned type : 3; /* 命令类型*/
|
||||||
|
unsigned enable : 1; /* CLI 开关控制*/
|
||||||
|
unsigned echo : 1; /* 回显设置*/
|
||||||
|
}cli_obj_t;
|
||||||
|
|
||||||
|
void cli_init(cli_obj_t *obj, const cli_port_t *p);
|
||||||
|
|
||||||
|
void cli_enable(cli_obj_t *obj);
|
||||||
|
|
||||||
|
void cli_disable (cli_obj_t *obj);
|
||||||
|
|
||||||
|
void cli_echo_ctrl (cli_obj_t *obj, int echo);
|
||||||
|
|
||||||
|
void cli_exec_cmd(cli_obj_t *obj, const char *cmd);
|
||||||
|
|
||||||
|
void cli_process(cli_obj_t *obj);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __CMDLINE_H */
|
@ -1,58 +1,51 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* @brief ͨ<EFBFBD>ú궨<EFBFBD><EFBFBD>
|
* @brief 通用宏定义
|
||||||
*
|
*
|
||||||
* Copyright (c) 2018~2020, <morro_luo@163.com>
|
* Change Logs:
|
||||||
*
|
* Date Author Notes
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* 2018-02-01 Roger.luo Initial version.
|
||||||
*
|
******************************************************************************/
|
||||||
* Change Logs:
|
|
||||||
* Date Author Notes
|
#ifndef _COM_DEF_H_
|
||||||
* 2018-02-01 Morro Initial version.
|
#define _COM_DEF_H_
|
||||||
******************************************************************************/
|
|
||||||
|
#ifdef __cplusplus
|
||||||
#ifndef _COM_DEF_H_
|
extern "C" {
|
||||||
#define _COM_DEF_H_
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
/*匿名类型定义 -----------------------------------------------------------*/
|
||||||
extern "C" {
|
#define ANONY_CONN(type, var, line) type var##line
|
||||||
#endif
|
#define ANONY_DEF(type,prefix,line) ANONY_CONN(type, prefix, line)
|
||||||
|
#define ANONY_TYPE(type,prefix) ANONY_DEF(type, prefix, __LINE__)
|
||||||
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD><CDB6><EFBFBD> -----------------------------------------------------------*/
|
|
||||||
#define ANONY_CONN(type, var, line) type var##line
|
/**
|
||||||
#define ANONY_DEF(type,prefix,line) ANONY_CONN(type, prefix, line)
|
* container_of - cast a member of a structure out to the containing structure
|
||||||
#define ANONY_TYPE(type,prefix) ANONY_DEF(type, prefix, __LINE__)
|
* @ptr: the pointer to the member.
|
||||||
|
* @type: the type of the container struct this is embedded in.
|
||||||
/**
|
* @member: the name of the member within the struct.
|
||||||
* container_of - cast a member of a structure out to the containing structure
|
*
|
||||||
* @ptr: the pointer to the member.
|
*/
|
||||||
* @type: the type of the container struct this is embedded in.
|
#define container_of(ptr, type, member) ( \
|
||||||
* @member: the name of the member within the struct.
|
(type *)( (char *)(ptr) - offsetof(type,member) ))
|
||||||
*
|
|
||||||
*/
|
|
||||||
#define container_of(ptr, type, member) ( \
|
#if defined(__CC_ARM) || defined(__GNUC__) /* ARM,GCC*/
|
||||||
(type *)( (char *)(ptr) - offsetof(type,member) ))
|
#define SECTION(x) __attribute__((section(x)))
|
||||||
|
#define UNUSED __attribute__((unused))
|
||||||
|
#define USED __attribute__((used))
|
||||||
#if defined(__CC_ARM) || defined(__GNUC__) /* ARM,GCC*/
|
#define ALIGN(n) __attribute__((aligned(n)))
|
||||||
#define SECTION(x) __attribute__((section(x)))
|
#define WEAK __attribute__((weak))
|
||||||
#define UNUSED __attribute__((unused))
|
#elif defined (__ICCARM__) /*IAR */
|
||||||
#define USED __attribute__((used))
|
#define SECTION(x) @ x
|
||||||
#define ALIGN(n) __attribute__((aligned(n)))
|
#define UNUSED
|
||||||
#define WEAK __attribute__((weak))
|
#define USED __root
|
||||||
#elif defined (__ICCARM__) /*IAR */
|
#define WEAK __weak
|
||||||
#define SECTION(x) @ x
|
#else
|
||||||
#define UNUSED
|
#error "Current tool chain haven't supported yet!"
|
||||||
#define USED __root
|
#endif
|
||||||
#define WEAK __weak
|
|
||||||
#else
|
#ifdef __cplusplus
|
||||||
#error "Current tool chain haven't supported yet!"
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*<2A><><EFBFBD><EFBFBD>Ԫ<EFBFBD>ظ<EFBFBD><D8B8><EFBFBD> ---------------------------------------------------------------*/
|
#endif
|
||||||
#define ARRAY_COUNT(Array) (sizeof(Array) / sizeof(Array[0]))
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#endif
|
|
@ -1,45 +1,47 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD>ο<EFBFBD>linux/kfifo)
|
* @brief <EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD>ο<EFBFBD>linux/kfifo)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016~2020, <morro_luo@163.com>
|
* Copyright (c) 2016~2021, <morro_luo@163.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2016-05-30 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* 2016-05-30 Morro Initial version.
|
||||||
******************************************************************************/
|
* 2021-02-05 Morro <EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD><EFBFBD>пռ<EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD>ӿ<EFBFBD>.
|
||||||
|
******************************************************************************/
|
||||||
#ifndef _RING_BUF_H_
|
|
||||||
#define _RING_BUF_H_
|
#ifndef _RING_BUF_H_
|
||||||
|
#define _RING_BUF_H_
|
||||||
#include <stdbool.h>
|
|
||||||
|
#include <stdbool.h>
|
||||||
#ifdef __cplusplus
|
|
||||||
extern "C" {
|
#ifdef __cplusplus
|
||||||
#endif
|
extern "C" {
|
||||||
|
#endif
|
||||||
/*<2A><><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
|
||||||
typedef struct {
|
/*<2A><><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
unsigned char *buf; /*<2A><><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD> */
|
typedef struct {
|
||||||
unsigned int size; /*<2A><><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD> */
|
unsigned char *buf; /*<2A><><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
unsigned int front; /*ͷָ<CDB7><D6B8> */
|
unsigned int size; /*<2A><><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
unsigned int rear; /*βָ<CEB2><D6B8> */
|
unsigned int front; /*ͷָ<CDB7><D6B8> */
|
||||||
}ring_buf_t;
|
unsigned int rear; /*βָ<CEB2><D6B8> */
|
||||||
|
}ring_buf_t;
|
||||||
bool ring_buf_init(ring_buf_t *r,unsigned char *buf,unsigned int size);
|
|
||||||
|
bool ring_buf_init(ring_buf_t *r,unsigned char *buf,unsigned int size);
|
||||||
void ring_buf_clr(ring_buf_t *r);
|
|
||||||
|
void ring_buf_clr(ring_buf_t *r);
|
||||||
unsigned int ring_buf_len(ring_buf_t *r);
|
|
||||||
|
unsigned int ring_buf_len(ring_buf_t *r);
|
||||||
unsigned int ring_buf_put(ring_buf_t *r,unsigned char *buf,unsigned int len);
|
|
||||||
|
unsigned int ring_buf_put(ring_buf_t *r,unsigned char *buf,unsigned int len);
|
||||||
unsigned int ring_buf_get(ring_buf_t *r,unsigned char *buf,unsigned int len);
|
|
||||||
|
unsigned int ring_buf_get(ring_buf_t *r,unsigned char *buf,unsigned int len);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
unsigned int ring_buf_free_space(ring_buf_t *r);
|
||||||
}
|
|
||||||
#endif
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#endif
|
228
samples/linux/linker.lds
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
/* Script for -z combreloc: combine and sort reloc sections */
|
||||||
|
OUTPUT_FORMAT("elf64-x86-64", "elf64-x86-64",
|
||||||
|
"elf64-x86-64")
|
||||||
|
OUTPUT_ARCH(i386:x86-64)
|
||||||
|
ENTRY(_start)
|
||||||
|
SEARCH_DIR("/usr/x86_64-linux-gnu/lib64"); SEARCH_DIR("=/usr/local/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/local/lib64"); SEARCH_DIR("=/lib/x86_64-linux-gnu"); SEARCH_DIR("=/lib64"); SEARCH_DIR("=/usr/lib/x86_64-linux-gnu"); SEARCH_DIR("=/usr/lib64"); SEARCH_DIR("=/usr/local/lib"); SEARCH_DIR("=/lib"); SEARCH_DIR("=/usr/lib");
|
||||||
|
SECTIONS
|
||||||
|
{
|
||||||
|
/* Read-only sections, merged into text segment: */
|
||||||
|
PROVIDE (__executable_start = SEGMENT_START("text-segment", 0x400000)); . = SEGMENT_START("text-segment", 0x400000) + SIZEOF_HEADERS;
|
||||||
|
.interp : { *(.interp) }
|
||||||
|
.note.gnu.build-id : { *(.note.gnu.build-id) }
|
||||||
|
.hash : { *(.hash) }
|
||||||
|
.gnu.hash : { *(.gnu.hash) }
|
||||||
|
.dynsym : { *(.dynsym) }
|
||||||
|
.dynstr : { *(.dynstr) }
|
||||||
|
.gnu.version : { *(.gnu.version) }
|
||||||
|
.gnu.version_d : { *(.gnu.version_d) }
|
||||||
|
.gnu.version_r : { *(.gnu.version_r) }
|
||||||
|
.rela.dyn :
|
||||||
|
{
|
||||||
|
*(.rela.init)
|
||||||
|
*(.rela.text .rela.text.* .rela.gnu.linkonce.t.*)
|
||||||
|
*(.rela.fini)
|
||||||
|
*(.rela.rodata .rela.rodata.* .rela.gnu.linkonce.r.*)
|
||||||
|
*(.rela.data .rela.data.* .rela.gnu.linkonce.d.*)
|
||||||
|
*(.rela.tdata .rela.tdata.* .rela.gnu.linkonce.td.*)
|
||||||
|
*(.rela.tbss .rela.tbss.* .rela.gnu.linkonce.tb.*)
|
||||||
|
*(.rela.ctors)
|
||||||
|
*(.rela.dtors)
|
||||||
|
*(.rela.got)
|
||||||
|
*(.rela.bss .rela.bss.* .rela.gnu.linkonce.b.*)
|
||||||
|
*(.rela.ldata .rela.ldata.* .rela.gnu.linkonce.l.*)
|
||||||
|
*(.rela.lbss .rela.lbss.* .rela.gnu.linkonce.lb.*)
|
||||||
|
*(.rela.lrodata .rela.lrodata.* .rela.gnu.linkonce.lr.*)
|
||||||
|
*(.rela.ifunc)
|
||||||
|
}
|
||||||
|
.rela.plt :
|
||||||
|
{
|
||||||
|
*(.rela.plt)
|
||||||
|
PROVIDE_HIDDEN (__rela_iplt_start = .);
|
||||||
|
*(.rela.iplt)
|
||||||
|
PROVIDE_HIDDEN (__rela_iplt_end = .);
|
||||||
|
}
|
||||||
|
.init :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT_NONE(.init)))
|
||||||
|
}
|
||||||
|
.plt : { *(.plt) *(.iplt) }
|
||||||
|
.text :
|
||||||
|
{
|
||||||
|
*(.text.unlikely .text.*_unlikely .text.unlikely.*)
|
||||||
|
*(.text.exit .text.exit.*)
|
||||||
|
*(.text.startup .text.startup.*)
|
||||||
|
*(.text.hot .text.hot.*)
|
||||||
|
*(.text .stub .text.* .gnu.linkonce.t.*)
|
||||||
|
/* .gnu.warning sections are handled specially by elf32.em. */
|
||||||
|
*(.gnu.warning)
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.atcmd :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT(cli.cmd.*)))
|
||||||
|
}
|
||||||
|
.fini :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT_NONE(.fini)))
|
||||||
|
}
|
||||||
|
PROVIDE (__etext = .);
|
||||||
|
PROVIDE (_etext = .);
|
||||||
|
PROVIDE (etext = .);
|
||||||
|
.rodata : { *(.rodata .rodata.* .gnu.linkonce.r.*) }
|
||||||
|
.rodata1 : { *(.rodata1) }
|
||||||
|
.eh_frame_hdr : { *(.eh_frame_hdr) }
|
||||||
|
.eh_frame : ONLY_IF_RO { KEEP (*(.eh_frame)) }
|
||||||
|
.gcc_except_table : ONLY_IF_RO { *(.gcc_except_table
|
||||||
|
.gcc_except_table.*) }
|
||||||
|
/* These sections are generated by the Sun/Oracle C++ compiler. */
|
||||||
|
.exception_ranges : ONLY_IF_RO { *(.exception_ranges
|
||||||
|
.exception_ranges*) }
|
||||||
|
/* Adjust the address for the data segment. We want to adjust up to
|
||||||
|
the same address within the page on the next page up. */
|
||||||
|
. = ALIGN (CONSTANT (MAXPAGESIZE)) - ((CONSTANT (MAXPAGESIZE) - .) & (CONSTANT (MAXPAGESIZE) - 1)); . = DATA_SEGMENT_ALIGN (CONSTANT (MAXPAGESIZE), CONSTANT (COMMONPAGESIZE));
|
||||||
|
/* Exception handling */
|
||||||
|
.eh_frame : ONLY_IF_RW { KEEP (*(.eh_frame)) }
|
||||||
|
.gcc_except_table : ONLY_IF_RW { *(.gcc_except_table .gcc_except_table.*) }
|
||||||
|
.exception_ranges : ONLY_IF_RW { *(.exception_ranges .exception_ranges*) }
|
||||||
|
/* Thread Local Storage sections */
|
||||||
|
.tdata : { *(.tdata .tdata.* .gnu.linkonce.td.*) }
|
||||||
|
.tbss : { *(.tbss .tbss.* .gnu.linkonce.tb.*) *(.tcommon) }
|
||||||
|
.preinit_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_start = .);
|
||||||
|
KEEP (*(.preinit_array))
|
||||||
|
PROVIDE_HIDDEN (__preinit_array_end = .);
|
||||||
|
}
|
||||||
|
.init_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__init_array_start = .);
|
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.init_array.*) SORT_BY_INIT_PRIORITY(.ctors.*)))
|
||||||
|
KEEP (*(.init_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .ctors))
|
||||||
|
PROVIDE_HIDDEN (__init_array_end = .);
|
||||||
|
}
|
||||||
|
.fini_array :
|
||||||
|
{
|
||||||
|
PROVIDE_HIDDEN (__fini_array_start = .);
|
||||||
|
KEEP (*(SORT_BY_INIT_PRIORITY(.fini_array.*) SORT_BY_INIT_PRIORITY(.dtors.*)))
|
||||||
|
KEEP (*(.fini_array EXCLUDE_FILE (*crtbegin.o *crtbegin?.o *crtend.o *crtend?.o ) .dtors))
|
||||||
|
PROVIDE_HIDDEN (__fini_array_end = .);
|
||||||
|
}
|
||||||
|
.ctors :
|
||||||
|
{
|
||||||
|
/* gcc uses crtbegin.o to find the start of
|
||||||
|
the constructors, so we make sure it is
|
||||||
|
first. Because this is a wildcard, it
|
||||||
|
doesn't matter if the user does not
|
||||||
|
actually link against crtbegin.o; the
|
||||||
|
linker won't look for a file to match a
|
||||||
|
wildcard. The wildcard also means that it
|
||||||
|
doesn't matter which directory crtbegin.o
|
||||||
|
is in. */
|
||||||
|
KEEP (*crtbegin.o(.ctors))
|
||||||
|
KEEP (*crtbegin?.o(.ctors))
|
||||||
|
/* We don't want to include the .ctor section from
|
||||||
|
the crtend.o file until after the sorted ctors.
|
||||||
|
The .ctor section from the crtend file contains the
|
||||||
|
end of ctors marker and it must be last */
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .ctors))
|
||||||
|
KEEP (*(SORT(.ctors.*)))
|
||||||
|
KEEP (*(.ctors))
|
||||||
|
}
|
||||||
|
.dtors :
|
||||||
|
{
|
||||||
|
KEEP (*crtbegin.o(.dtors))
|
||||||
|
KEEP (*crtbegin?.o(.dtors))
|
||||||
|
KEEP (*(EXCLUDE_FILE (*crtend.o *crtend?.o ) .dtors))
|
||||||
|
KEEP (*(SORT(.dtors.*)))
|
||||||
|
KEEP (*(.dtors))
|
||||||
|
}
|
||||||
|
.jcr : { KEEP (*(.jcr)) }
|
||||||
|
.data.rel.ro : { *(.data.rel.ro.local* .gnu.linkonce.d.rel.ro.local.*) *(.data.rel.ro .data.rel.ro.* .gnu.linkonce.d.rel.ro.*) }
|
||||||
|
.dynamic : { *(.dynamic) }
|
||||||
|
.got : { *(.got) *(.igot) }
|
||||||
|
. = DATA_SEGMENT_RELRO_END (SIZEOF (.got.plt) >= 24 ? 24 : 0, .);
|
||||||
|
.got.plt : { *(.got.plt) *(.igot.plt) }
|
||||||
|
.data :
|
||||||
|
{
|
||||||
|
*(.data .data.* .gnu.linkonce.d.*)
|
||||||
|
SORT(CONSTRUCTORS)
|
||||||
|
}
|
||||||
|
.data1 : { *(.data1) }
|
||||||
|
_edata = .; PROVIDE (edata = .);
|
||||||
|
. = .;
|
||||||
|
__bss_start = .;
|
||||||
|
.bss :
|
||||||
|
{
|
||||||
|
*(.dynbss)
|
||||||
|
*(.bss .bss.* .gnu.linkonce.b.*)
|
||||||
|
*(COMMON)
|
||||||
|
/* Align here to ensure that the .bss section occupies space up to
|
||||||
|
_end. Align after .bss to ensure correct alignment even if the
|
||||||
|
.bss section disappears because there are no input sections.
|
||||||
|
FIXME: Why do we need it? When there is no .bss section, we don't
|
||||||
|
pad the .data section. */
|
||||||
|
. = ALIGN(. != 0 ? 64 / 8 : 1);
|
||||||
|
}
|
||||||
|
.lbss :
|
||||||
|
{
|
||||||
|
*(.dynlbss)
|
||||||
|
*(.lbss .lbss.* .gnu.linkonce.lb.*)
|
||||||
|
*(LARGE_COMMON)
|
||||||
|
}
|
||||||
|
. = ALIGN(64 / 8);
|
||||||
|
. = SEGMENT_START("ldata-segment", .);
|
||||||
|
.lrodata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
||||||
|
{
|
||||||
|
*(.lrodata .lrodata.* .gnu.linkonce.lr.*)
|
||||||
|
}
|
||||||
|
.ldata ALIGN(CONSTANT (MAXPAGESIZE)) + (. & (CONSTANT (MAXPAGESIZE) - 1)) :
|
||||||
|
{
|
||||||
|
*(.ldata .ldata.* .gnu.linkonce.l.*)
|
||||||
|
. = ALIGN(. != 0 ? 64 / 8 : 1);
|
||||||
|
}
|
||||||
|
. = ALIGN(64 / 8);
|
||||||
|
_end = .; PROVIDE (end = .);
|
||||||
|
. = DATA_SEGMENT_END (.);
|
||||||
|
/* Stabs debugging sections. */
|
||||||
|
.stab 0 : { *(.stab) }
|
||||||
|
.stabstr 0 : { *(.stabstr) }
|
||||||
|
.stab.excl 0 : { *(.stab.excl) }
|
||||||
|
.stab.exclstr 0 : { *(.stab.exclstr) }
|
||||||
|
.stab.index 0 : { *(.stab.index) }
|
||||||
|
.stab.indexstr 0 : { *(.stab.indexstr) }
|
||||||
|
.comment 0 : { *(.comment) }
|
||||||
|
/* DWARF debug sections.
|
||||||
|
Symbols in the DWARF debugging sections are relative to the beginning
|
||||||
|
of the section so we begin them at 0. */
|
||||||
|
/* DWARF 1 */
|
||||||
|
.debug 0 : { *(.debug) }
|
||||||
|
.line 0 : { *(.line) }
|
||||||
|
/* GNU DWARF 1 extensions */
|
||||||
|
.debug_srcinfo 0 : { *(.debug_srcinfo) }
|
||||||
|
.debug_sfnames 0 : { *(.debug_sfnames) }
|
||||||
|
/* DWARF 1.1 and DWARF 2 */
|
||||||
|
.debug_aranges 0 : { *(.debug_aranges) }
|
||||||
|
.debug_pubnames 0 : { *(.debug_pubnames) }
|
||||||
|
/* DWARF 2 */
|
||||||
|
.debug_info 0 : { *(.debug_info .gnu.linkonce.wi.*) }
|
||||||
|
.debug_abbrev 0 : { *(.debug_abbrev) }
|
||||||
|
.debug_line 0 : { *(.debug_line .debug_line.* .debug_line_end ) }
|
||||||
|
.debug_frame 0 : { *(.debug_frame) }
|
||||||
|
.debug_str 0 : { *(.debug_str) }
|
||||||
|
.debug_loc 0 : { *(.debug_loc) }
|
||||||
|
.debug_macinfo 0 : { *(.debug_macinfo) }
|
||||||
|
/* SGI/MIPS DWARF 2 extensions */
|
||||||
|
.debug_weaknames 0 : { *(.debug_weaknames) }
|
||||||
|
.debug_funcnames 0 : { *(.debug_funcnames) }
|
||||||
|
.debug_typenames 0 : { *(.debug_typenames) }
|
||||||
|
.debug_varnames 0 : { *(.debug_varnames) }
|
||||||
|
/* DWARF 3 */
|
||||||
|
.debug_pubtypes 0 : { *(.debug_pubtypes) }
|
||||||
|
.debug_ranges 0 : { *(.debug_ranges) }
|
||||||
|
/* DWARF Extension. */
|
||||||
|
.debug_macro 0 : { *(.debug_macro) }
|
||||||
|
.gnu.attributes 0 : { KEEP (*(.gnu.attributes)) }
|
||||||
|
/DISCARD/ : { *(.note.GNU-stack) *(.gnu_debuglink) *(.gnu.lto_*) }
|
||||||
|
}
|
628
samples/linux/main.c
Normal file
@ -0,0 +1,628 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* @brief AT命令测试程序
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
* 2022-04-01 Roger.luo 初版
|
||||||
|
******************************************************************************/
|
||||||
|
#include "at_chat.h"
|
||||||
|
#include "at_port.h"
|
||||||
|
#include "at_device.h"
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
|
||||||
|
static at_obj_t *at_obj; //AT
|
||||||
|
static pthread_mutex_t at_lock; //互斥锁
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
pthread_mutex_t completed; //完成信号量
|
||||||
|
} at_watch_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 测试项
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
void (*handler)(void);
|
||||||
|
const char *brief;
|
||||||
|
} test_item_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 上锁
|
||||||
|
*/
|
||||||
|
static void at_mutex_lock(void)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&at_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 解锁
|
||||||
|
*/
|
||||||
|
static void at_mutex_unlock(void)
|
||||||
|
{
|
||||||
|
pthread_mutex_unlock(&at_lock);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 命令异常处理
|
||||||
|
*/
|
||||||
|
static void at_error_handler(at_response_t *r)
|
||||||
|
{
|
||||||
|
printf("Error detected!\r\n");
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief 打印输出
|
||||||
|
*/
|
||||||
|
static void at_debug(const char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
vprintf(fmt, args);
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if AT_URC_WARCH_EN
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 开/关机URC处理程序
|
||||||
|
*/
|
||||||
|
static int urc_power_handler(at_urc_info_t *ctx)
|
||||||
|
{
|
||||||
|
int status;
|
||||||
|
if (sscanf(ctx->urcbuf, "+POWER:%d",&status) == 1) {
|
||||||
|
printf("Device power %s event detected!\r\n", status ? "on" : "off");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief socket数据包(+IPD,<socket id>,<data length>:.....)
|
||||||
|
*/
|
||||||
|
static int urc_socket_data_handler(at_urc_info_t *ctx)
|
||||||
|
{
|
||||||
|
int length, total_length, sockid, i;
|
||||||
|
char *data;
|
||||||
|
unsigned char check = 0;
|
||||||
|
if (sscanf(ctx->urcbuf, "+IPD,%d,%d:", &sockid, &length) == 2) { //解析出总数据长度
|
||||||
|
data = strchr(ctx->urcbuf, ':');
|
||||||
|
if (data == NULL)
|
||||||
|
return 0;
|
||||||
|
data++;
|
||||||
|
total_length = (data - ctx->urcbuf) + length; //计算头部长度
|
||||||
|
if (ctx->urclen < total_length) { //未接收全,返回剩余待接收数据
|
||||||
|
printf("Need to receive %d more bytes\r\n", total_length - ctx->urclen);
|
||||||
|
return total_length - ctx->urclen;
|
||||||
|
}
|
||||||
|
for (i = 1, check = 0; i < length; i++) {
|
||||||
|
check ^= data[i];
|
||||||
|
}
|
||||||
|
printf("%d bytes of data were received form socket %d, check %s!\r\n",
|
||||||
|
length, sockid, check == data[0] ? "ok": "error");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief urc订阅表
|
||||||
|
*/
|
||||||
|
static const urc_item_t urc_table[] =
|
||||||
|
{
|
||||||
|
{.prefix = "+POWER:", .endmark = '\n', .handler = urc_power_handler},
|
||||||
|
{.prefix = "+IPD,", .endmark = ':', .handler = urc_socket_data_handler}
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 显示内存使用信息
|
||||||
|
*/
|
||||||
|
static void sample_show_memory(void)
|
||||||
|
{
|
||||||
|
#if AT_MEM_WATCH_EN
|
||||||
|
printf("max memory:%d, current memory:%d\r\n", at_max_used_memory(), at_cur_used_memory());
|
||||||
|
#else
|
||||||
|
printf("Unknown memory usage, please enable 'AT_MEM_WATCH_EN' macro first.\r\n");
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 单行命令
|
||||||
|
*/
|
||||||
|
static void sample_singlline(void)
|
||||||
|
{
|
||||||
|
// => AT+CSQ
|
||||||
|
// <= +CSQ:<rssi>,<ber>
|
||||||
|
// <= OK
|
||||||
|
at_send_singlline(at_obj, NULL, 200, 1, "AT+CSQ");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 多行命令
|
||||||
|
*/
|
||||||
|
static void sample_multiline(void)
|
||||||
|
{
|
||||||
|
static const char *cmd_table[] = {
|
||||||
|
"AT+CPIN?",
|
||||||
|
"AT+CSQ",
|
||||||
|
"AT+CREG",
|
||||||
|
"AT+PARAM?",
|
||||||
|
NULL
|
||||||
|
};
|
||||||
|
at_send_multiline(at_obj, NULL, cmd_table);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 可变参数命令
|
||||||
|
*/
|
||||||
|
static void sample_variable_param_cmd(void)
|
||||||
|
{
|
||||||
|
srand((unsigned)time(NULL));
|
||||||
|
at_exec_cmd(at_obj, NULL, "AT+PARAM=%d,%d",rand() % 100,rand() % 200);
|
||||||
|
at_exec_cmd(at_obj, NULL, "AT+PARAM?");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 响应超级返重试
|
||||||
|
*/
|
||||||
|
static void sample_timeout_retry(void)
|
||||||
|
{
|
||||||
|
at_attr_t attr;
|
||||||
|
at_attr_deinit(&attr);
|
||||||
|
attr.retry = 3;
|
||||||
|
attr.timeout = 1000;
|
||||||
|
at_exec_cmd(at_obj, &attr, "AAA");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 命令错误重试
|
||||||
|
*/
|
||||||
|
static void sample_error_retry(void)
|
||||||
|
{
|
||||||
|
at_attr_t attr;
|
||||||
|
at_attr_deinit(&attr);
|
||||||
|
attr.retry = 2;
|
||||||
|
at_exec_cmd(at_obj, &attr, "AT+CMD");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 命令终止
|
||||||
|
*/
|
||||||
|
static void sample_abort_command(void)
|
||||||
|
{
|
||||||
|
at_exec_cmd(at_obj, NULL, "AT+CMD");
|
||||||
|
at_work_abort_all(at_obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 版本读取响应程序
|
||||||
|
*/
|
||||||
|
static void read_ver_cb(at_response_t *r)
|
||||||
|
{
|
||||||
|
char verbuf[16];
|
||||||
|
if (r->code == AT_RESP_OK) {
|
||||||
|
sscanf(r->prefix, "+VER:%s\r\n", verbuf);
|
||||||
|
printf("Version info:%s\r\n", verbuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 指定响应前缀
|
||||||
|
* => AT+VER
|
||||||
|
* <= +VER:Vxxxx
|
||||||
|
* <= OK
|
||||||
|
*/
|
||||||
|
static void sample_specific_prefix(void)
|
||||||
|
{
|
||||||
|
at_attr_t attr;
|
||||||
|
at_attr_deinit(&attr);
|
||||||
|
//匹配介于[+VER -> \r\n]之间的内容
|
||||||
|
attr.prefix = "+VER",
|
||||||
|
attr.suffix = "\r";
|
||||||
|
attr.cb = read_ver_cb;
|
||||||
|
at_exec_cmd(at_obj, &attr, "AT+VER");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 自定义命令发送器
|
||||||
|
*/
|
||||||
|
static void custom_sender(at_env_t *env)
|
||||||
|
{
|
||||||
|
env->println(env, "AT+CSQ\r\n");
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief 自定义命令
|
||||||
|
*/
|
||||||
|
static void sample_custom_cmd(void)
|
||||||
|
{
|
||||||
|
at_custom_cmd(at_obj, NULL, custom_sender);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 发送缓冲区
|
||||||
|
*/
|
||||||
|
static void sample_send_buffer(void)
|
||||||
|
{
|
||||||
|
char buf[] = "AT+CSQ\r\n";
|
||||||
|
at_send_data(at_obj, NULL, buf, sizeof(buf));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 查询CSQ
|
||||||
|
*/
|
||||||
|
static int at_work_query_csq(at_env_t *env)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
int rssi, ber;
|
||||||
|
switch (env->state)
|
||||||
|
{
|
||||||
|
case 0:
|
||||||
|
env->println(env, "AT+CSQ\r\n");
|
||||||
|
env->state++; //转到接收状态
|
||||||
|
env->recvclr(env); //清空接口
|
||||||
|
env->reset_timer(env); //重置计时器
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (env->contains(env, "OK")) {
|
||||||
|
//+CSQ:<rssi>,<ber>
|
||||||
|
if ((p = env->contains(env, "+CSQ")) != NULL &&
|
||||||
|
sscanf(p, "+CSQ:%d,%d", &rssi, &ber) == 2) {
|
||||||
|
printf("The CSQ read ok, rssi:%d, ber:%d\r\n", rssi, ber);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else if (env->contains(env, "ERROR")) { //错误处理
|
||||||
|
printf("The CSQ read failed.\r\n");
|
||||||
|
return true;
|
||||||
|
} else if (env->is_timeout(env, 1000)) { //错误处理
|
||||||
|
printf("The CSQ read timeout.\r\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 自定义作业测试1
|
||||||
|
*/
|
||||||
|
static void sample_at_work_1(void)
|
||||||
|
{
|
||||||
|
at_do_work(at_obj, NULL, at_work_query_csq);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static unsigned char check_bin_data(unsigned char *buf, int len)
|
||||||
|
{
|
||||||
|
unsigned char check = 0;
|
||||||
|
while (len--) {
|
||||||
|
check ^= *buf++;
|
||||||
|
}
|
||||||
|
return check;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 读取socket数制
|
||||||
|
*/
|
||||||
|
static int at_work_read_bin(at_env_t *env)
|
||||||
|
{
|
||||||
|
#define READ_STAT_START 0
|
||||||
|
#define READ_STAT_HEAD 1
|
||||||
|
#define READ_STAT_DATA 2
|
||||||
|
|
||||||
|
static char *start, *end;
|
||||||
|
static int total, sockid;
|
||||||
|
unsigned char buf[256];
|
||||||
|
//=> AT+BINDAT=<socket id>,<read size>
|
||||||
|
//
|
||||||
|
//<= +BINDAT:<socket id>,<real size>\r\n<raw data......>
|
||||||
|
//
|
||||||
|
//<= OK
|
||||||
|
switch (env->state)
|
||||||
|
{
|
||||||
|
case READ_STAT_START:
|
||||||
|
env->println(env, "AT+BINDAT=%d,%d\r\n", 1, sizeof(buf));
|
||||||
|
env->recvclr(env);
|
||||||
|
env->reset_timer(env);
|
||||||
|
env->state = READ_STAT_HEAD;
|
||||||
|
break;
|
||||||
|
case READ_STAT_HEAD:
|
||||||
|
if ((start = env->contains(env, "+BINDAT:")) != NULL) {
|
||||||
|
end = strchr(start, '\n');
|
||||||
|
if (end == NULL)
|
||||||
|
break;
|
||||||
|
end++;
|
||||||
|
if (sscanf(start, "+BINDAT:%d,%d" ,&sockid, &total) == 2) {
|
||||||
|
env->reset_timer(env);
|
||||||
|
env->state++;
|
||||||
|
printf("Next receive %d bytes data from socket %d\r\n", total, sockid);
|
||||||
|
}
|
||||||
|
} else if (env->contains(env, "ERROR")) {
|
||||||
|
env->finish(env, AT_RESP_ERROR);
|
||||||
|
return true;
|
||||||
|
} else if (env->is_timeout(env, 1000)) {
|
||||||
|
if (env->i++ > 3) {
|
||||||
|
/*产生发送异常事件 */
|
||||||
|
printf("recv error!!!\r\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
env->state = READ_STAT_START; /*重新发送*/
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case READ_STAT_DATA:
|
||||||
|
//
|
||||||
|
//recvbuf...start....end....data ....
|
||||||
|
// |---- total ----|
|
||||||
|
//|---------- recvlen ---------------|
|
||||||
|
if (env->recvlen(env) >= total + (end - env->recvbuf(env))) { //数据接收完成
|
||||||
|
memcpy(buf, end, total);
|
||||||
|
printf("recv ok!!!\r\n");
|
||||||
|
if (total > 0 && buf[0] == check_bin_data(&buf[1], total - 1))
|
||||||
|
printf("check ok!!!\r\n");
|
||||||
|
return true;
|
||||||
|
} else if (env->is_timeout(env, 1000)){
|
||||||
|
printf("recv error!!!\r\n");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Read binary data via 'at work'
|
||||||
|
*/
|
||||||
|
static void sample_read_bin_data(void)
|
||||||
|
{
|
||||||
|
at_do_work(at_obj, NULL, at_work_read_bin);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Capture unsolicited binary data
|
||||||
|
*/
|
||||||
|
static void sample_urc_bin_data(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
unsigned char check; //数据校验码
|
||||||
|
int len;
|
||||||
|
char buf[256];
|
||||||
|
char head[32];
|
||||||
|
srand((unsigned)time(NULL));
|
||||||
|
len = rand() % sizeof(buf);
|
||||||
|
for (i = 1, check = 0; i < len; i++) {
|
||||||
|
|
||||||
|
buf[i] = rand() % 128;
|
||||||
|
check ^= buf[i]; //计算校验码
|
||||||
|
}
|
||||||
|
buf[0] = check;
|
||||||
|
//BCC+DATA
|
||||||
|
//+IPD,<socket id>,<data length>:.....
|
||||||
|
snprintf(head, sizeof(head),"+IPD,%d,%d:",rand() % 16, len);
|
||||||
|
at_device_emit_urc(head, strlen(head));
|
||||||
|
at_device_emit_urc(buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if AT_WORK_CONTEXT_EN
|
||||||
|
/**
|
||||||
|
* @brief 发送命令(同步方式)
|
||||||
|
* @param respbuf 响应缓冲区
|
||||||
|
* @param bufsize 缓冲区大小
|
||||||
|
* @param timeout 超时时间
|
||||||
|
* @param cmd 命令
|
||||||
|
* @retval 命令执行状态
|
||||||
|
*/
|
||||||
|
static at_resp_code at_send_cmd_sync(char *respbuf, int bufsize, int timeout, const char *cmd, ...)
|
||||||
|
{
|
||||||
|
at_attr_t attr;
|
||||||
|
at_context_t ctx;
|
||||||
|
va_list args;
|
||||||
|
bool ret;
|
||||||
|
//属性初始化
|
||||||
|
at_attr_deinit(&attr);
|
||||||
|
attr.timeout = timeout;
|
||||||
|
attr.retry = 1;
|
||||||
|
//初始化context
|
||||||
|
at_context_init(&ctx, respbuf, bufsize);
|
||||||
|
//为工作项绑定context
|
||||||
|
at_context_attach(&attr, &ctx);
|
||||||
|
|
||||||
|
va_start(args, cmd);
|
||||||
|
ret = at_exec_vcmd(at_obj, &attr, cmd, args);
|
||||||
|
va_end(args);
|
||||||
|
|
||||||
|
if (!ret) {
|
||||||
|
return AT_RESP_ERROR;
|
||||||
|
}
|
||||||
|
|
||||||
|
//等待命令执行完毕
|
||||||
|
while (!at_work_is_finish(&ctx)) {
|
||||||
|
usleep(1000);
|
||||||
|
}
|
||||||
|
return at_work_get_result(&ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 基于上下文实现同步接口
|
||||||
|
*/
|
||||||
|
static void sample_at_sync(void)
|
||||||
|
{
|
||||||
|
int rssi, error_rate;
|
||||||
|
char csqbuf[64];
|
||||||
|
at_resp_code code;
|
||||||
|
code = at_send_cmd_sync(csqbuf, sizeof(csqbuf), 200, "AT+CSQ");
|
||||||
|
if (code == AT_RESP_OK) {
|
||||||
|
sscanf(csqbuf, "+CSQ:%d,%d", &rssi, &error_rate);
|
||||||
|
printf("The CSQ value is read successfully\r\n=>rssi:%d, error_rate:%d\r\n", rssi, error_rate);
|
||||||
|
} else if (code == AT_RESP_TIMEOUT) {
|
||||||
|
printf("The CSQ read timeout.\r\n");
|
||||||
|
} else {
|
||||||
|
printf("The CSQ read failed.\r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
/**
|
||||||
|
* @brief 测试用例
|
||||||
|
*/
|
||||||
|
static const test_item_t test_cases[] = {
|
||||||
|
{sample_show_memory, "Display memory information."},
|
||||||
|
{sample_singlline, "Testing singlline command."},
|
||||||
|
{sample_multiline, "Testing multiline commands."},
|
||||||
|
{sample_variable_param_cmd, "Testing variable parameter command."},
|
||||||
|
{sample_timeout_retry, "Testing response timeout retry."},
|
||||||
|
{sample_error_retry, "Testing response error retry."},
|
||||||
|
{sample_abort_command, "Testing command abort."},
|
||||||
|
{sample_specific_prefix, "Testing specific response prefix."},
|
||||||
|
{sample_custom_cmd, "Testing custom command."},
|
||||||
|
{sample_send_buffer, "Testing buffer send."},
|
||||||
|
{sample_at_work_1, "Testing 'at_do_work' 1."},
|
||||||
|
{sample_read_bin_data, "Testing read binary data via 'at work'."},
|
||||||
|
{sample_urc_bin_data, "Testing capture unsolicited binary data."},
|
||||||
|
#if AT_WORK_CONTEXT_EN
|
||||||
|
{sample_at_sync, "Testing at context interface."},
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 显示测试用例
|
||||||
|
*/
|
||||||
|
static void show_test_case(void)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
printf("Please input test item:\r\n");
|
||||||
|
for (i = 0; i < sizeof(test_cases) / sizeof(test_cases[0]); i++)
|
||||||
|
printf("\t%d:%s\r\n", i + 1, test_cases[i].brief);
|
||||||
|
printf("*******************************************************\r\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 显示测试用例
|
||||||
|
*/
|
||||||
|
static void input_process(void)
|
||||||
|
{
|
||||||
|
const test_item_t *item;
|
||||||
|
char buf[128];
|
||||||
|
int num;
|
||||||
|
|
||||||
|
fgets(buf, sizeof(buf), stdin);
|
||||||
|
num = atoi(buf);
|
||||||
|
if (num > 0 && num <= sizeof(test_cases) / sizeof(test_cases[0])) {
|
||||||
|
item = &test_cases[num - 1];
|
||||||
|
printf("Start '%s'\r\n", item->brief);
|
||||||
|
item->handler();
|
||||||
|
} else {
|
||||||
|
show_test_case();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief at适配器
|
||||||
|
*/
|
||||||
|
static const at_adapter_t at_adapter = {
|
||||||
|
.lock = at_mutex_lock,
|
||||||
|
.unlock = at_mutex_unlock,
|
||||||
|
.write = at_device_write,
|
||||||
|
.read = at_device_read,
|
||||||
|
.error = at_error_handler,
|
||||||
|
.debug = at_debug,
|
||||||
|
#if AT_URC_WARCH_EN
|
||||||
|
.urc_bufsize = 300,
|
||||||
|
#endif
|
||||||
|
.recv_bufsize = 300
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief at通信处理线程
|
||||||
|
*/
|
||||||
|
static void *at_thread(void *args)
|
||||||
|
{
|
||||||
|
pthread_detach(pthread_self());
|
||||||
|
printf("at thread running...\r\n");
|
||||||
|
while(1) {
|
||||||
|
usleep(1000);
|
||||||
|
at_obj_process(at_obj);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
pthread_t tid;
|
||||||
|
at_obj = at_obj_create(&at_adapter);
|
||||||
|
if (at_obj == NULL) {
|
||||||
|
printf("at object create failed\r\n");
|
||||||
|
_exit(0);
|
||||||
|
}
|
||||||
|
at_obj_set_urc(at_obj, urc_table, sizeof(urc_table) / sizeof(urc_table[0]) );
|
||||||
|
at_device_init();
|
||||||
|
pthread_mutex_init(&at_lock, NULL);
|
||||||
|
pthread_create(&tid, NULL, at_thread, NULL);
|
||||||
|
printf("*******************************************************\r\n");
|
||||||
|
printf("This is an asynchronous AT command framework.\r\n");
|
||||||
|
printf("Author:roger.luo, Mail:morro_luo@163.com\r\n");
|
||||||
|
printf("*******************************************************\r\n\r\n");
|
||||||
|
//Open AT emulator device
|
||||||
|
at_device_open();
|
||||||
|
|
||||||
|
show_test_case();
|
||||||
|
while(1){
|
||||||
|
input_process();
|
||||||
|
usleep(10 * 1000);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//....
|
||||||
|
typedef struct {
|
||||||
|
//....
|
||||||
|
int id;
|
||||||
|
unsigned char *sendptr;
|
||||||
|
int sendcnt;
|
||||||
|
}socket_t;
|
||||||
|
//....
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief socket 数据发送处理
|
||||||
|
* @return true - 结束运行 false - 保持运行
|
||||||
|
*/
|
||||||
|
static int socket_send_handler(at_env_t *env)
|
||||||
|
{
|
||||||
|
socket_t *sk = (socket_t *)env->params;
|
||||||
|
switch (env->state) {
|
||||||
|
case 0:
|
||||||
|
env->println(env, "AT+KTCPSND=%d,%d", sk->id, sk->sendcnt);
|
||||||
|
env->reset_timer(env); /*重置定时器*/
|
||||||
|
env->state++;
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
if (env->contains(env, "CONNECT")) {
|
||||||
|
env->obj->adap->write(sk->sendptr, sk->sendcnt); /*发送数据*/
|
||||||
|
env->println(env, "--EOF--Pattern--"); /*发送结束符*/
|
||||||
|
env->reset_timer(env);
|
||||||
|
env->recvclr(env);
|
||||||
|
env->state++;
|
||||||
|
} else if (env->contains(env, "ERROR")) { /*匹配到错误,结束作业*/
|
||||||
|
env->finish(env, AT_RESP_ERROR);
|
||||||
|
} else if (env->is_timeout(env, 1000)) {
|
||||||
|
if (++env->i > 3) {
|
||||||
|
env->finish(env, AT_RESP_ERROR);
|
||||||
|
}
|
||||||
|
env->state--; /*重新发送*/
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
if (env->contains(env, "OK"))
|
||||||
|
env->finish(env, AT_RESP_OK); /*发送成功,设置状态为OK后退出*/
|
||||||
|
else if (env->contains(env, "ERROR") ||
|
||||||
|
env->is_timeout(env, 1000)) {
|
||||||
|
env->finish(env, AT_RESP_ERROR);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
111
samples/linux/makefile
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
# Specify the compiler name
|
||||||
|
CROSS_COMPILE ?=
|
||||||
|
|
||||||
|
# Name of the target
|
||||||
|
TARGET_NAME := demo
|
||||||
|
|
||||||
|
# Source File Directory
|
||||||
|
source_path := ./ ../../src
|
||||||
|
source_path += ./src
|
||||||
|
source_path += ./cmd
|
||||||
|
|
||||||
|
# Source Files
|
||||||
|
source_files :=
|
||||||
|
|
||||||
|
# Header file directory
|
||||||
|
include_path := ./include ../../include
|
||||||
|
|
||||||
|
# Exclude files that do not participate in compilation
|
||||||
|
exclude_files := ../../src/at_port.c
|
||||||
|
|
||||||
|
#Dependency library
|
||||||
|
LIB =
|
||||||
|
|
||||||
|
#MAKEFLAGS := -j $(shell nproc)
|
||||||
|
|
||||||
|
#
|
||||||
|
# 警告选项
|
||||||
|
#
|
||||||
|
WARNINGS := -Wall -Wextra -Werror\
|
||||||
|
-Wshadow -Wundef -Wmaybe-uninitialized \
|
||||||
|
-Wno-unused-function -Wno-error=strict-prototypes -Wpointer-arith -fno-strict-aliasing -Wno-error=cpp -Wuninitialized \
|
||||||
|
-Wno-missing-field-initializers -Wno-parentheses -Wno-format-nonliteral -Wno-cast-qual -Wunreachable-code -Wno-switch-default \
|
||||||
|
-Wreturn-type -Wmultichar -Wformat-security -Wno-ignored-qualifiers -Wno-error=pedantic -Wno-sign-compare -Wno-error=missing-prototypes -Wdouble-promotion -Wclobbered -Wdeprecated \
|
||||||
|
-Wempty-body -Wstack-usage=4096 -Wno-unused-parameter \
|
||||||
|
-Wtype-limits -Wsizeof-pointer-memaccess -Wpointer-arith -Wno-pointer-to-int-cast -Wno-pointer-sign
|
||||||
|
|
||||||
|
##############################################################################
|
||||||
|
# Compile options
|
||||||
|
#
|
||||||
|
CFLAGS := -O0 -g -fPIC -Wall $(WARNINGS)
|
||||||
|
CFLAGS += -std=gnu99
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
# Linker options
|
||||||
|
#
|
||||||
|
# Link script
|
||||||
|
LDFLAGS = -Tlinker.lds -Wl,-Map=$(TARGET).map
|
||||||
|
#pthread
|
||||||
|
LDFLAGS += -pthread -lpthread
|
||||||
|
|
||||||
|
#############################################################################
|
||||||
|
AS = $(CROSS_COMPILE)as
|
||||||
|
LD = $(CROSS_COMPILE)ld
|
||||||
|
CC = $(CROSS_COMPILE)gcc
|
||||||
|
CPP = $(CC) -E
|
||||||
|
AR = $(CROSS_COMPILE)ar
|
||||||
|
NM = $(CROSS_COMPILE)nm
|
||||||
|
|
||||||
|
#Target directory
|
||||||
|
BIN_DIR := ./output/
|
||||||
|
OBJ_DIR := ./output/obj/
|
||||||
|
TARGET := $(BIN_DIR)$(TARGET_NAME)
|
||||||
|
TOPDIR := $(shell pwd)/
|
||||||
|
|
||||||
|
#Source file directory
|
||||||
|
SRC_DIRS := $(source_path)
|
||||||
|
|
||||||
|
#Search the list of source files
|
||||||
|
CSRCS := $(shell find $(SRC_DIRS) -maxdepth 1 -path '*.c')
|
||||||
|
CSRCS += $(source_files)
|
||||||
|
CSRCS := $(notdir $(CSRCS))
|
||||||
|
#排除文件列表
|
||||||
|
EXCLUDE_LIST := $(notdir $(exclude_files))
|
||||||
|
|
||||||
|
CSRCS := $(filter-out $(EXCLUDE_LIST), $(CSRCS))
|
||||||
|
|
||||||
|
#
|
||||||
|
# Target files(*.o)
|
||||||
|
#
|
||||||
|
OBJS := $(addprefix $(OBJ_DIR),$(CSRCS:.c=.o) )
|
||||||
|
|
||||||
|
|
||||||
|
CFLAGS += $(patsubst %,-I$(TOPDIR)%,$(subst ./, ,$(SRC_DIRS)))
|
||||||
|
CFLAGS += $(addprefix -I$(TOPDIR),$(include_path) )
|
||||||
|
|
||||||
|
#指定搜索目录
|
||||||
|
VPATH += $(addprefix :, $(SRC_DIRS))
|
||||||
|
|
||||||
|
all: default $(TARGET)
|
||||||
|
|
||||||
|
$(TARGET):$(OBJS)
|
||||||
|
@$(CC) $(LDFLAGS) -o $@ $^
|
||||||
|
@echo Creating $(notdir $(TARGET)) ...
|
||||||
|
|
||||||
|
$(OBJ_DIR)%.o: %.c
|
||||||
|
@echo 'Compiling ' $< ...
|
||||||
|
@$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
|
||||||
|
.PHONY: all clean default
|
||||||
|
|
||||||
|
#创建输出目录
|
||||||
|
default:
|
||||||
|
@rm -rf $(TARGET)
|
||||||
|
@mkdir -p $(BIN_DIR)
|
||||||
|
@mkdir -p $(OBJ_DIR)
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf $(TARGET).map
|
||||||
|
rm -rf $(TARGET)
|
||||||
|
@rm -rf $(OBJS)
|
||||||
|
@rm -rf tmp
|
6
samples/linux/readme.md
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
.atcmd :
|
||||||
|
{
|
||||||
|
KEEP (*(SORT(cli.cmd.*)))
|
||||||
|
}
|
125
samples/linux/src/at_device.c
Normal file
@ -0,0 +1,125 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* @brief AT命令模拟器
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
* 2022-04-01 Roger.luo 初版
|
||||||
|
******************************************************************************/
|
||||||
|
#include "cli.h"
|
||||||
|
#include "at_device.h"
|
||||||
|
#include "ringbuffer.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <sys/poll.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief AT设备
|
||||||
|
*/
|
||||||
|
typedef struct {
|
||||||
|
cli_obj_t cli;
|
||||||
|
ring_buf_t rb_tx;
|
||||||
|
ring_buf_t rb_rx;
|
||||||
|
unsigned char txbuf[1024];
|
||||||
|
unsigned char rxbuf[512];
|
||||||
|
} at_device_t;
|
||||||
|
|
||||||
|
static at_device_t at_device;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 数据写操作
|
||||||
|
*/
|
||||||
|
static unsigned int cli_write(const void *buf, unsigned int size)
|
||||||
|
{
|
||||||
|
return ring_buf_put(&at_device.rb_tx, (unsigned char *)buf, size);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief 数据读操作
|
||||||
|
*/
|
||||||
|
static unsigned int cli_read(void *buf, unsigned int size)
|
||||||
|
{
|
||||||
|
return ring_buf_get(&at_device.rb_rx, buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 命令处理任务
|
||||||
|
*/
|
||||||
|
static void *at_device_thread(void *args)
|
||||||
|
{
|
||||||
|
pthread_detach(pthread_self());
|
||||||
|
printf("at devicce running...\r\n");
|
||||||
|
while(1) {
|
||||||
|
usleep(1000);
|
||||||
|
cli_process(&at_device.cli);
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief AT模拟器初始化()
|
||||||
|
*/
|
||||||
|
void at_device_init(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
cli_port_t p = {cli_write, cli_read, NULL}; /*读写接口 */
|
||||||
|
/*初始化环形缓冲区 */
|
||||||
|
ring_buf_init(&at_device.rb_rx, at_device.rxbuf, sizeof(at_device.rxbuf));
|
||||||
|
ring_buf_init(&at_device.rb_tx, at_device.txbuf, sizeof(at_device.txbuf));
|
||||||
|
|
||||||
|
cli_init(&at_device.cli, &p); /*初始化命令行对象 */
|
||||||
|
cli_enable(&at_device.cli);
|
||||||
|
pthread_t tid;
|
||||||
|
pthread_create(&tid, NULL, at_device_thread, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 数据写操作
|
||||||
|
* @param buf 数据缓冲区
|
||||||
|
* @param size 缓冲区长度
|
||||||
|
* @retval 实际写入数据
|
||||||
|
*/
|
||||||
|
unsigned int at_device_write(const void *buf, unsigned int size)
|
||||||
|
{
|
||||||
|
return ring_buf_put(&at_device.rb_rx, (unsigned char *)buf, size);
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* @brief 数据读操作
|
||||||
|
* @param buf 数据缓冲区
|
||||||
|
* @param size 缓冲区长度
|
||||||
|
* @retval 实际读到的数据
|
||||||
|
*/
|
||||||
|
unsigned int at_device_read(void *buf, unsigned int size)
|
||||||
|
{
|
||||||
|
return ring_buf_get(&at_device.rb_tx, buf, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 触发生成URC消息
|
||||||
|
*/
|
||||||
|
void at_device_emit_urc(const void *urc, int size)
|
||||||
|
{
|
||||||
|
cli_write(urc, size);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 打开AT设备(将触发 "+POWER:1" URC消息)
|
||||||
|
*/
|
||||||
|
void at_device_open(void)
|
||||||
|
{
|
||||||
|
char *s = "+POWER:1\r\n";
|
||||||
|
at_device_emit_urc(s, strlen(s));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 关闭AT设备(将触发 "+POWER:0" URC消息)
|
||||||
|
*/
|
||||||
|
void at_device_close(void)
|
||||||
|
{
|
||||||
|
char *s = "+POWER:0\r\n";
|
||||||
|
at_device_emit_urc(s, strlen(s));
|
||||||
|
}
|
35
samples/linux/src/at_port_linux.c
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
/**
|
||||||
|
* @Brief: The AT component drives the interface implementation
|
||||||
|
* @Author: roger.luo
|
||||||
|
* @Date: 2021-04-04
|
||||||
|
* @Last Modified by: roger.luo
|
||||||
|
* @Last Modified time: 2021-11-27
|
||||||
|
*/
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Custom malloc for AT component.
|
||||||
|
*/
|
||||||
|
void *at_malloc(unsigned int nbytes)
|
||||||
|
{
|
||||||
|
return malloc(nbytes);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Custom free for AT component.
|
||||||
|
*/
|
||||||
|
void at_free(void *ptr)
|
||||||
|
{
|
||||||
|
free(ptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Gets the total number of milliseconds in the system.
|
||||||
|
*/
|
||||||
|
unsigned int at_get_ms(void)
|
||||||
|
{
|
||||||
|
struct timeval tv_now;
|
||||||
|
gettimeofday(&tv_now, NULL);
|
||||||
|
return (tv_now.tv_sec * 1000000 + tv_now.tv_usec) / 1000;
|
||||||
|
}
|
307
samples/linux/src/cli.c
Normal file
@ -0,0 +1,307 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* @brief 命令行处理
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015-2022, <master_roger@sina.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
* 2015-06-09 Morro 初版
|
||||||
|
*
|
||||||
|
* 2017-07-04 Morro 优化字段分割处理
|
||||||
|
*
|
||||||
|
* 2020-07-05 roger.luo 使用cli_obj_t对象, 支持多个命令源处理
|
||||||
|
* 2021-08-29 roger.luo 支持AT指令解析及回显控制
|
||||||
|
* 2022-02-16 roger.luo 添加命令行守卫处理程序
|
||||||
|
******************************************************************************/
|
||||||
|
#include "cli.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
static const cmd_item_t cmd_tbl_start SECTION("cli.cmd.0") = {0};
|
||||||
|
static const cmd_item_t cmd_tbl_end SECTION("cli.cmd.4") = {0};
|
||||||
|
/**
|
||||||
|
* @brief 查找命令
|
||||||
|
* @param[in] keyword - 命令关键字
|
||||||
|
* @return 命令项
|
||||||
|
*/
|
||||||
|
static const cmd_item_t *find_cmd(const char *keyword, int n)
|
||||||
|
{
|
||||||
|
const cmd_item_t *it;
|
||||||
|
for (it = &cmd_tbl_start + 1; it < &cmd_tbl_end; it++) {
|
||||||
|
if (it->name != NULL && !strncasecmp(keyword, it->name, n))
|
||||||
|
return it;
|
||||||
|
}
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* @brief 字符串分割 - 在源字符串查找出所有由separator指定的分隔符
|
||||||
|
* (如',')并替换成字符串结束符'\0'形成子串,同时令list
|
||||||
|
* 指针列表中的每一个指针分别指向一个子串
|
||||||
|
* @example
|
||||||
|
* input=> s = "abc,123,456,,fb$"
|
||||||
|
* separator = ",$"
|
||||||
|
*
|
||||||
|
* output=>s = abc'\0' 123'\0' 456'\0' '\0' fb'\0''\0'
|
||||||
|
* list[0] = "abc"
|
||||||
|
* list[1] = "123"
|
||||||
|
* list[2] = "456"
|
||||||
|
* list[3] = ""
|
||||||
|
* list[4] = "fb"
|
||||||
|
* list[5] = ""
|
||||||
|
*
|
||||||
|
* @param[in] str - 源字符串
|
||||||
|
* @param[in] separator - 分隔字符串
|
||||||
|
* @param[in] list - 字符串指针列表
|
||||||
|
* @param[in] len - 列表长度
|
||||||
|
* @return list指针列表项数,如上例所示则返回6
|
||||||
|
******************************************************************************/
|
||||||
|
static size_t strsplit(char *s, const char *separator, char *list[], size_t len)
|
||||||
|
{
|
||||||
|
size_t count = 0;
|
||||||
|
if (s == NULL || list == NULL || len == 0)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
list[count++] = s;
|
||||||
|
while(*s && count < len) {
|
||||||
|
if (strchr(separator, *s) != NULL) {
|
||||||
|
*s = '\0';
|
||||||
|
list[count++] = s + 1; /*指向下一个子串*/
|
||||||
|
}
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
*@brief 打印一个格式化字符串到串口控制台
|
||||||
|
*@retval
|
||||||
|
*/
|
||||||
|
static void cli_print(cli_obj_t *obj, const char *format, ...)
|
||||||
|
{
|
||||||
|
va_list args;
|
||||||
|
int len;
|
||||||
|
char buf[CLI_MAX_CMD_LEN + CLI_MAX_CMD_LEN / 2];
|
||||||
|
va_start (args, format);
|
||||||
|
len = vsnprintf (buf, sizeof(buf), format, args);
|
||||||
|
va_end (args);
|
||||||
|
obj->write(buf, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 处理行
|
||||||
|
* @param[in] line - 命令行
|
||||||
|
* @return none
|
||||||
|
**/
|
||||||
|
static void process_line(cli_obj_t *obj)
|
||||||
|
{
|
||||||
|
char *argv[CLI_MAX_ARGS];
|
||||||
|
int argc, ret, isat = 0;
|
||||||
|
const cmd_item_t *it;
|
||||||
|
|
||||||
|
//命令拦截
|
||||||
|
if (obj->guard && !obj->guard(obj->recvbuf))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (obj->echo) { //回显
|
||||||
|
obj->print(obj,"%s\r\n",obj->recvbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
argc = strsplit(obj->recvbuf, ",",argv, CLI_MAX_ARGS);
|
||||||
|
|
||||||
|
const char *start, *end;
|
||||||
|
|
||||||
|
if (argv[0] == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
#if CLI_AT_ENABLE != 0
|
||||||
|
isat = strncasecmp(argv[0], "AT+", 3) == 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
start= !isat ? argv[0] : argv[0] + 3;
|
||||||
|
|
||||||
|
if ((end = strchr(start, '=')) != NULL) {
|
||||||
|
obj->type = CLI_CMD_TYPE_SET;
|
||||||
|
|
||||||
|
} else if ((end = strchr(start, '?')) != NULL) {
|
||||||
|
obj->type = CLI_CMD_TYPE_QUERY;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
obj->type = CLI_CMD_TYPE_EXEC;
|
||||||
|
end = start + strlen(argv[0]);
|
||||||
|
}
|
||||||
|
if (start == end)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if ((it = find_cmd(start, end - start)) == NULL) {
|
||||||
|
obj->print(obj, "%s\r\n", isat ? "ERROR" : "");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
ret = it->handler(obj, argc, argv);
|
||||||
|
if (isat) {
|
||||||
|
obj->print(obj, "%s\r\n" ,ret ? "OK":"ERROR");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 获取设置值
|
||||||
|
*/
|
||||||
|
static int get_val(struct cli_obj *self)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
p = strchr(self->recvbuf, '=');
|
||||||
|
if ( p == NULL)
|
||||||
|
return 0;
|
||||||
|
return atoi(p + 1);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief cli 初始化
|
||||||
|
* @param[in] p - cli驱动接口
|
||||||
|
* @return none
|
||||||
|
*/
|
||||||
|
void cli_init(cli_obj_t *obj, const cli_port_t *p)
|
||||||
|
{
|
||||||
|
obj->read = p->read;
|
||||||
|
obj->write = p->write;
|
||||||
|
obj->print = cli_print;
|
||||||
|
obj->enable = true;
|
||||||
|
obj->get_val = get_val;
|
||||||
|
obj->guard = p->cmd_guard;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 进入cli命令模式(cli此时自动处理用户输入的命令)
|
||||||
|
* @param[in] none
|
||||||
|
* @return none
|
||||||
|
**/
|
||||||
|
void cli_enable(cli_obj_t *obj)
|
||||||
|
{
|
||||||
|
char a;
|
||||||
|
obj->enable = true;
|
||||||
|
obj->recvcnt = 0;
|
||||||
|
while (obj->read(&a, 1) > 0) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 退出cli命令模式(cli此时不再处理用户输入的命令)
|
||||||
|
* @param[in] none
|
||||||
|
* @return none
|
||||||
|
**/
|
||||||
|
void cli_disable (cli_obj_t *obj)
|
||||||
|
{
|
||||||
|
obj->enable = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 回显控制
|
||||||
|
* @param[in] echo - 回显开关控制(0/1)
|
||||||
|
* @return none
|
||||||
|
**/
|
||||||
|
void cli_echo_ctrl (cli_obj_t *obj, int echo)
|
||||||
|
{
|
||||||
|
obj->echo = echo;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 执行一行命令(无论cli是否运行,都会执行)
|
||||||
|
* @param[in] none
|
||||||
|
* @return none
|
||||||
|
**/
|
||||||
|
void cli_exec_cmd(cli_obj_t *obj, const char *cmd)
|
||||||
|
{
|
||||||
|
int len = strlen(cmd);
|
||||||
|
if (len >= CLI_MAX_CMD_LEN - 1)
|
||||||
|
return;
|
||||||
|
strcpy(obj->recvbuf, cmd);
|
||||||
|
process_line(obj);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief 命令行处理程序
|
||||||
|
* @param[in] none
|
||||||
|
* @return none
|
||||||
|
**/
|
||||||
|
void cli_process(cli_obj_t *obj)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
if (!obj->read || !obj->enable)
|
||||||
|
return;
|
||||||
|
i = obj->recvcnt;
|
||||||
|
obj->recvcnt += obj->read(&obj->recvbuf[i], CLI_MAX_CMD_LEN - i);
|
||||||
|
while (i < obj->recvcnt) {
|
||||||
|
if (obj->recvbuf[i] == '\r' || obj->recvbuf[i] == '\n' || obj->recvbuf[i] == '\0') { /*读取1行*/
|
||||||
|
obj->recvbuf[i] = '\0';
|
||||||
|
process_line(obj);
|
||||||
|
obj->recvcnt = 0;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
if (obj->recvcnt >= CLI_MAX_CMD_LEN) /*缓冲区满之后强制清空*/
|
||||||
|
obj->recvcnt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
/*******************************************************************************
|
||||||
|
* @brief 命令比较器
|
||||||
|
* @param[in] none
|
||||||
|
* @return 参考strcmp
|
||||||
|
*******************************************************************************/
|
||||||
|
static int cmd_item_comparer(const void *item1,const void *item2)
|
||||||
|
{
|
||||||
|
cmd_item_t *it1 = *((cmd_item_t **)item1);
|
||||||
|
cmd_item_t *it2 = *((cmd_item_t **)item2);
|
||||||
|
return strcmp(it1->name, it2->name);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief 帮助命令
|
||||||
|
*/
|
||||||
|
static int do_help (struct cli_obj *s, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int i,j, count;
|
||||||
|
const cmd_item_t *item_start = &cmd_tbl_start + 1;
|
||||||
|
const cmd_item_t *item_end = &cmd_tbl_end;
|
||||||
|
const cmd_item_t *cmdtbl[CLI_MAX_CMDS];
|
||||||
|
|
||||||
|
if (argc == 2) {
|
||||||
|
if ((item_start = find_cmd(argv[1], strlen(argv[1]))) != NULL)
|
||||||
|
{
|
||||||
|
s->print(s, item_start->brief); /*命令使用信息----*/
|
||||||
|
s->print(s, "\r\n");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (i = 0; i < item_end - item_start && i < CLI_MAX_ARGS; i++)
|
||||||
|
cmdtbl[i] = &item_start[i];
|
||||||
|
count = i;
|
||||||
|
/*对命令进行排序 ---------------------------------------------------------*/
|
||||||
|
qsort(cmdtbl, i, sizeof(cmd_item_t*), cmd_item_comparer);
|
||||||
|
s->print(s, "\r\n");
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
s->print(s, cmdtbl[i]->name); /*打印命令名------*/
|
||||||
|
/*对齐调整*/
|
||||||
|
j = strlen(cmdtbl[i]->name);
|
||||||
|
if (j < 10)
|
||||||
|
j = 10 - j;
|
||||||
|
|
||||||
|
while (j--)
|
||||||
|
s->print(s, " ");
|
||||||
|
|
||||||
|
s->print(s, "- ");
|
||||||
|
s->print(s, cmdtbl[i]->brief); /*命令使用信息----*/
|
||||||
|
s->print(s, "\r\n");
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*注册帮助命令 ---------------------------------------------------------------*/
|
||||||
|
cmd_register("help", do_help, "list all command.");
|
||||||
|
cmd_register("?", do_help, "alias for 'help'");
|
99
samples/linux/src/ringbuffer.c
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* @brief 环形缓冲区管理(参考linux/kfifo)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016~2021, <morro_luo@163.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
* 2016-05-30 Morro Initial version
|
||||||
|
* 2021-02-05 Morro 增加空闲空间获取接口.
|
||||||
|
******************************************************************************/
|
||||||
|
#include "ringbuffer.h"
|
||||||
|
#include <string.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
#define min(a,b) ( (a) < (b) )? (a):(b)
|
||||||
|
|
||||||
|
/*
|
||||||
|
*@brief 构造一个空环形缓冲区
|
||||||
|
*@param[in] r - 环形缓冲区管理器
|
||||||
|
*@param[in] buf - 数据缓冲区
|
||||||
|
*@param[in] len - buf长度(必须是2的N次幂)
|
||||||
|
*@retval bool
|
||||||
|
*/
|
||||||
|
bool ring_buf_init(ring_buf_t *r,unsigned char *buf, unsigned int len)
|
||||||
|
{
|
||||||
|
r->buf = buf;
|
||||||
|
r->size = len;
|
||||||
|
r->front = r->rear = 0;
|
||||||
|
return buf != NULL && (len & len -1) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*@brief 清空环形缓冲区
|
||||||
|
*@param[in] r - 待清空的环形缓冲区
|
||||||
|
*@retval none
|
||||||
|
*/
|
||||||
|
void ring_buf_clr(ring_buf_t *r)
|
||||||
|
{
|
||||||
|
r->front = r->rear = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*@brief 获取环形缓冲区数据长度
|
||||||
|
*@retval 环形缓冲区中有效字节数
|
||||||
|
*/
|
||||||
|
unsigned int ring_buf_len(ring_buf_t *r)
|
||||||
|
{
|
||||||
|
return r->rear - r->front;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*@brief 获取环形缓冲空闲空间
|
||||||
|
*@retval 空闲空间
|
||||||
|
*/
|
||||||
|
unsigned int ring_buf_free_space(ring_buf_t *r)
|
||||||
|
{
|
||||||
|
return r->size - (unsigned int)(r->rear - r->front);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*@brief 将指定长度的数据放到环形缓冲区中
|
||||||
|
*@param[in] buf - 数据缓冲区
|
||||||
|
* len - 缓冲区长度
|
||||||
|
*@retval 实际放到中的数据
|
||||||
|
*/
|
||||||
|
unsigned int ring_buf_put(ring_buf_t *r,unsigned char *buf,unsigned int len)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
unsigned int left;
|
||||||
|
left = r->size + r->front - r->rear;
|
||||||
|
len = min(len , left);
|
||||||
|
i = min(len, r->size - (r->rear & r->size - 1));
|
||||||
|
memcpy(r->buf + (r->rear & r->size - 1), buf, i);
|
||||||
|
memcpy(r->buf, buf + i, len - i);
|
||||||
|
r->rear += len;
|
||||||
|
return len;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
*@brief 从环形缓冲区中读取指定长度的数据
|
||||||
|
*@param[in] len - 读取长度
|
||||||
|
*@param[out] buf - 输出数据缓冲区
|
||||||
|
*@retval 实际读取长度
|
||||||
|
*/
|
||||||
|
unsigned int ring_buf_get(ring_buf_t *r,unsigned char *buf,unsigned int len)
|
||||||
|
{
|
||||||
|
unsigned int i;
|
||||||
|
unsigned int left;
|
||||||
|
left = r->rear - r->front;
|
||||||
|
len = min(len , left);
|
||||||
|
i = min(len, r->size - (r->front & r->size - 1));
|
||||||
|
memcpy(buf, r->buf + (r->front & r->size - 1), i);
|
||||||
|
memcpy(buf + i, r->buf, len - i);
|
||||||
|
r->front += len;
|
||||||
|
return len;
|
||||||
|
}
|
@ -1,201 +1,201 @@
|
|||||||
Apache License
|
Apache License
|
||||||
Version 2.0, January 2004
|
Version 2.0, January 2004
|
||||||
http://www.apache.org/licenses/
|
http://www.apache.org/licenses/
|
||||||
|
|
||||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||||
|
|
||||||
1. Definitions.
|
1. Definitions.
|
||||||
|
|
||||||
"License" shall mean the terms and conditions for use, reproduction,
|
"License" shall mean the terms and conditions for use, reproduction,
|
||||||
and distribution as defined by Sections 1 through 9 of this document.
|
and distribution as defined by Sections 1 through 9 of this document.
|
||||||
|
|
||||||
"Licensor" shall mean the copyright owner or entity authorized by
|
"Licensor" shall mean the copyright owner or entity authorized by
|
||||||
the copyright owner that is granting the License.
|
the copyright owner that is granting the License.
|
||||||
|
|
||||||
"Legal Entity" shall mean the union of the acting entity and all
|
"Legal Entity" shall mean the union of the acting entity and all
|
||||||
other entities that control, are controlled by, or are under common
|
other entities that control, are controlled by, or are under common
|
||||||
control with that entity. For the purposes of this definition,
|
control with that entity. For the purposes of this definition,
|
||||||
"control" means (i) the power, direct or indirect, to cause the
|
"control" means (i) the power, direct or indirect, to cause the
|
||||||
direction or management of such entity, whether by contract or
|
direction or management of such entity, whether by contract or
|
||||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||||
|
|
||||||
"You" (or "Your") shall mean an individual or Legal Entity
|
"You" (or "Your") shall mean an individual or Legal Entity
|
||||||
exercising permissions granted by this License.
|
exercising permissions granted by this License.
|
||||||
|
|
||||||
"Source" form shall mean the preferred form for making modifications,
|
"Source" form shall mean the preferred form for making modifications,
|
||||||
including but not limited to software source code, documentation
|
including but not limited to software source code, documentation
|
||||||
source, and configuration files.
|
source, and configuration files.
|
||||||
|
|
||||||
"Object" form shall mean any form resulting from mechanical
|
"Object" form shall mean any form resulting from mechanical
|
||||||
transformation or translation of a Source form, including but
|
transformation or translation of a Source form, including but
|
||||||
not limited to compiled object code, generated documentation,
|
not limited to compiled object code, generated documentation,
|
||||||
and conversions to other media types.
|
and conversions to other media types.
|
||||||
|
|
||||||
"Work" shall mean the work of authorship, whether in Source or
|
"Work" shall mean the work of authorship, whether in Source or
|
||||||
Object form, made available under the License, as indicated by a
|
Object form, made available under the License, as indicated by a
|
||||||
copyright notice that is included in or attached to the work
|
copyright notice that is included in or attached to the work
|
||||||
(an example is provided in the Appendix below).
|
(an example is provided in the Appendix below).
|
||||||
|
|
||||||
"Derivative Works" shall mean any work, whether in Source or Object
|
"Derivative Works" shall mean any work, whether in Source or Object
|
||||||
form, that is based on (or derived from) the Work and for which the
|
form, that is based on (or derived from) the Work and for which the
|
||||||
editorial revisions, annotations, elaborations, or other modifications
|
editorial revisions, annotations, elaborations, or other modifications
|
||||||
represent, as a whole, an original work of authorship. For the purposes
|
represent, as a whole, an original work of authorship. For the purposes
|
||||||
of this License, Derivative Works shall not include works that remain
|
of this License, Derivative Works shall not include works that remain
|
||||||
separable from, or merely link (or bind by name) to the interfaces of,
|
separable from, or merely link (or bind by name) to the interfaces of,
|
||||||
the Work and Derivative Works thereof.
|
the Work and Derivative Works thereof.
|
||||||
|
|
||||||
"Contribution" shall mean any work of authorship, including
|
"Contribution" shall mean any work of authorship, including
|
||||||
the original version of the Work and any modifications or additions
|
the original version of the Work and any modifications or additions
|
||||||
to that Work or Derivative Works thereof, that is intentionally
|
to that Work or Derivative Works thereof, that is intentionally
|
||||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||||
or by an individual or Legal Entity authorized to submit on behalf of
|
or by an individual or Legal Entity authorized to submit on behalf of
|
||||||
the copyright owner. For the purposes of this definition, "submitted"
|
the copyright owner. For the purposes of this definition, "submitted"
|
||||||
means any form of electronic, verbal, or written communication sent
|
means any form of electronic, verbal, or written communication sent
|
||||||
to the Licensor or its representatives, including but not limited to
|
to the Licensor or its representatives, including but not limited to
|
||||||
communication on electronic mailing lists, source code control systems,
|
communication on electronic mailing lists, source code control systems,
|
||||||
and issue tracking systems that are managed by, or on behalf of, the
|
and issue tracking systems that are managed by, or on behalf of, the
|
||||||
Licensor for the purpose of discussing and improving the Work, but
|
Licensor for the purpose of discussing and improving the Work, but
|
||||||
excluding communication that is conspicuously marked or otherwise
|
excluding communication that is conspicuously marked or otherwise
|
||||||
designated in writing by the copyright owner as "Not a Contribution."
|
designated in writing by the copyright owner as "Not a Contribution."
|
||||||
|
|
||||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||||
on behalf of whom a Contribution has been received by Licensor and
|
on behalf of whom a Contribution has been received by Licensor and
|
||||||
subsequently incorporated within the Work.
|
subsequently incorporated within the Work.
|
||||||
|
|
||||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
copyright license to reproduce, prepare Derivative Works of,
|
copyright license to reproduce, prepare Derivative Works of,
|
||||||
publicly display, publicly perform, sublicense, and distribute the
|
publicly display, publicly perform, sublicense, and distribute the
|
||||||
Work and such Derivative Works in Source or Object form.
|
Work and such Derivative Works in Source or Object form.
|
||||||
|
|
||||||
3. Grant of Patent License. Subject to the terms and conditions of
|
3. Grant of Patent License. Subject to the terms and conditions of
|
||||||
this License, each Contributor hereby grants to You a perpetual,
|
this License, each Contributor hereby grants to You a perpetual,
|
||||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||||
(except as stated in this section) patent license to make, have made,
|
(except as stated in this section) patent license to make, have made,
|
||||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||||
where such license applies only to those patent claims licensable
|
where such license applies only to those patent claims licensable
|
||||||
by such Contributor that are necessarily infringed by their
|
by such Contributor that are necessarily infringed by their
|
||||||
Contribution(s) alone or by combination of their Contribution(s)
|
Contribution(s) alone or by combination of their Contribution(s)
|
||||||
with the Work to which such Contribution(s) was submitted. If You
|
with the Work to which such Contribution(s) was submitted. If You
|
||||||
institute patent litigation against any entity (including a
|
institute patent litigation against any entity (including a
|
||||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||||
or a Contribution incorporated within the Work constitutes direct
|
or a Contribution incorporated within the Work constitutes direct
|
||||||
or contributory patent infringement, then any patent licenses
|
or contributory patent infringement, then any patent licenses
|
||||||
granted to You under this License for that Work shall terminate
|
granted to You under this License for that Work shall terminate
|
||||||
as of the date such litigation is filed.
|
as of the date such litigation is filed.
|
||||||
|
|
||||||
4. Redistribution. You may reproduce and distribute copies of the
|
4. Redistribution. You may reproduce and distribute copies of the
|
||||||
Work or Derivative Works thereof in any medium, with or without
|
Work or Derivative Works thereof in any medium, with or without
|
||||||
modifications, and in Source or Object form, provided that You
|
modifications, and in Source or Object form, provided that You
|
||||||
meet the following conditions:
|
meet the following conditions:
|
||||||
|
|
||||||
(a) You must give any other recipients of the Work or
|
(a) You must give any other recipients of the Work or
|
||||||
Derivative Works a copy of this License; and
|
Derivative Works a copy of this License; and
|
||||||
|
|
||||||
(b) You must cause any modified files to carry prominent notices
|
(b) You must cause any modified files to carry prominent notices
|
||||||
stating that You changed the files; and
|
stating that You changed the files; and
|
||||||
|
|
||||||
(c) You must retain, in the Source form of any Derivative Works
|
(c) You must retain, in the Source form of any Derivative Works
|
||||||
that You distribute, all copyright, patent, trademark, and
|
that You distribute, all copyright, patent, trademark, and
|
||||||
attribution notices from the Source form of the Work,
|
attribution notices from the Source form of the Work,
|
||||||
excluding those notices that do not pertain to any part of
|
excluding those notices that do not pertain to any part of
|
||||||
the Derivative Works; and
|
the Derivative Works; and
|
||||||
|
|
||||||
(d) If the Work includes a "NOTICE" text file as part of its
|
(d) If the Work includes a "NOTICE" text file as part of its
|
||||||
distribution, then any Derivative Works that You distribute must
|
distribution, then any Derivative Works that You distribute must
|
||||||
include a readable copy of the attribution notices contained
|
include a readable copy of the attribution notices contained
|
||||||
within such NOTICE file, excluding those notices that do not
|
within such NOTICE file, excluding those notices that do not
|
||||||
pertain to any part of the Derivative Works, in at least one
|
pertain to any part of the Derivative Works, in at least one
|
||||||
of the following places: within a NOTICE text file distributed
|
of the following places: within a NOTICE text file distributed
|
||||||
as part of the Derivative Works; within the Source form or
|
as part of the Derivative Works; within the Source form or
|
||||||
documentation, if provided along with the Derivative Works; or,
|
documentation, if provided along with the Derivative Works; or,
|
||||||
within a display generated by the Derivative Works, if and
|
within a display generated by the Derivative Works, if and
|
||||||
wherever such third-party notices normally appear. The contents
|
wherever such third-party notices normally appear. The contents
|
||||||
of the NOTICE file are for informational purposes only and
|
of the NOTICE file are for informational purposes only and
|
||||||
do not modify the License. You may add Your own attribution
|
do not modify the License. You may add Your own attribution
|
||||||
notices within Derivative Works that You distribute, alongside
|
notices within Derivative Works that You distribute, alongside
|
||||||
or as an addendum to the NOTICE text from the Work, provided
|
or as an addendum to the NOTICE text from the Work, provided
|
||||||
that such additional attribution notices cannot be construed
|
that such additional attribution notices cannot be construed
|
||||||
as modifying the License.
|
as modifying the License.
|
||||||
|
|
||||||
You may add Your own copyright statement to Your modifications and
|
You may add Your own copyright statement to Your modifications and
|
||||||
may provide additional or different license terms and conditions
|
may provide additional or different license terms and conditions
|
||||||
for use, reproduction, or distribution of Your modifications, or
|
for use, reproduction, or distribution of Your modifications, or
|
||||||
for any such Derivative Works as a whole, provided Your use,
|
for any such Derivative Works as a whole, provided Your use,
|
||||||
reproduction, and distribution of the Work otherwise complies with
|
reproduction, and distribution of the Work otherwise complies with
|
||||||
the conditions stated in this License.
|
the conditions stated in this License.
|
||||||
|
|
||||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||||
any Contribution intentionally submitted for inclusion in the Work
|
any Contribution intentionally submitted for inclusion in the Work
|
||||||
by You to the Licensor shall be under the terms and conditions of
|
by You to the Licensor shall be under the terms and conditions of
|
||||||
this License, without any additional terms or conditions.
|
this License, without any additional terms or conditions.
|
||||||
Notwithstanding the above, nothing herein shall supersede or modify
|
Notwithstanding the above, nothing herein shall supersede or modify
|
||||||
the terms of any separate license agreement you may have executed
|
the terms of any separate license agreement you may have executed
|
||||||
with Licensor regarding such Contributions.
|
with Licensor regarding such Contributions.
|
||||||
|
|
||||||
6. Trademarks. This License does not grant permission to use the trade
|
6. Trademarks. This License does not grant permission to use the trade
|
||||||
names, trademarks, service marks, or product names of the Licensor,
|
names, trademarks, service marks, or product names of the Licensor,
|
||||||
except as required for reasonable and customary use in describing the
|
except as required for reasonable and customary use in describing the
|
||||||
origin of the Work and reproducing the content of the NOTICE file.
|
origin of the Work and reproducing the content of the NOTICE file.
|
||||||
|
|
||||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||||
agreed to in writing, Licensor provides the Work (and each
|
agreed to in writing, Licensor provides the Work (and each
|
||||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||||
implied, including, without limitation, any warranties or conditions
|
implied, including, without limitation, any warranties or conditions
|
||||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||||
appropriateness of using or redistributing the Work and assume any
|
appropriateness of using or redistributing the Work and assume any
|
||||||
risks associated with Your exercise of permissions under this License.
|
risks associated with Your exercise of permissions under this License.
|
||||||
|
|
||||||
8. Limitation of Liability. In no event and under no legal theory,
|
8. Limitation of Liability. In no event and under no legal theory,
|
||||||
whether in tort (including negligence), contract, or otherwise,
|
whether in tort (including negligence), contract, or otherwise,
|
||||||
unless required by applicable law (such as deliberate and grossly
|
unless required by applicable law (such as deliberate and grossly
|
||||||
negligent acts) or agreed to in writing, shall any Contributor be
|
negligent acts) or agreed to in writing, shall any Contributor be
|
||||||
liable to You for damages, including any direct, indirect, special,
|
liable to You for damages, including any direct, indirect, special,
|
||||||
incidental, or consequential damages of any character arising as a
|
incidental, or consequential damages of any character arising as a
|
||||||
result of this License or out of the use or inability to use the
|
result of this License or out of the use or inability to use the
|
||||||
Work (including but not limited to damages for loss of goodwill,
|
Work (including but not limited to damages for loss of goodwill,
|
||||||
work stoppage, computer failure or malfunction, or any and all
|
work stoppage, computer failure or malfunction, or any and all
|
||||||
other commercial damages or losses), even if such Contributor
|
other commercial damages or losses), even if such Contributor
|
||||||
has been advised of the possibility of such damages.
|
has been advised of the possibility of such damages.
|
||||||
|
|
||||||
9. Accepting Warranty or Additional Liability. While redistributing
|
9. Accepting Warranty or Additional Liability. While redistributing
|
||||||
the Work or Derivative Works thereof, You may choose to offer,
|
the Work or Derivative Works thereof, You may choose to offer,
|
||||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||||
or other liability obligations and/or rights consistent with this
|
or other liability obligations and/or rights consistent with this
|
||||||
License. However, in accepting such obligations, You may act only
|
License. However, in accepting such obligations, You may act only
|
||||||
on Your own behalf and on Your sole responsibility, not on behalf
|
on Your own behalf and on Your sole responsibility, not on behalf
|
||||||
of any other Contributor, and only if You agree to indemnify,
|
of any other Contributor, and only if You agree to indemnify,
|
||||||
defend, and hold each Contributor harmless for any liability
|
defend, and hold each Contributor harmless for any liability
|
||||||
incurred by, or claims asserted against, such Contributor by reason
|
incurred by, or claims asserted against, such Contributor by reason
|
||||||
of your accepting any such warranty or additional liability.
|
of your accepting any such warranty or additional liability.
|
||||||
|
|
||||||
END OF TERMS AND CONDITIONS
|
END OF TERMS AND CONDITIONS
|
||||||
|
|
||||||
APPENDIX: How to apply the Apache License to your work.
|
APPENDIX: How to apply the Apache License to your work.
|
||||||
|
|
||||||
To apply the Apache License to your work, attach the following
|
To apply the Apache License to your work, attach the following
|
||||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||||
replaced with your own identifying information. (Don't include
|
replaced with your own identifying information. (Don't include
|
||||||
the brackets!) The text should be enclosed in the appropriate
|
the brackets!) The text should be enclosed in the appropriate
|
||||||
comment syntax for the file format. We also recommend that a
|
comment syntax for the file format. We also recommend that a
|
||||||
file or class name and description of purpose be included on the
|
file or class name and description of purpose be included on the
|
||||||
same "printed page" as the copyright notice for easier
|
same "printed page" as the copyright notice for easier
|
||||||
identification within third-party archives.
|
identification within third-party archives.
|
||||||
|
|
||||||
Copyright [2015~2020] [master_roger@sina.com]
|
Copyright [2015~2020] [master_roger@sina.com]
|
||||||
|
|
||||||
Licensed under the Apache License, Version 2.0 (the "License");
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
you may not use this file except in compliance with the License.
|
you may not use this file except in compliance with the License.
|
||||||
You may obtain a copy of the License at
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
http://www.apache.org/licenses/LICENSE-2.0
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
Unless required by applicable law or agreed to in writing, software
|
Unless required by applicable law or agreed to in writing, software
|
||||||
distributed under the License is distributed on an "AS IS" BASIS,
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
See the License for the specific language governing permissions and
|
See the License for the specific language governing permissions and
|
||||||
limitations under the License.
|
limitations under the License.
|
@ -1,21 +1,21 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* @brief ST mcu Ƭ<EFBFBD><EFBFBD>flash<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief ST mcu Ƭ<EFBFBD><EFBFBD>flash<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
*
|
*
|
||||||
* Copyright (c) 2018~2020, <morro_luo@163.com>
|
* Copyright (c) 2018~2020, <morro_luo@163.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2018-09-09 Morro Initial version
|
* 2018-09-09 roger.luo Initial version
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#ifndef _MCU_FLASH_H_
|
#ifndef _MCU_FLASH_H_
|
||||||
#define _MCU_FLASH_H_
|
#define _MCU_FLASH_H_
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
int mcu_flash_erase(unsigned int addr, size_t size);
|
int mcu_flash_erase(unsigned int addr, size_t size);
|
||||||
int mcu_flash_write(unsigned int addr ,const void *buf, size_t size);
|
int mcu_flash_write(unsigned int addr ,const void *buf, size_t size);
|
||||||
int mcu_flash_read(unsigned int addr ,void *buf, size_t size);
|
int mcu_flash_read(unsigned int addr ,void *buf, size_t size);
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,30 +1,30 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* @brief tty<EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>ӡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief tty<EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>ӡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015, <morro_luo@163.com>
|
* Copyright (c) 2015, <morro_luo@163.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2015-07-03 Morro
|
* 2015-07-03 Morro
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#ifndef _TTY_H_
|
#ifndef _TTY_H_
|
||||||
#define _TTY_H_
|
#define _TTY_H_
|
||||||
|
|
||||||
#define TTY_RXBUF_SIZE 256
|
#define TTY_RXBUF_SIZE 256
|
||||||
#define TTY_TXBUF_SIZE 1024
|
#define TTY_TXBUF_SIZE 1024
|
||||||
|
|
||||||
/*<2A>ӿ<EFBFBD><D3BF><EFBFBD><EFBFBD><EFBFBD> --------------------------------------------------------------------*/
|
/*<2A>ӿ<EFBFBD><D3BF><EFBFBD><EFBFBD><EFBFBD> --------------------------------------------------------------------*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void (*init)(int baudrate);
|
void (*init)(int baudrate);
|
||||||
unsigned int (*write)(const void *buf, unsigned int len);
|
unsigned int (*write)(const void *buf, unsigned int len);
|
||||||
unsigned int (*read)(void *buf, unsigned int len);
|
unsigned int (*read)(void *buf, unsigned int len);
|
||||||
bool (*tx_isfull)(void); /*<2A><><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
bool (*tx_isfull)(void); /*<2A><><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
bool (*rx_isempty)(void); /*<2A><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
bool (*rx_isempty)(void); /*<2A><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
}tty_t;
|
}tty_t;
|
||||||
|
|
||||||
extern const tty_t tty;
|
extern const tty_t tty;
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,28 +1,28 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* @brief wifi<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief wifi<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
*
|
*
|
||||||
* Copyright (c) 2021, <morro_luo@163.com>
|
* Copyright (c) 2021, <morro_luo@163.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2021-01-20 Morro <EFBFBD><EFBFBD>ʼ<EFBFBD>汾
|
* 2021-01-20 roger.luo <EFBFBD><EFBFBD>ʼ<EFBFBD>汾
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#ifndef _WIFI_UART_H_
|
#ifndef _WIFI_UART_H_
|
||||||
#define _WIFI_UART_H_
|
#define _WIFI_UART_H_
|
||||||
|
|
||||||
#define WIFI_RXBUF_SIZE 256
|
#define WIFI_RXBUF_SIZE 256
|
||||||
#define WIFI_TXBUF_SIZE 1024
|
#define WIFI_TXBUF_SIZE 1024
|
||||||
|
|
||||||
/*<2A>ӿ<EFBFBD><D3BF><EFBFBD><EFBFBD><EFBFBD> --------------------------------------------------------------------*/
|
/*<2A>ӿ<EFBFBD><D3BF><EFBFBD><EFBFBD><EFBFBD> --------------------------------------------------------------------*/
|
||||||
void wifi_uart_init(int baud_rate);
|
void wifi_uart_init(int baud_rate);
|
||||||
|
|
||||||
unsigned int wifi_uart_write(const void *buf, unsigned int len);
|
unsigned int wifi_uart_write(const void *buf, unsigned int len);
|
||||||
|
|
||||||
unsigned int wifi_uart_read(void *buf, unsigned int len);
|
unsigned int wifi_uart_read(void *buf, unsigned int len);
|
||||||
|
|
||||||
bool wifi_uart_rx_empty(void);
|
bool wifi_uart_rx_empty(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,161 +1,161 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* @brief ST mcu Ƭ<EFBFBD><EFBFBD>flash<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief ST mcu Ƭ<EFBFBD><EFBFBD>flash<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
*
|
*
|
||||||
* Copyright (c) 2018~2020, <morro_luo@163.com>
|
* Copyright (c) 2018~2020, <morro_luo@163.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2018-09-09 Morro Initial version
|
* 2018-09-09 roger.luo Initial version
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#include "mcu_flash.h"
|
#include "mcu_flash.h"
|
||||||
#include "stm32f4xx.h"
|
#include "stm32f4xx.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned int start;
|
unsigned int start;
|
||||||
unsigned int size;
|
unsigned int size;
|
||||||
unsigned int secnum;
|
unsigned int secnum;
|
||||||
}sec_info_t;
|
}sec_info_t;
|
||||||
|
|
||||||
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַӳ<D6B7><D3B3> ---------------------------------------------------------------*/
|
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַӳ<D6B7><D3B3> ---------------------------------------------------------------*/
|
||||||
const sec_info_t sec_map[] =
|
const sec_info_t sec_map[] =
|
||||||
{
|
{
|
||||||
{0x08000000, 16*1024, FLASH_Sector_0},
|
{0x08000000, 16*1024, FLASH_Sector_0},
|
||||||
{0x08004000, 16*1024, FLASH_Sector_1},
|
{0x08004000, 16*1024, FLASH_Sector_1},
|
||||||
{0x08008000, 16*1024, FLASH_Sector_2},
|
{0x08008000, 16*1024, FLASH_Sector_2},
|
||||||
{0x0800C000, 16*1024, FLASH_Sector_3},
|
{0x0800C000, 16*1024, FLASH_Sector_3},
|
||||||
{0x08010000, 64*1024, FLASH_Sector_4},
|
{0x08010000, 64*1024, FLASH_Sector_4},
|
||||||
{0x08020000, 128*1024, FLASH_Sector_5},
|
{0x08020000, 128*1024, FLASH_Sector_5},
|
||||||
{0x08040000, 128*1024, FLASH_Sector_6},
|
{0x08040000, 128*1024, FLASH_Sector_6},
|
||||||
{0x08040000, 128*1024, FLASH_Sector_7}
|
{0x08040000, 128*1024, FLASH_Sector_7}
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief stm32 mcu <EFBFBD>ڲ<EFBFBD>flash<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief stm32 mcu <EFBFBD>ڲ<EFBFBD>flash<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] addr - <EFBFBD><EFBFBD>ַ
|
* @param[in] addr - <EFBFBD><EFBFBD>ַ
|
||||||
* @param[in] ̽<EFBFBD>մ<EFBFBD>С - size
|
* @param[in] ̽<EFBFBD>մ<EFBFBD>С - size
|
||||||
* @return 0 - ʧ<EFBFBD><EFBFBD>, <EFBFBD><EFBFBD>0 - <EFBFBD>ɹ<EFBFBD>
|
* @return 0 - ʧ<EFBFBD><EFBFBD>, <EFBFBD><EFBFBD>0 - <EFBFBD>ɹ<EFBFBD>
|
||||||
*/
|
*/
|
||||||
int mcu_flash_erase(unsigned int addr, size_t size)
|
int mcu_flash_erase(unsigned int addr, size_t size)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
int len = sizeof(sec_map) / sizeof(sec_info_t);
|
int len = sizeof(sec_map) / sizeof(sec_info_t);
|
||||||
const sec_info_t *sec = &sec_map[len - 1];
|
const sec_info_t *sec = &sec_map[len - 1];
|
||||||
|
|
||||||
FLASH_Status status;
|
FLASH_Status status;
|
||||||
|
|
||||||
/*Խ<>紦<EFBFBD><E7B4A6>*/
|
/*Խ<>紦<EFBFBD><E7B4A6>*/
|
||||||
if (addr > sec->start + sec->size)
|
if (addr > sec->start + sec->size)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
FLASH_Unlock();
|
FLASH_Unlock();
|
||||||
for (i = 0; i < len; i++)
|
for (i = 0; i < len; i++)
|
||||||
{
|
{
|
||||||
sec = &sec_map[i];
|
sec = &sec_map[i];
|
||||||
if ( (sec->start >= addr && sec->start < addr + size) ||
|
if ( (sec->start >= addr && sec->start < addr + size) ||
|
||||||
(sec->start + sec->size > addr && sec->start + sec->size <= addr + size))
|
(sec->start + sec->size > addr && sec->start + sec->size <= addr + size))
|
||||||
{
|
{
|
||||||
//FLASH_OB_WRPConfig();
|
//FLASH_OB_WRPConfig();
|
||||||
status = FLASH_EraseSector(sec->secnum, VoltageRange_2);
|
status = FLASH_EraseSector(sec->secnum, VoltageRange_2);
|
||||||
if (status != FLASH_COMPLETE)
|
if (status != FLASH_COMPLETE)
|
||||||
{
|
{
|
||||||
FLASH_Lock();
|
FLASH_Lock();
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
FLASH_Lock();
|
FLASH_Lock();
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief stm32 mcu <EFBFBD>ڲ<EFBFBD>flashд<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief stm32 mcu <EFBFBD>ڲ<EFBFBD>flashд<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] addr - <EFBFBD><EFBFBD>ַ
|
* @param[in] addr - <EFBFBD><EFBFBD>ַ
|
||||||
* @param[in] buf - <EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] buf - <EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] д<EFBFBD><EFBFBD><EFBFBD><EFBFBD>С - size
|
* @param[in] д<EFBFBD><EFBFBD><EFBFBD><EFBFBD>С - size
|
||||||
* @return 0 - ʧ<EFBFBD><EFBFBD>, <EFBFBD><EFBFBD>0 - <EFBFBD>ɹ<EFBFBD>
|
* @return 0 - ʧ<EFBFBD><EFBFBD>, <EFBFBD><EFBFBD>0 - <EFBFBD>ɹ<EFBFBD>
|
||||||
*/
|
*/
|
||||||
int mcu_flash_write(unsigned int addr ,const void *buf, size_t size)
|
int mcu_flash_write(unsigned int addr ,const void *buf, size_t size)
|
||||||
{
|
{
|
||||||
unsigned char *p = (uint8_t *)buf;
|
unsigned char *p = (uint8_t *)buf;
|
||||||
// unsigned int base = addr;
|
// unsigned int base = addr;
|
||||||
// size_t tlen = size;
|
// size_t tlen = size;
|
||||||
int wrlen;
|
int wrlen;
|
||||||
FLASH_Status status = FLASH_COMPLETE;
|
FLASH_Status status = FLASH_COMPLETE;
|
||||||
int ret = 0;
|
int ret = 0;
|
||||||
FLASH_Unlock();
|
FLASH_Unlock();
|
||||||
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_OPERR |
|
FLASH_ClearFlag(FLASH_FLAG_EOP | FLASH_FLAG_WRPERR | FLASH_FLAG_OPERR |
|
||||||
FLASH_FLAG_PGAERR);
|
FLASH_FLAG_PGAERR);
|
||||||
while (size) {
|
while (size) {
|
||||||
#if 0
|
#if 0
|
||||||
/*<2A><><EFBFBD>ݶ<EFBFBD><DDB6>뷽ʽ<EBB7BD>Ż<EFBFBD>д<EFBFBD>볤<EFBFBD><EBB3A4>*/
|
/*<2A><><EFBFBD>ݶ<EFBFBD><DDB6>뷽ʽ<EBB7BD>Ż<EFBFBD>д<EFBFBD>볤<EFBFBD><EBB3A4>*/
|
||||||
if ((addr & 7) == 0 && size > 8) /*8<>ֽڶ<D6BD><DAB6><EFBFBD>,<2C><>˫<EFBFBD><CBAB>д<EFBFBD><D0B4>*/
|
if ((addr & 7) == 0 && size > 8) /*8<>ֽڶ<D6BD><DAB6><EFBFBD>,<2C><>˫<EFBFBD><CBAB>д<EFBFBD><D0B4>*/
|
||||||
{
|
{
|
||||||
status = FLASH_ProgramDoubleWord(addr, *((uint64_t *)p));
|
status = FLASH_ProgramDoubleWord(addr, *((uint64_t *)p));
|
||||||
if (status != FLASH_COMPLETE)
|
if (status != FLASH_COMPLETE)
|
||||||
goto _quit;
|
goto _quit;
|
||||||
wrlen = 8;
|
wrlen = 8;
|
||||||
}
|
}
|
||||||
else if ((addr & 3) == 0 && size > 4) /*4<>ֽڶ<D6BD><DAB6><EFBFBD>,<2C><><EFBFBD><EFBFBD>д<EFBFBD><D0B4>*/
|
else if ((addr & 3) == 0 && size > 4) /*4<>ֽڶ<D6BD><DAB6><EFBFBD>,<2C><><EFBFBD><EFBFBD>д<EFBFBD><D0B4>*/
|
||||||
{
|
{
|
||||||
status = FLASH_ProgramWord(addr, *((uint32_t *)p));
|
status = FLASH_ProgramWord(addr, *((uint32_t *)p));
|
||||||
if (status != FLASH_COMPLETE)
|
if (status != FLASH_COMPLETE)
|
||||||
goto _quit;
|
goto _quit;
|
||||||
wrlen = 4;
|
wrlen = 4;
|
||||||
}
|
}
|
||||||
else if ((addr & 1) == 0 && size > 2) /*2<>ֽڶ<D6BD><DAB6><EFBFBD>,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4>*/
|
else if ((addr & 1) == 0 && size > 2) /*2<>ֽڶ<D6BD><DAB6><EFBFBD>,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4>*/
|
||||||
{
|
{
|
||||||
status = FLASH_ProgramHalfWord(addr, *((uint16_t *)p));
|
status = FLASH_ProgramHalfWord(addr, *((uint16_t *)p));
|
||||||
if (status != FLASH_COMPLETE)
|
if (status != FLASH_COMPLETE)
|
||||||
goto _quit;
|
goto _quit;
|
||||||
wrlen = 2;
|
wrlen = 2;
|
||||||
}
|
}
|
||||||
else /*<2A><><EFBFBD>ֽ<EFBFBD>д<EFBFBD><D0B4> --------*/
|
else /*<2A><><EFBFBD>ֽ<EFBFBD>д<EFBFBD><D0B4> --------*/
|
||||||
{
|
{
|
||||||
status = FLASH_ProgramByte(addr, *((uint8_t *)p));
|
status = FLASH_ProgramByte(addr, *((uint8_t *)p));
|
||||||
if (status != FLASH_COMPLETE)
|
if (status != FLASH_COMPLETE)
|
||||||
goto _quit;
|
goto _quit;
|
||||||
wrlen = 1;
|
wrlen = 1;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
if ((addr & 1) == 0 && size > 2) /*2<>ֽڶ<D6BD><DAB6><EFBFBD>,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4>*/
|
if ((addr & 1) == 0 && size > 2) /*2<>ֽڶ<D6BD><DAB6><EFBFBD>,<2C><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><D0B4>*/
|
||||||
{
|
{
|
||||||
status = FLASH_ProgramHalfWord(addr, *((uint16_t *)p));
|
status = FLASH_ProgramHalfWord(addr, *((uint16_t *)p));
|
||||||
if (status != FLASH_COMPLETE)
|
if (status != FLASH_COMPLETE)
|
||||||
goto _quit;
|
goto _quit;
|
||||||
wrlen = 2;
|
wrlen = 2;
|
||||||
}
|
}
|
||||||
else /*<2A><><EFBFBD>ֽ<EFBFBD>д<EFBFBD><D0B4> --------*/
|
else /*<2A><><EFBFBD>ֽ<EFBFBD>д<EFBFBD><D0B4> --------*/
|
||||||
{
|
{
|
||||||
status = FLASH_ProgramByte(addr, *((uint8_t *)p));
|
status = FLASH_ProgramByte(addr, *((uint8_t *)p));
|
||||||
if (status != FLASH_COMPLETE)
|
if (status != FLASH_COMPLETE)
|
||||||
goto _quit;
|
goto _quit;
|
||||||
wrlen = 1;
|
wrlen = 1;
|
||||||
}
|
}
|
||||||
/*<2A><>ַƫ<D6B7><C6AB> -------------------------------------------------------*/
|
/*<2A><>ַƫ<D6B7><C6AB> -------------------------------------------------------*/
|
||||||
size -= wrlen;
|
size -= wrlen;
|
||||||
addr += wrlen;
|
addr += wrlen;
|
||||||
p += wrlen;
|
p += wrlen;
|
||||||
}
|
}
|
||||||
_quit:
|
_quit:
|
||||||
|
|
||||||
ret = status == FLASH_COMPLETE;// && memcmp(buf, (void *)base, tlen) ? 1 : 0;
|
ret = status == FLASH_COMPLETE;// && memcmp(buf, (void *)base, tlen) ? 1 : 0;
|
||||||
FLASH_Lock();
|
FLASH_Lock();
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief stm32 mcu <EFBFBD>ڲ<EFBFBD>flash<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief stm32 mcu <EFBFBD>ڲ<EFBFBD>flash<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] addr - <EFBFBD><EFBFBD>ַ
|
* @param[in] addr - <EFBFBD><EFBFBD>ַ
|
||||||
* @param[in] buf - <EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] buf - <EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> - size
|
* @param[in] <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> - size
|
||||||
* @return 0 - ʧ<EFBFBD><EFBFBD>, <EFBFBD><EFBFBD>0 - <EFBFBD>ɹ<EFBFBD>
|
* @return 0 - ʧ<EFBFBD><EFBFBD>, <EFBFBD><EFBFBD>0 - <EFBFBD>ɹ<EFBFBD>
|
||||||
*/
|
*/
|
||||||
int mcu_flash_read(unsigned int addr ,void *buf, size_t size)
|
int mcu_flash_read(unsigned int addr ,void *buf, size_t size)
|
||||||
{
|
{
|
||||||
memcpy(buf, (void *)addr, size);
|
memcpy(buf, (void *)addr, size);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
@ -1,125 +1,125 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* @brief tty<EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>ӡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief tty<EFBFBD><EFBFBD><EFBFBD>ڴ<EFBFBD>ӡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015, <morro_luo@163.com>
|
* Copyright (c) 2015, <morro_luo@163.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2015-07-03 Morro
|
* 2015-07-03 roger.luo
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#include "stm32f4xx.h"
|
#include "stm32f4xx.h"
|
||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
#include "tty.h"
|
#include "tty.h"
|
||||||
#include "public.h"
|
#include "public.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#if (TTY_RXBUF_SIZE & (TTY_RXBUF_SIZE - 1)) != 0
|
#if (TTY_RXBUF_SIZE & (TTY_RXBUF_SIZE - 1)) != 0
|
||||||
#error "TTY_RXBUF_SIZE must be power of 2!"
|
#error "TTY_RXBUF_SIZE must be power of 2!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (TTY_TXBUF_SIZE & (TTY_TXBUF_SIZE - 1)) != 0
|
#if (TTY_TXBUF_SIZE & (TTY_TXBUF_SIZE - 1)) != 0
|
||||||
#error "TTY_RXBUF_SIZE must be power of 2!"
|
#error "TTY_RXBUF_SIZE must be power of 2!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static unsigned char rxbuf[TTY_RXBUF_SIZE]; /*<2A><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD> */
|
static unsigned char rxbuf[TTY_RXBUF_SIZE]; /*<2A><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
static unsigned char txbuf[TTY_TXBUF_SIZE]; /*<2A><><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD><EFBFBD> */
|
static unsigned char txbuf[TTY_TXBUF_SIZE]; /*<2A><><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
static ring_buf_t rbsend, rbrecv; /*<2A>շ<EFBFBD><D5B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
static ring_buf_t rbsend, rbrecv; /*<2A>շ<EFBFBD><D5B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD>ڳ<EFBFBD>ʼ<EFBFBD><EFBFBD>
|
* @brief <EFBFBD><EFBFBD><EFBFBD>ڳ<EFBFBD>ʼ<EFBFBD><EFBFBD>
|
||||||
* @param[in] baudrate - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] baudrate - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @return none
|
* @return none
|
||||||
*/
|
*/
|
||||||
static void uart_init(int baudrate)
|
static void uart_init(int baudrate)
|
||||||
{
|
{
|
||||||
ring_buf_init(&rbsend, txbuf, sizeof(txbuf));/*<2A><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD> */
|
ring_buf_init(&rbsend, txbuf, sizeof(txbuf));/*<2A><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
ring_buf_init(&rbrecv, rxbuf, sizeof(rxbuf));
|
ring_buf_init(&rbrecv, rxbuf, sizeof(rxbuf));
|
||||||
|
|
||||||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA , ENABLE);
|
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA , ENABLE);
|
||||||
|
|
||||||
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
|
GPIO_PinAFConfig(GPIOA, GPIO_PinSource9, GPIO_AF_USART1);
|
||||||
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
|
GPIO_PinAFConfig(GPIOA, GPIO_PinSource10, GPIO_AF_USART1);
|
||||||
|
|
||||||
gpio_conf(GPIOA, GPIO_Mode_AF, GPIO_PuPd_NOPULL,
|
gpio_conf(GPIOA, GPIO_Mode_AF, GPIO_PuPd_NOPULL,
|
||||||
GPIO_Pin_9 | GPIO_Pin_10);
|
GPIO_Pin_9 | GPIO_Pin_10);
|
||||||
|
|
||||||
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
|
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);
|
||||||
uart_conf(USART1, baudrate); /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
uart_conf(USART1, baudrate); /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
|
|
||||||
nvic_conf(USART1_IRQn, 1, 1);
|
nvic_conf(USART1_IRQn, 1, 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief <EFBFBD>ڷ<EFBFBD><EFBFBD>ͻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief <EFBFBD>ڷ<EFBFBD><EFBFBD>ͻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] buf - <EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] buf - <EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] len - <EFBFBD><EFBFBD><EFBFBD>ݳ<EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] len - <EFBFBD><EFBFBD><EFBFBD>ݳ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @return ʵ<EFBFBD><EFBFBD>д<EFBFBD>볤<EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<EFBFBD><EFBFBD>len)
|
* @return ʵ<EFBFBD><EFBFBD>д<EFBFBD>볤<EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<EFBFBD><EFBFBD>len)
|
||||||
*/
|
*/
|
||||||
static unsigned int uart_write(const void *buf, unsigned int len)
|
static unsigned int uart_write(const void *buf, unsigned int len)
|
||||||
{
|
{
|
||||||
unsigned int ret;
|
unsigned int ret;
|
||||||
ret = ring_buf_put(&rbsend, (unsigned char *)buf, len);
|
ret = ring_buf_put(&rbsend, (unsigned char *)buf, len);
|
||||||
USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
|
USART_ITConfig(USART1, USART_IT_TXE, ENABLE);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>ڽ<EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>ڽ<EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] buf - <EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] buf - <EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] len - <EFBFBD><EFBFBD><EFBFBD>ݳ<EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] len - <EFBFBD><EFBFBD><EFBFBD>ݳ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @return (ʵ<EFBFBD>ʶ<EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>)<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><EFBFBD><EFBFBD>ݴ<EFBFBD><EFBFBD><EFBFBD>len<EFBFBD><EFBFBD>len<EFBFBD><EFBFBD><EFBFBD>ػ<EFBFBD><EFBFBD><EFBFBD>
|
* @return (ʵ<EFBFBD>ʶ<EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>)<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><EFBFBD><EFBFBD>ݴ<EFBFBD><EFBFBD><EFBFBD>len<EFBFBD><EFBFBD>len<EFBFBD><EFBFBD><EFBFBD>ػ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><EFBFBD><EFBFBD>ݵij<EFBFBD><EFBFBD><EFBFBD>
|
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><EFBFBD><EFBFBD>ݵij<EFBFBD><EFBFBD><EFBFBD>
|
||||||
*/
|
*/
|
||||||
static unsigned int uart_read(void *buf, unsigned int len)
|
static unsigned int uart_read(void *buf, unsigned int len)
|
||||||
{
|
{
|
||||||
return ring_buf_get(&rbrecv, (unsigned char *)buf, len);
|
return ring_buf_get(&rbrecv, (unsigned char *)buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*<2A><><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
/*<2A><><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
static bool tx_isfull(void)
|
static bool tx_isfull(void)
|
||||||
{
|
{
|
||||||
return ring_buf_len(&rbsend) == TTY_TXBUF_SIZE;
|
return ring_buf_len(&rbsend) == TTY_TXBUF_SIZE;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*<2A><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
/*<2A><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
bool rx_isempty(void)
|
bool rx_isempty(void)
|
||||||
{
|
{
|
||||||
return ring_buf_len(&rbrecv) == 0;
|
return ring_buf_len(&rbrecv) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*<2A><><EFBFBD><EFBFBD>̨<EFBFBD>ӿڶ<D3BF><DAB6><EFBFBD> -------------------------------------------------------------*/
|
/*<2A><><EFBFBD><EFBFBD>̨<EFBFBD>ӿڶ<D3BF><DAB6><EFBFBD> -------------------------------------------------------------*/
|
||||||
const tty_t tty = {
|
const tty_t tty = {
|
||||||
uart_init,
|
uart_init,
|
||||||
uart_write,
|
uart_write,
|
||||||
uart_read,
|
uart_read,
|
||||||
tx_isfull,
|
tx_isfull,
|
||||||
rx_isempty
|
rx_isempty
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>1<EFBFBD>շ<EFBFBD><EFBFBD>ж<EFBFBD>
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>1<EFBFBD>շ<EFBFBD><EFBFBD>ж<EFBFBD>
|
||||||
* @param[in] none
|
* @param[in] none
|
||||||
* @return none
|
* @return none
|
||||||
*/
|
*/
|
||||||
void USART1_IRQHandler(void)
|
void USART1_IRQHandler(void)
|
||||||
{
|
{
|
||||||
unsigned char data;
|
unsigned char data;
|
||||||
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
|
if (USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) {
|
||||||
data = USART_ReceiveData(USART1);
|
data = USART_ReceiveData(USART1);
|
||||||
ring_buf_put(&rbrecv, &data, 1); /*<2A><><EFBFBD><EFBFBD><EFBFBD>ݷ<EFBFBD><DDB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD>*/
|
ring_buf_put(&rbrecv, &data, 1); /*<2A><><EFBFBD><EFBFBD><EFBFBD>ݷ<EFBFBD><DDB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
}
|
}
|
||||||
if (USART_GetITStatus(USART1, USART_IT_TXE) != RESET) {
|
if (USART_GetITStatus(USART1, USART_IT_TXE) != RESET) {
|
||||||
if (ring_buf_get(&rbsend, &data, 1)) /*<2A>ӻ<EFBFBD><D3BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>---*/
|
if (ring_buf_get(&rbsend, &data, 1)) /*<2A>ӻ<EFBFBD><D3BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>---*/
|
||||||
USART_SendData(USART1, data);
|
USART_SendData(USART1, data);
|
||||||
else{
|
else{
|
||||||
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
|
USART_ITConfig(USART1, USART_IT_TXE, DISABLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (USART_GetITStatus(USART1, USART_IT_ORE_RX) != RESET) {
|
if (USART_GetITStatus(USART1, USART_IT_ORE_RX) != RESET) {
|
||||||
data = USART_ReceiveData(USART1);
|
data = USART_ReceiveData(USART1);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,108 +1,108 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* @brief wifi<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief wifi<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
*
|
*
|
||||||
* Copyright (c) 2021, <morro_luo@163.com>
|
* Copyright (c) 2021, <morro_luo@163.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2021-01-20 Morro <EFBFBD><EFBFBD>ʼ<EFBFBD>汾
|
* 2021-01-20 roger.luo <EFBFBD><EFBFBD>ʼ<EFBFBD>汾
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#include "stm32f4xx.h"
|
#include "stm32f4xx.h"
|
||||||
#include "ringbuffer.h"
|
#include "ringbuffer.h"
|
||||||
#include "wifi_uart.h"
|
#include "wifi_uart.h"
|
||||||
#include "public.h"
|
#include "public.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#if (TTY_RXBUF_SIZE & (TTY_RXBUF_SIZE - 1)) != 0
|
#if (TTY_RXBUF_SIZE & (TTY_RXBUF_SIZE - 1)) != 0
|
||||||
#error "TTY_RXBUF_SIZE must be power of 2!"
|
#error "TTY_RXBUF_SIZE must be power of 2!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if (TTY_TXBUF_SIZE & (TTY_TXBUF_SIZE - 1)) != 0
|
#if (TTY_TXBUF_SIZE & (TTY_TXBUF_SIZE - 1)) != 0
|
||||||
#error "TTY_RXBUF_SIZE must be power of 2!"
|
#error "TTY_RXBUF_SIZE must be power of 2!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static unsigned char rxbuf[WIFI_RXBUF_SIZE]; /*<2A><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD> */
|
static unsigned char rxbuf[WIFI_RXBUF_SIZE]; /*<2A><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
static unsigned char txbuf[WIFI_TXBUF_SIZE]; /*<2A><><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD><EFBFBD> */
|
static unsigned char txbuf[WIFI_TXBUF_SIZE]; /*<2A><><EFBFBD>ͻ<EFBFBD><CDBB><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
static ring_buf_t rbsend, rbrecv; /*<2A>շ<EFBFBD><D5B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
static ring_buf_t rbsend, rbrecv; /*<2A>շ<EFBFBD><D5B7><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief wifi<EFBFBD><EFBFBD><EFBFBD>ڳ<EFBFBD>ʼ<EFBFBD><EFBFBD>
|
* @brief wifi<EFBFBD><EFBFBD><EFBFBD>ڳ<EFBFBD>ʼ<EFBFBD><EFBFBD>
|
||||||
* @param[in] baudrate - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] baudrate - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @return none
|
* @return none
|
||||||
*/
|
*/
|
||||||
void wifi_uart_init(int baud_rate)
|
void wifi_uart_init(int baud_rate)
|
||||||
{
|
{
|
||||||
ring_buf_init(&rbsend, txbuf, sizeof(txbuf));/*<2A><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD> */
|
ring_buf_init(&rbsend, txbuf, sizeof(txbuf));/*<2A><>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
ring_buf_init(&rbrecv, rxbuf, sizeof(rxbuf));
|
ring_buf_init(&rbrecv, rxbuf, sizeof(rxbuf));
|
||||||
|
|
||||||
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB , ENABLE);
|
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOB , ENABLE);
|
||||||
|
|
||||||
GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART3);
|
GPIO_PinAFConfig(GPIOB, GPIO_PinSource10, GPIO_AF_USART3);
|
||||||
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_USART3);
|
GPIO_PinAFConfig(GPIOB, GPIO_PinSource11, GPIO_AF_USART3);
|
||||||
|
|
||||||
gpio_conf(GPIOB, GPIO_Mode_AF, GPIO_PuPd_NOPULL, GPIO_Pin_10 | GPIO_Pin_11);
|
gpio_conf(GPIOB, GPIO_Mode_AF, GPIO_PuPd_NOPULL, GPIO_Pin_10 | GPIO_Pin_11);
|
||||||
|
|
||||||
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
|
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART3, ENABLE);
|
||||||
uart_conf(USART3, baud_rate); /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
uart_conf(USART3, baud_rate); /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
|
|
||||||
nvic_conf(USART3_IRQn, 1, 1);
|
nvic_conf(USART3_IRQn, 1, 1);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief <EFBFBD>ڷ<EFBFBD><EFBFBD>ͻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief <EFBFBD>ڷ<EFBFBD><EFBFBD>ͻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݲ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] buf - <EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] buf - <EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] len - <EFBFBD><EFBFBD><EFBFBD>ݳ<EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] len - <EFBFBD><EFBFBD><EFBFBD>ݳ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @return ʵ<EFBFBD><EFBFBD>д<EFBFBD>볤<EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<EFBFBD><EFBFBD>len)
|
* @return ʵ<EFBFBD><EFBFBD>д<EFBFBD>볤<EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<EFBFBD><EFBFBD>len)
|
||||||
*/
|
*/
|
||||||
unsigned int wifi_uart_write(const void *buf, unsigned int len)
|
unsigned int wifi_uart_write(const void *buf, unsigned int len)
|
||||||
{
|
{
|
||||||
unsigned int ret;
|
unsigned int ret;
|
||||||
ret = ring_buf_put(&rbsend, (unsigned char *)buf, len);
|
ret = ring_buf_put(&rbsend, (unsigned char *)buf, len);
|
||||||
USART_ITConfig(USART3, USART_IT_TXE, ENABLE);
|
USART_ITConfig(USART3, USART_IT_TXE, ENABLE);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>ڽ<EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>ڽ<EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] buf - <EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] buf - <EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] len - <EFBFBD><EFBFBD><EFBFBD>ݳ<EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] len - <EFBFBD><EFBFBD><EFBFBD>ݳ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @return (ʵ<EFBFBD>ʶ<EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>)<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><EFBFBD><EFBFBD>ݴ<EFBFBD><EFBFBD><EFBFBD>len<EFBFBD><EFBFBD>len<EFBFBD><EFBFBD><EFBFBD>ػ<EFBFBD><EFBFBD><EFBFBD>
|
* @return (ʵ<EFBFBD>ʶ<EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>)<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><EFBFBD><EFBFBD>ݴ<EFBFBD><EFBFBD><EFBFBD>len<EFBFBD><EFBFBD>len<EFBFBD><EFBFBD><EFBFBD>ػ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><EFBFBD><EFBFBD>ݵij<EFBFBD><EFBFBD><EFBFBD>
|
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD><EFBFBD><EFBFBD>ݵij<EFBFBD><EFBFBD><EFBFBD>
|
||||||
*/
|
*/
|
||||||
unsigned int wifi_uart_read(void *buf, unsigned int len)
|
unsigned int wifi_uart_read(void *buf, unsigned int len)
|
||||||
{
|
{
|
||||||
return ring_buf_get(&rbrecv, (unsigned char *)buf, len);
|
return ring_buf_get(&rbrecv, (unsigned char *)buf, len);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*<2A><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
/*<2A><><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
bool wifi_uart_rx_empty(void)
|
bool wifi_uart_rx_empty(void)
|
||||||
{
|
{
|
||||||
return ring_buf_len(&rbrecv) == 0;
|
return ring_buf_len(&rbrecv) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>1<EFBFBD>շ<EFBFBD><EFBFBD>ж<EFBFBD>
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>1<EFBFBD>շ<EFBFBD><EFBFBD>ж<EFBFBD>
|
||||||
* @param[in] none
|
* @param[in] none
|
||||||
* @return none
|
* @return none
|
||||||
*/
|
*/
|
||||||
void USART3_IRQHandler(void)
|
void USART3_IRQHandler(void)
|
||||||
{
|
{
|
||||||
unsigned char data;
|
unsigned char data;
|
||||||
if (USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) {
|
if (USART_GetITStatus(USART3, USART_IT_RXNE) != RESET) {
|
||||||
data = USART_ReceiveData(USART3);
|
data = USART_ReceiveData(USART3);
|
||||||
ring_buf_put(&rbrecv, &data, 1); /*<2A><><EFBFBD><EFBFBD><EFBFBD>ݷ<EFBFBD><DDB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD>*/
|
ring_buf_put(&rbrecv, &data, 1); /*<2A><><EFBFBD><EFBFBD><EFBFBD>ݷ<EFBFBD><DDB7><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
}
|
}
|
||||||
if (USART_GetITStatus(USART3, USART_IT_TXE) != RESET) {
|
if (USART_GetITStatus(USART3, USART_IT_TXE) != RESET) {
|
||||||
if (ring_buf_get(&rbsend, &data, 1)) /*<2A>ӻ<EFBFBD><D3BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>---*/
|
if (ring_buf_get(&rbsend, &data, 1)) /*<2A>ӻ<EFBFBD><D3BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>---*/
|
||||||
USART_SendData(USART3, data);
|
USART_SendData(USART3, data);
|
||||||
else{
|
else{
|
||||||
USART_ITConfig(USART3, USART_IT_TXE, DISABLE);
|
USART_ITConfig(USART3, USART_IT_TXE, DISABLE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (USART_GetITStatus(USART3, USART_IT_ORE_RX) != RESET) {
|
if (USART_GetITStatus(USART3, USART_IT_ORE_RX) != RESET) {
|
||||||
data = USART_ReceiveData(USART3);
|
data = USART_ReceiveData(USART3);
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,94 +1,94 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˸<EFBFBD><EFBFBD><EFBFBD><EFBFBD>(dev, motor, buzzer)<EFBFBD><EFBFBD><EFBFBD>豸(dev, motor, buzzer)<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˸<EFBFBD><EFBFBD><EFBFBD><EFBFBD>(dev, motor, buzzer)<EFBFBD><EFBFBD><EFBFBD>豸(dev, motor, buzzer)<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019, <morro_luo@163.com>
|
* Copyright (c) 2019, <morro_luo@163.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2019-04-01 Morro Initial version
|
* 2019-04-01 roger.luo Initial version
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#include "module.h" /*get_tick()*/
|
#include "module.h" /*get_tick()*/
|
||||||
#include "blink.h"
|
#include "blink.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
static blink_dev_t *head = NULL; /*ͷ<><CDB7><EFBFBD><EFBFBD> -*/
|
static blink_dev_t *head = NULL; /*ͷ<><CDB7><EFBFBD><EFBFBD> -*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>blink<EFBFBD>豸
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>blink<EFBFBD>豸
|
||||||
* @param[in] dev - <EFBFBD>豸
|
* @param[in] dev - <EFBFBD>豸
|
||||||
* @param[in] ioctrl - IO<EFBFBD><EFBFBD><EFBFBD>ƺ<EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] ioctrl - IO<EFBFBD><EFBFBD><EFBFBD>ƺ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @return none
|
* @return none
|
||||||
*/
|
*/
|
||||||
void blink_dev_create(blink_dev_t *dev, void (*ioctrl)(bool enable))
|
void blink_dev_create(blink_dev_t *dev, void (*ioctrl)(bool enable))
|
||||||
{
|
{
|
||||||
blink_dev_t *tail = head;
|
blink_dev_t *tail = head;
|
||||||
memset(dev, 0, sizeof(blink_dev_t));
|
memset(dev, 0, sizeof(blink_dev_t));
|
||||||
dev->ioctrl = ioctrl;
|
dev->ioctrl = ioctrl;
|
||||||
dev->next = NULL;
|
dev->next = NULL;
|
||||||
if (head == NULL) {
|
if (head == NULL) {
|
||||||
head = dev;
|
head = dev;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
while (tail->next != NULL)
|
while (tail->next != NULL)
|
||||||
tail = tail->next;
|
tail = tail->next;
|
||||||
tail->next = dev;
|
tail->next = dev;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief blink <EFBFBD>豸<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief blink <EFBFBD>豸<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] name - <EFBFBD>豸<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] name - <EFBFBD>豸<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] ontime - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵΪ0<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ùر<EFBFBD>)
|
* @param[in] ontime - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵΪ0<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ùر<EFBFBD>)
|
||||||
* @param[in] offtime- <EFBFBD>ر<EFBFBD>ʱ<EFBFBD><EFBFBD>
|
* @param[in] offtime- <EFBFBD>ر<EFBFBD>ʱ<EFBFBD><EFBFBD>
|
||||||
* @param[in] repeats- <EFBFBD>ظ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(0<EFBFBD><EFBFBD>ʾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD>)
|
* @param[in] repeats- <EFBFBD>ظ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(0<EFBFBD><EFBFBD>ʾ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ѭ<EFBFBD><EFBFBD>)
|
||||||
* @return none
|
* @return none
|
||||||
*/
|
*/
|
||||||
void blink_dev_ctrl(blink_dev_t *dev, int ontime, int offtime, int repeats)
|
void blink_dev_ctrl(blink_dev_t *dev, int ontime, int offtime, int repeats)
|
||||||
{
|
{
|
||||||
dev->ontime = ontime;
|
dev->ontime = ontime;
|
||||||
dev->offtime = offtime + ontime;
|
dev->offtime = offtime + ontime;
|
||||||
dev->repeats = repeats;
|
dev->repeats = repeats;
|
||||||
dev->tick = get_tick();
|
dev->tick = get_tick();
|
||||||
dev->count = 0;
|
dev->count = 0;
|
||||||
if (ontime == 0) {
|
if (ontime == 0) {
|
||||||
dev->ioctrl(false);
|
dev->ioctrl(false);
|
||||||
dev->enable = false;
|
dev->enable = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief blink<EFBFBD>豸<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief blink<EFBFBD>豸<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] none
|
* @param[in] none
|
||||||
* @return none
|
* @return none
|
||||||
*/
|
*/
|
||||||
void blink_dev_process(void)
|
void blink_dev_process(void)
|
||||||
{
|
{
|
||||||
blink_dev_t *dev;
|
blink_dev_t *dev;
|
||||||
for (dev = head; dev != NULL; dev = dev->next) {
|
for (dev = head; dev != NULL; dev = dev->next) {
|
||||||
if (dev->ontime == 0) {
|
if (dev->ontime == 0) {
|
||||||
continue;
|
continue;
|
||||||
} else if (get_tick() - dev->tick < dev->ontime) {
|
} else if (get_tick() - dev->tick < dev->ontime) {
|
||||||
if (!dev->enable) {
|
if (!dev->enable) {
|
||||||
dev->enable = true;
|
dev->enable = true;
|
||||||
dev->ioctrl(true);
|
dev->ioctrl(true);
|
||||||
}
|
}
|
||||||
} else if(get_tick() - dev->tick < dev->offtime) { /**/
|
} else if(get_tick() - dev->tick < dev->offtime) { /**/
|
||||||
if (dev->enable) {
|
if (dev->enable) {
|
||||||
dev->enable = false;
|
dev->enable = false;
|
||||||
dev->ioctrl(false);
|
dev->ioctrl(false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
dev->tick = get_tick();
|
dev->tick = get_tick();
|
||||||
if (dev->repeats) {
|
if (dev->repeats) {
|
||||||
if (++dev->count >= dev->repeats) {
|
if (++dev->count >= dev->repeats) {
|
||||||
dev->ontime = 0;
|
dev->ontime = 0;
|
||||||
dev->ioctrl(false);
|
dev->ioctrl(false);
|
||||||
dev->enable = false;
|
dev->enable = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,43 +1,43 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˸<EFBFBD><EFBFBD><EFBFBD><EFBFBD>(dev, motor, buzzer)<EFBFBD><EFBFBD><EFBFBD>豸(dev, motor, buzzer)<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>˸<EFBFBD><EFBFBD><EFBFBD><EFBFBD>(dev, motor, buzzer)<EFBFBD><EFBFBD><EFBFBD>豸(dev, motor, buzzer)<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
*
|
*
|
||||||
* Copyright (c) 2019, <morro_luo@163.com>
|
* Copyright (c) 2019, <morro_luo@163.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2019-04-01 Morro Initial version
|
* 2019-04-01 roger.luo Initial version
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#ifndef _BLINK_H_
|
#ifndef _BLINK_H_
|
||||||
#define _BLINK_H_
|
#define _BLINK_H_
|
||||||
|
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*Blink <20>豸<EFBFBD><E8B1B8><EFBFBD><EFBFBD>*/
|
/*Blink <20>豸<EFBFBD><E8B1B8><EFBFBD><EFBFBD>*/
|
||||||
typedef struct blink_dev {
|
typedef struct blink_dev {
|
||||||
unsigned short ontime; /*<2A><><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>*/
|
unsigned short ontime; /*<2A><><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>*/
|
||||||
unsigned short offtime; /*<2A>ر<EFBFBD>ʱ<EFBFBD><CAB1>*/
|
unsigned short offtime; /*<2A>ر<EFBFBD>ʱ<EFBFBD><CAB1>*/
|
||||||
unsigned short repeats; /*<2A>ظ<EFBFBD><D8B8><EFBFBD><EFBFBD><EFBFBD>*/
|
unsigned short repeats; /*<2A>ظ<EFBFBD><D8B8><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
unsigned char count;
|
unsigned char count;
|
||||||
unsigned char enable;
|
unsigned char enable;
|
||||||
unsigned int tick;
|
unsigned int tick;
|
||||||
void (*ioctrl)(bool enable); /*io<69><6F><EFBFBD>ƽӿ<C6BD>*/
|
void (*ioctrl)(bool enable); /*io<69><6F><EFBFBD>ƽӿ<C6BD>*/
|
||||||
struct blink_dev *next;
|
struct blink_dev *next;
|
||||||
}blink_dev_t;
|
}blink_dev_t;
|
||||||
|
|
||||||
void blink_dev_create(blink_dev_t *dev, void (*ioctrl)(bool enable));
|
void blink_dev_create(blink_dev_t *dev, void (*ioctrl)(bool enable));
|
||||||
|
|
||||||
void blink_dev_ctrl(blink_dev_t *dev, int ontime, int offtime, int repeat);
|
void blink_dev_ctrl(blink_dev_t *dev, int ontime, int offtime, int repeat);
|
||||||
|
|
||||||
void blink_dev_process(void);
|
void blink_dev_process(void);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,235 +1,318 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD>
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD>
|
||||||
*
|
*
|
||||||
* Copyright (c) 2015-2020, <morro_luo@163.com>
|
* Copyright (c) 2015-2020, <morro_luo@163.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2015-06-09 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* 2015-06-09 roger.luo <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
*
|
*
|
||||||
* 2017-07-04 Morro <EFBFBD>Ż<EFBFBD><EFBFBD>ֶηָ<EFBFBD><EFBFBD>
|
* 2017-07-04 roger.luo <EFBFBD>Ż<EFBFBD><EFBFBD>ֶηָ<EFBFBD><EFBFBD>
|
||||||
*
|
*
|
||||||
* 2020-07-05 Morro ʹ<EFBFBD><EFBFBD>cli_obj_t<EFBFBD><EFBFBD><EFBFBD><EFBFBD>, ֧<EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* 2020-07-05 roger.luo ʹ<EFBFBD><EFBFBD>cli_obj_t<EFBFBD><EFBFBD><EFBFBD><EFBFBD>, ֧<EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#include "cli.h"
|
#include "cli.h"
|
||||||
#include <string.h>
|
#include <stdio.h>
|
||||||
#include <stdio.h>
|
#include <string.h>
|
||||||
#include <stdarg.h>
|
#include <stdarg.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
static const cmd_item_t cmd_tbl_start SECTION("cli.cmd.0") = {0};
|
static const cmd_item_t cmd_tbl_start SECTION("cli.cmd.0") = {0};
|
||||||
static const cmd_item_t cmd_tbl_end SECTION("cli.cmd.4") = {0};
|
static const cmd_item_t cmd_tbl_end SECTION("cli.cmd.4") = {0};
|
||||||
/*
|
/**
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] keyword - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ؼ<EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] keyword - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ؼ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
*/
|
*/
|
||||||
static const cmd_item_t *find_cmd(const char *keyword)
|
static const cmd_item_t *find_cmd(const char *keyword, int n)
|
||||||
{
|
{
|
||||||
const cmd_item_t *it;
|
const cmd_item_t *it;
|
||||||
for (it = &cmd_tbl_start + 1; it < &cmd_tbl_end; it++) {
|
for (it = &cmd_tbl_start + 1; it < &cmd_tbl_end; it++) {
|
||||||
if (!strcasecmp(keyword, it->name))
|
if (!strncasecmp(keyword, it->name, n))
|
||||||
return it;
|
return it;
|
||||||
}
|
}
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* @brief <EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD> - <EFBFBD><EFBFBD>Դ<EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>separatorָ<EFBFBD><EFBFBD><EFBFBD>ķָ<EFBFBD><EFBFBD><EFBFBD>
|
* @brief <EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD> - <EFBFBD><EFBFBD>Դ<EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ҳ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>separatorָ<EFBFBD><EFBFBD><EFBFBD>ķָ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
* (<EFBFBD><EFBFBD>',')<EFBFBD><EFBFBD><EFBFBD>滻<EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>'\0'<EFBFBD>γ<EFBFBD><EFBFBD>Ӵ<EFBFBD><EFBFBD><EFBFBD>ͬʱ<EFBFBD><EFBFBD>list
|
* (<EFBFBD><EFBFBD>',')<EFBFBD><EFBFBD><EFBFBD>滻<EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>'\0'<EFBFBD>γ<EFBFBD><EFBFBD>Ӵ<EFBFBD><EFBFBD><EFBFBD>ͬʱ<EFBFBD><EFBFBD>list
|
||||||
* ָ<EFBFBD><EFBFBD><EFBFBD>б<EFBFBD><EFBFBD>е<EFBFBD>ÿһ<EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>ֱ<EFBFBD>ָ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>Ӵ<EFBFBD>
|
* ָ<EFBFBD><EFBFBD><EFBFBD>б<EFBFBD><EFBFBD>е<EFBFBD>ÿһ<EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>ֱ<EFBFBD>ָ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>Ӵ<EFBFBD>
|
||||||
* @example
|
* @example
|
||||||
* input=> s = "abc,123,456,,fb$"
|
* input=> s = "abc,123,456,,fb$"
|
||||||
* separator = ",$"
|
* separator = ",$"
|
||||||
*
|
*
|
||||||
* output=>s = abc'\0' 123'\0' 456'\0' '\0' fb'\0''\0'
|
* output=>s = abc'\0' 123'\0' 456'\0' '\0' fb'\0''\0'
|
||||||
* list[0] = "abc"
|
* list[0] = "abc"
|
||||||
* list[1] = "123"
|
* list[1] = "123"
|
||||||
* list[2] = "456"
|
* list[2] = "456"
|
||||||
* list[3] = ""
|
* list[3] = ""
|
||||||
* list[4] = "fb"
|
* list[4] = "fb"
|
||||||
* list[5] = ""
|
* list[5] = ""
|
||||||
*
|
*
|
||||||
* @param[in] str - Դ<EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] str - Դ<EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] separator - <EFBFBD>ָ<EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] separator - <EFBFBD>ָ<EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] list - <EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>б<EFBFBD>
|
* @param[in] list - <EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD>б<EFBFBD>
|
||||||
* @param[in] len - <EFBFBD>б<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] len - <EFBFBD>б<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @return listָ<EFBFBD><EFBFBD><EFBFBD>б<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><EFBFBD>6
|
* @return listָ<EFBFBD><EFBFBD><EFBFBD>б<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʾ<EFBFBD><EFBFBD>6
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
static size_t strsplit(char *s, const char *separator, char *list[], size_t len)
|
static size_t strsplit(char *s, const char *separator, char *list[], size_t len)
|
||||||
{
|
{
|
||||||
size_t count = 0;
|
size_t count = 0;
|
||||||
if (s == NULL || list == NULL || len == 0)
|
if (s == NULL || list == NULL || len == 0)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
list[count++] = s;
|
list[count++] = s;
|
||||||
while(*s && count < len) {
|
while(*s && count < len) {
|
||||||
if (strchr(separator, *s) != NULL) {
|
if (strchr(separator, *s) != NULL) {
|
||||||
*s = '\0';
|
*s = '\0';
|
||||||
list[count++] = s + 1; /*ָ<><D6B8><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>Ӵ<EFBFBD>*/
|
list[count++] = s + 1; /*ָ<><D6B8><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD>Ӵ<EFBFBD>*/
|
||||||
}
|
}
|
||||||
s++;
|
s++;
|
||||||
}
|
}
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
*@brief <EFBFBD><EFBFBD>ӡһ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڿ<EFBFBD><EFBFBD><EFBFBD>̨
|
|
||||||
*@retval
|
/**
|
||||||
*/
|
* @brief <EFBFBD><EFBFBD>ӡһ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD><EFBFBD>ַ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ڿ<EFBFBD><EFBFBD><EFBFBD>̨
|
||||||
static void cli_print(cli_obj_t *obj, const char *format, ...)
|
* @retval
|
||||||
{
|
*/
|
||||||
va_list args;
|
static void cli_print(cli_obj_t *obj, const char *format, ...)
|
||||||
int len;
|
{
|
||||||
char buf[CLI_MAX_CMD_LEN + CLI_MAX_CMD_LEN / 2];
|
va_list args;
|
||||||
va_start (args, format);
|
int len;
|
||||||
len = vsnprintf (buf, sizeof(buf), format, args);
|
char buf[CLI_MAX_CMD_LEN + CLI_MAX_CMD_LEN / 2];
|
||||||
obj->write(buf, len);
|
va_start (args, format);
|
||||||
}
|
len = vsnprintf (buf, sizeof(buf), format, args);
|
||||||
|
va_end (args);
|
||||||
|
obj->write(buf, len);
|
||||||
/*
|
}
|
||||||
* @brief cli <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>
|
|
||||||
* @param[in] p - cli<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD>
|
|
||||||
* @return none
|
/**
|
||||||
*/
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
void cli_init(cli_obj_t *obj, const cli_port_t *p)
|
* @param[in] line - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
{
|
* @return none
|
||||||
obj->read = p->read;
|
**/
|
||||||
obj->write = p->write;
|
static void process_line(cli_obj_t *obj)
|
||||||
obj->print = cli_print;
|
{
|
||||||
obj->enable = true;
|
char *argv[CLI_MAX_ARGS];
|
||||||
}
|
int argc, ret, isat = 0;
|
||||||
|
const cmd_item_t *it;
|
||||||
/*
|
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>cli<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģʽ(cli<EFBFBD><EFBFBD>ʱ<EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
//<2F><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] none
|
if (obj->guard && !obj->guard(obj->recvbuf))
|
||||||
* @return none
|
return;
|
||||||
**/
|
|
||||||
void cli_enable(cli_obj_t *obj)
|
if (obj->echo) { //<2F><><EFBFBD><EFBFBD>
|
||||||
{
|
obj->print(obj,"%s\r\n",obj->recvbuf);
|
||||||
obj->enable = true;
|
}
|
||||||
}
|
|
||||||
|
argc = strsplit(obj->recvbuf, ",",argv, CLI_MAX_ARGS);
|
||||||
/*
|
|
||||||
* @brief <EFBFBD>˳<EFBFBD>cli<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģʽ(cli<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD>ٴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
const char *start, *end;
|
||||||
* @param[in] none
|
|
||||||
* @return none
|
if (argv[0] == NULL)
|
||||||
**/
|
return;
|
||||||
void cli_disable (cli_obj_t *obj)
|
|
||||||
{
|
if (strcasecmp("AT", argv[0]) == 0) {
|
||||||
obj->enable = false;
|
obj->print(obj, "OK\r\n");
|
||||||
}
|
return;
|
||||||
|
}
|
||||||
/*
|
#if CLI_AT_ENABLE != 0
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
isat = strncasecmp(argv[0], "AT+", 3) == 0;
|
||||||
* @param[in] line - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
#endif
|
||||||
* @return none
|
|
||||||
**/
|
start= !isat ? argv[0] : argv[0] + 3;
|
||||||
static void process_line(cli_obj_t *obj)
|
|
||||||
{
|
if ((end = strchr(start, '=')) != NULL) {
|
||||||
char *argv[CLI_MAX_ARGS];
|
obj->type = CLI_CMD_TYPE_SET;
|
||||||
int argc;
|
|
||||||
const cmd_item_t *it;
|
} else if ((end = strchr(start, '?')) != NULL) {
|
||||||
argc = strsplit(obj->recvbuf, " ,",argv, CLI_MAX_ARGS);
|
obj->type = CLI_CMD_TYPE_QUERY;
|
||||||
if ((it = find_cmd(argv[0])) == NULL) {
|
|
||||||
obj->print(obj, "Unknown command '%s' - try 'help'\r\n", argv[0]);
|
} else {
|
||||||
return;
|
obj->type = CLI_CMD_TYPE_EXEC;
|
||||||
}
|
end = start + strlen(argv[0]);
|
||||||
it->handler(obj, argc, argv);
|
}
|
||||||
}
|
if (start == end)
|
||||||
|
return;
|
||||||
/*
|
|
||||||
* @brief ִ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD>cli<EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD>)
|
if ((it = find_cmd(start, end - start)) == NULL) {
|
||||||
* @param[in] none
|
obj->print(obj, "%s\r\n", isat ? "ERROR" : "");
|
||||||
* @return none
|
return;
|
||||||
**/
|
}
|
||||||
void cli_exec_cmd(cli_obj_t *obj, const char *cmd)
|
ret = it->handler(obj, argc, argv);
|
||||||
{
|
if (isat) {
|
||||||
snprintf(obj->recvbuf, CLI_MAX_CMD_LEN, "%s", cmd);
|
obj->print(obj, "%s\r\n" ,ret ? "OK":"ERROR");
|
||||||
process_line(obj);
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/**
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ֵ
|
||||||
* @param[in] none
|
*/
|
||||||
* @return none
|
static int get_val(struct cli_obj *self)
|
||||||
**/
|
{
|
||||||
void cli_process(cli_obj_t *obj)
|
char *p;
|
||||||
{
|
p = strchr(self->recvbuf, '=');
|
||||||
|
if ( p == NULL)
|
||||||
int i;
|
return 0;
|
||||||
if (!obj->read || !obj->enable)
|
return atoi(p + 1);
|
||||||
return;
|
|
||||||
i = obj->recvcnt;
|
}
|
||||||
obj->recvcnt += obj->read(&obj->recvbuf[i], CLI_MAX_CMD_LEN - i);
|
|
||||||
while (i < obj->recvcnt) {
|
/**
|
||||||
if (obj->recvbuf[i] == '\r' || obj->recvbuf[i] == '\n') { /*<2A><>ȡ1<C8A1><31>*/
|
* @brief cli <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>
|
||||||
obj->recvbuf[i] = '\0';
|
* @param[in] p - cli<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD>
|
||||||
process_line(obj);
|
* @return none
|
||||||
obj->recvcnt = 0;
|
*/
|
||||||
}
|
void cli_init(cli_obj_t *obj, const cli_port_t *p)
|
||||||
i++;
|
{
|
||||||
}
|
obj->read = p->read;
|
||||||
}
|
obj->write = p->write;
|
||||||
|
obj->print = cli_print;
|
||||||
|
obj->enable = true;
|
||||||
/*******************************************************************************
|
obj->get_val = get_val;
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƚ<EFBFBD><EFBFBD><EFBFBD>
|
obj->guard = p->cmd_guard;
|
||||||
* @param[in] none
|
}
|
||||||
* @return <EFBFBD>ο<EFBFBD>strcmp
|
|
||||||
*******************************************************************************/
|
/**
|
||||||
static int cmd_item_comparer(const void *item1,const void *item2)
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>cli<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģʽ(cli<EFBFBD><EFBFBD>ʱ<EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
||||||
{
|
* @param[in] none
|
||||||
cmd_item_t *it1 = *((cmd_item_t **)item1);
|
* @return none
|
||||||
cmd_item_t *it2 = *((cmd_item_t **)item2);
|
**/
|
||||||
return strcmp(it1->name, it2->name);
|
void cli_enable(cli_obj_t *obj)
|
||||||
}
|
{
|
||||||
|
char a;
|
||||||
/*
|
obj->enable = true;
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
obj->recvcnt = 0;
|
||||||
*/
|
while (obj->read(&a, 1) > 0) {}
|
||||||
static int do_help (struct cli_obj *s, int argc, char *argv[])
|
}
|
||||||
{
|
|
||||||
int i,j, count;
|
/**
|
||||||
const cmd_item_t *item_start = &cmd_tbl_start + 1;
|
* @brief <EFBFBD>˳<EFBFBD>cli<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ģʽ(cli<EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD><EFBFBD>ٴ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>û<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
||||||
const cmd_item_t *item_end = &cmd_tbl_end;
|
* @param[in] none
|
||||||
const cmd_item_t *cmdtbl[CLI_MAX_CMDS];
|
* @return none
|
||||||
|
**/
|
||||||
if (argc == 2) {
|
void cli_disable (cli_obj_t *obj)
|
||||||
if ((item_start = find_cmd(argv[1])) != NULL)
|
{
|
||||||
{
|
obj->enable = false;
|
||||||
s->print(s, item_start->brief); /*<2A><><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9><EFBFBD><EFBFBD>Ϣ----*/
|
}
|
||||||
s->print(s, "\r\n");
|
|
||||||
}
|
/**
|
||||||
return 0;
|
* @brief <EFBFBD><EFBFBD><EFBFBD>Կ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
}
|
* @param[in] echo - <EFBFBD><EFBFBD><EFBFBD>Կ<EFBFBD><EFBFBD>ؿ<EFBFBD><EFBFBD><EFBFBD>(0/1)
|
||||||
for (i = 0; i < item_end - item_start && i < CLI_MAX_ARGS; i++)
|
* @return none
|
||||||
cmdtbl[i] = &item_start[i];
|
**/
|
||||||
count = i;
|
void cli_echo_ctrl (cli_obj_t *obj, int echo)
|
||||||
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ---------------------------------------------------------*/
|
{
|
||||||
qsort(cmdtbl, i, sizeof(cmd_item_t*), cmd_item_comparer);
|
obj->echo = echo;
|
||||||
s->print(s, "\r\n");
|
}
|
||||||
for (i = 0; i < count; i++) {
|
|
||||||
s->print(s, cmdtbl[i]->name); /*<2A><>ӡ<EFBFBD><D3A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>------*/
|
/**
|
||||||
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
* @brief ִ<EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD>cli<EFBFBD>Ƿ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD>)
|
||||||
j = strlen(cmdtbl[i]->name);
|
* @param[in] none
|
||||||
if (j < 10)
|
* @return none
|
||||||
j = 10 - j;
|
**/
|
||||||
|
void cli_exec_cmd(cli_obj_t *obj, const char *cmd)
|
||||||
while (j--)
|
{
|
||||||
s->print(s, " ");
|
int len = strlen(cmd);
|
||||||
|
if (len >= CLI_MAX_CMD_LEN - 1)
|
||||||
s->print(s, "- ");
|
return;
|
||||||
s->print(s, cmdtbl[i]->brief); /*<2A><><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9><EFBFBD><EFBFBD>Ϣ----*/
|
strcpy(obj->recvbuf, cmd);
|
||||||
s->print(s, "\r\n");
|
process_line(obj);
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
}
|
/**
|
||||||
/*ע<><D7A2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ---------------------------------------------------------------*/
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
cmd_register("help", do_help, "list all command.");
|
* @param[in] none
|
||||||
cmd_register("?", do_help, "alias for 'help'");
|
* @return none
|
||||||
|
**/
|
||||||
|
void cli_process(cli_obj_t *obj)
|
||||||
|
{
|
||||||
|
char buf[32];
|
||||||
|
int i, readcnt;
|
||||||
|
if (!obj->read || !obj->enable)
|
||||||
|
return;
|
||||||
|
|
||||||
|
readcnt = obj->read(buf, sizeof(buf));
|
||||||
|
|
||||||
|
if (readcnt) {
|
||||||
|
for (i = 0; i < readcnt; i++) {
|
||||||
|
if (buf[i] == '\r' || buf[i] == '\n' || buf[i] == '\0') {
|
||||||
|
obj->recvbuf[obj->recvcnt] = '\0';
|
||||||
|
if (obj->recvcnt > 1)
|
||||||
|
process_line(obj);
|
||||||
|
obj->recvcnt = 0;
|
||||||
|
} else {
|
||||||
|
obj->recvbuf[obj->recvcnt++] = buf[i];
|
||||||
|
|
||||||
|
if (obj->recvcnt >= CLI_MAX_CMD_LEN) /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>֮<EFBFBD><D6AE>ǿ<EFBFBD><C7BF><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
|
obj->recvcnt = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#if 1
|
||||||
|
/*******************************************************************************
|
||||||
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ƚ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
* @param[in] none
|
||||||
|
* @return <EFBFBD>ο<EFBFBD>strcmp
|
||||||
|
*******************************************************************************/
|
||||||
|
static int cmd_item_comparer(const void *item1,const void *item2)
|
||||||
|
{
|
||||||
|
cmd_item_t *it1 = *((cmd_item_t **)item1);
|
||||||
|
cmd_item_t *it2 = *((cmd_item_t **)item2);
|
||||||
|
return strcmp(it1->name, it2->name);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
*/
|
||||||
|
static int do_help (struct cli_obj *s, int argc, char *argv[])
|
||||||
|
{
|
||||||
|
int i,j, count;
|
||||||
|
const cmd_item_t *item_start = &cmd_tbl_start + 1;
|
||||||
|
const cmd_item_t *item_end = &cmd_tbl_end;
|
||||||
|
const cmd_item_t *cmdtbl[CLI_MAX_CMDS];
|
||||||
|
|
||||||
|
if (argc == 2) {
|
||||||
|
if ((item_start = find_cmd(argv[1], strlen(argv[1]))) != NULL)
|
||||||
|
{
|
||||||
|
s->print(s, item_start->brief); /*<2A><><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9><EFBFBD><EFBFBD>Ϣ----*/
|
||||||
|
s->print(s, "\r\n");
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
for (i = 0; i < item_end - item_start && i < CLI_MAX_ARGS; i++)
|
||||||
|
cmdtbl[i] = &item_start[i];
|
||||||
|
count = i;
|
||||||
|
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ---------------------------------------------------------*/
|
||||||
|
qsort(cmdtbl, i, sizeof(cmd_item_t*), cmd_item_comparer);
|
||||||
|
s->print(s, "\r\n");
|
||||||
|
for (i = 0; i < count; i++) {
|
||||||
|
s->print(s, cmdtbl[i]->name); /*<2A><>ӡ<EFBFBD><D3A1><EFBFBD><EFBFBD><EFBFBD><EFBFBD>------*/
|
||||||
|
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
|
j = strlen(cmdtbl[i]->name);
|
||||||
|
if (j < 10)
|
||||||
|
j = 10 - j;
|
||||||
|
|
||||||
|
while (j--)
|
||||||
|
s->print(s, " ");
|
||||||
|
|
||||||
|
s->print(s, "- ");
|
||||||
|
s->print(s, cmdtbl[i]->brief); /*<2A><><EFBFBD><EFBFBD>ʹ<EFBFBD><CAB9><EFBFBD><EFBFBD>Ϣ----*/
|
||||||
|
s->print(s, "\r\n");
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*ע<><D7A2><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ---------------------------------------------------------------*/
|
||||||
|
cmd_register("help", do_help, "list all command.");
|
||||||
|
cmd_register("?", do_help, "alias for 'help'");
|
114
samples/none_os/framework/cli.h
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>д<EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
*
|
||||||
|
* Copyright (c) 2015-2020, <master_roger@sina.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
* 2015-06-09 roger.luo <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
*
|
||||||
|
* 2017-07-04 roger.luo <EFBFBD>Ż<EFBFBD><EFBFBD>ֶηָ<EFBFBD><EFBFBD>
|
||||||
|
*
|
||||||
|
* 2020-07-05 roger.luo ʹ<EFBFBD><EFBFBD>cli_obj_t<EFBFBD><EFBFBD><EFBFBD><EFBFBD>, ֧<EFBFBD>ֶ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
* 2020-08-29 roger.luo ֧<EFBFBD><EFBFBD>ATָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Կ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
* 2020-02-16 roger.luo <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
******************************************************************************/
|
||||||
|
#ifndef _CMDLINE_H_
|
||||||
|
#define _CMDLINE_H_
|
||||||
|
|
||||||
|
#include "comdef.h"
|
||||||
|
|
||||||
|
#define CLI_MAX_CMD_LEN 256 /*<2A><><EFBFBD><EFBFBD><EFBFBD>г<EFBFBD><D0B3><EFBFBD>*/
|
||||||
|
#define CLI_MAX_ARGS 16 /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
|
#define CLI_MAX_CMDS 64 /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief CLI<EFBFBD><EFBFBD>ΪAT<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʹ<EFBFBD><EFBFBD>,<EFBFBD>ڽ<EFBFBD><EFBFBD><EFBFBD>ƥ<EFBFBD><EFBFBD>ʱ<EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>"AT+",
|
||||||
|
*/
|
||||||
|
#define CLI_AT_ENABLE 1
|
||||||
|
|
||||||
|
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
#define CLI_CMD_TYPE_EXEC 0 /* <20><>ִͨ<CDA8><D6B4><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
|
#define CLI_CMD_TYPE_QUERY 1 /* <20><>ѯ<EFBFBD><D1AF><EFBFBD><EFBFBD> (XXX?)*/
|
||||||
|
#define CLI_CMD_TYPE_SET 2 /* <20>豸<EFBFBD><E8B1B8><EFBFBD><EFBFBD> (XXX=YY)*/
|
||||||
|
|
||||||
|
struct cli_obj;
|
||||||
|
|
||||||
|
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EEB6A8>*/
|
||||||
|
typedef struct {
|
||||||
|
char *name; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
|
/**
|
||||||
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
* @params o - cli <EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
* @params argc - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
* @params argv - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD>н<EFBFBD><EFBFBD><EFBFBD>, <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ATָ<EFBFBD><EFBFBD>, <EFBFBD><EFBFBD><EFBFBD><EFBFBD>trueʱ<EFBFBD><EFBFBD><EFBFBD>Զ<EFBFBD><EFBFBD><EFBFBD>ӦOK,<EFBFBD><EFBFBD><EFBFBD><EFBFBD>falseʱ<EFBFBD><EFBFBD>
|
||||||
|
* <EFBFBD><EFBFBD>ӦERROR
|
||||||
|
*/
|
||||||
|
int (*handler)(struct cli_obj *o, int argc, char *argv[]);
|
||||||
|
const char *brief; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
|
}cmd_item_t;
|
||||||
|
|
||||||
|
#define __cmd_register(name,handler,brief)\
|
||||||
|
USED ANONY_TYPE(const cmd_item_t,__cli_cmd_##handler)\
|
||||||
|
SECTION("cli.cmd.1") = {name, handler, brief}
|
||||||
|
|
||||||
|
/*******************************************************************************
|
||||||
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ע<EFBFBD><EFBFBD>
|
||||||
|
* @params name - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
* @params handler - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
* <EFBFBD><EFBFBD><EFBFBD><EFBFBD>:int (*handler)(struct cli_obj *s, int argc, char *argv[]);
|
||||||
|
* @params brief - ʹ<EFBFBD><EFBFBD>˵<EFBFBD><EFBFBD>
|
||||||
|
*/
|
||||||
|
#define cmd_register(name,handler,brief)\
|
||||||
|
__cmd_register(name,handler,brief)
|
||||||
|
|
||||||
|
/*cli <20>ӿڶ<D3BF><DAB6><EFBFBD> -------------------------------------------------------------*/
|
||||||
|
typedef struct {
|
||||||
|
/**
|
||||||
|
* @brief ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD>)д<EFBFBD>ӿ<EFBFBD>
|
||||||
|
*/
|
||||||
|
unsigned int (*write)(const void *buf, unsigned int len);
|
||||||
|
/**
|
||||||
|
* @brief ͨ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD>)<EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD>
|
||||||
|
*/
|
||||||
|
unsigned int (*read) (void *buf, unsigned int len);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ҫ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>дNULL,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD>)
|
||||||
|
* @retval true - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ִ<EFBFBD><EFBFBD>, false - <EFBFBD><EFBFBD><EFBFBD>Դ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
|
*/
|
||||||
|
int (*cmd_guard)(char *cmdline);
|
||||||
|
|
||||||
|
}cli_port_t;
|
||||||
|
|
||||||
|
/*<2A><><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD><D0B6><EFBFBD>*/
|
||||||
|
typedef struct cli_obj {
|
||||||
|
int (*guard)(char *cmdline);
|
||||||
|
unsigned int (*write)(const void *buf, unsigned int len);
|
||||||
|
unsigned int (*read) (void *buf, unsigned int len);
|
||||||
|
void (*print)(struct cli_obj *this, const char *fmt, ...);
|
||||||
|
int (*get_val)(struct cli_obj *this);
|
||||||
|
char recvbuf[CLI_MAX_CMD_LEN + 1]; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><D5BB><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
|
unsigned short recvcnt; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ճ<EFBFBD><D5B3><EFBFBD>*/
|
||||||
|
unsigned type : 3; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
|
unsigned enable : 1; /* CLI <20><><EFBFBD>ؿ<EFBFBD><D8BF><EFBFBD>*/
|
||||||
|
unsigned echo : 1; /* <20><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
|
}cli_obj_t;
|
||||||
|
|
||||||
|
void cli_init(cli_obj_t *obj, const cli_port_t *p);
|
||||||
|
|
||||||
|
void cli_enable(cli_obj_t *obj);
|
||||||
|
|
||||||
|
void cli_disable (cli_obj_t *obj);
|
||||||
|
|
||||||
|
void cli_echo_ctrl (cli_obj_t *obj, int echo);
|
||||||
|
|
||||||
|
void cli_exec_cmd(cli_obj_t *obj, const char *cmd);
|
||||||
|
|
||||||
|
void cli_process(cli_obj_t *obj);
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* __CMDLINE_H */
|
@ -1,55 +1,55 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* @brief ͨ<EFBFBD>ú궨<EFBFBD><EFBFBD>
|
* @brief ͨ<EFBFBD>ú궨<EFBFBD><EFBFBD>
|
||||||
*
|
*
|
||||||
* Copyright (c) 2018~2020, <morro_luo@163.com>
|
* Copyright (c) 2018~2020, <morro_luo@163.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2018-02-01 Morro Initial version.
|
* 2018-02-01 roger.luo Initial version.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#ifndef _COM_DEF_H_
|
#ifndef _COM_DEF_H_
|
||||||
#define _COM_DEF_H_
|
#define _COM_DEF_H_
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD><CDB6><EFBFBD> -----------------------------------------------------------*/
|
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ͷ<EFBFBD><CDB6><EFBFBD> -----------------------------------------------------------*/
|
||||||
#define ANONY_CONN(type, var, line) type var##line
|
#define ANONY_CONN(type, var, line) type var##line
|
||||||
#define ANONY_DEF(type,prefix,line) ANONY_CONN(type, prefix, line)
|
#define ANONY_DEF(type,prefix,line) ANONY_CONN(type, prefix, line)
|
||||||
#define ANONY_TYPE(type,prefix) ANONY_DEF(type, prefix, __LINE__)
|
#define ANONY_TYPE(type,prefix) ANONY_DEF(type, prefix, __LINE__)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* container_of - cast a member of a structure out to the containing structure
|
* container_of - cast a member of a structure out to the containing structure
|
||||||
* @ptr: the pointer to the member.
|
* @ptr: the pointer to the member.
|
||||||
* @type: the type of the container struct this is embedded in.
|
* @type: the type of the container struct this is embedded in.
|
||||||
* @member: the name of the member within the struct.
|
* @member: the name of the member within the struct.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
#define container_of(ptr, type, member) ( \
|
#define container_of(ptr, type, member) ( \
|
||||||
(type *)( (char *)(ptr) - offsetof(type,member) ))
|
(type *)( (char *)(ptr) - offsetof(type,member) ))
|
||||||
|
|
||||||
|
|
||||||
#if defined(__CC_ARM) || defined(__GNUC__) /* ARM,GCC*/
|
#if defined(__CC_ARM) || defined(__GNUC__) /* ARM,GCC*/
|
||||||
#define SECTION(x) __attribute__((section(x)))
|
#define SECTION(x) __attribute__((section(x)))
|
||||||
#define UNUSED __attribute__((unused))
|
#define UNUSED __attribute__((unused))
|
||||||
#define USED __attribute__((used))
|
#define USED __attribute__((used))
|
||||||
#define ALIGN(n) __attribute__((aligned(n)))
|
#define ALIGN(n) __attribute__((aligned(n)))
|
||||||
#define WEAK __attribute__((weak))
|
#define WEAK __attribute__((weak))
|
||||||
#elif defined (__ICCARM__) /*IAR */
|
#elif defined (__ICCARM__) /*IAR */
|
||||||
#define SECTION(x) @ x
|
#define SECTION(x) @ x
|
||||||
#define UNUSED
|
#define UNUSED
|
||||||
#define USED __root
|
#define USED __root
|
||||||
#define WEAK __weak
|
#define WEAK __weak
|
||||||
#else
|
#else
|
||||||
#error "Current tool chain haven't supported yet!"
|
#error "Current tool chain haven't supported yet!"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,73 +1,73 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
*
|
*
|
||||||
* Copyright (c) 2017~2020, <morro_luo@163.com>
|
* Copyright (c) 2017~2020, <morro_luo@163.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2017-08-10 Morro Initial version
|
* 2017-08-10 roger.luo Initial version
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#include "key.h"
|
#include "key.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
static key_t *keyhead = NULL; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD>*/
|
static key_t *keyhead = NULL; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD><CDB7><EFBFBD><EFBFBD>*/
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] key - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] key - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] readkey - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ժ<EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD>
|
* @param[in] readkey - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ժ<EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD>
|
||||||
* @param[in] event - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD>
|
* @param[in] event - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD>
|
||||||
* @return true - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><EFBFBD>, false - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɹ<EFBFBD>
|
* @return true - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><EFBFBD>, false - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɹ<EFBFBD>
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
bool key_create(key_t *key, int (*readkey)(void),
|
bool key_create(key_t *key, int (*readkey)(void),
|
||||||
void (*event)(int type, unsigned int duration))
|
void (*event)(int type, unsigned int duration))
|
||||||
{
|
{
|
||||||
key_t *keytail = keyhead;
|
key_t *keytail = keyhead;
|
||||||
if (key == NULL || readkey == NULL || event == NULL)
|
if (key == NULL || readkey == NULL || event == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
key->event = event;
|
key->event = event;
|
||||||
key->readkey = readkey;
|
key->readkey = readkey;
|
||||||
key->next = NULL;
|
key->next = NULL;
|
||||||
if (keyhead == NULL) {
|
if (keyhead == NULL) {
|
||||||
keyhead = key;
|
keyhead = key;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
while (keytail->next != NULL) /*ת<><D7AA><EFBFBD><EFBFBD>β*/
|
while (keytail->next != NULL) /*ת<><D7AA><EFBFBD><EFBFBD>β*/
|
||||||
keytail = keytail->next;
|
keytail = keytail->next;
|
||||||
keytail->next = key;
|
keytail->next = key;
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɨ<EFBFBD>账<EFBFBD><EFBFBD>
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɨ<EFBFBD>账<EFBFBD><EFBFBD>
|
||||||
* @return none
|
* @return none
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
void key_scan_process(void)
|
void key_scan_process(void)
|
||||||
{
|
{
|
||||||
key_t *k;
|
key_t *k;
|
||||||
for (k = keyhead; k != NULL; k = k->next) {
|
for (k = keyhead; k != NULL; k = k->next) {
|
||||||
if (k->readkey()) {
|
if (k->readkey()) {
|
||||||
if (k->tick) {
|
if (k->tick) {
|
||||||
if (is_timeout(k->tick, LONG_PRESS_TIME)) /*<2A><><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD> */
|
if (is_timeout(k->tick, LONG_PRESS_TIME)) /*<2A><><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD> */
|
||||||
k->event(KEY_LONG_DOWN, get_tick() - k->tick);
|
k->event(KEY_LONG_DOWN, get_tick() - k->tick);
|
||||||
} else {
|
} else {
|
||||||
k->tick = get_tick(); /*<2A><>¼<EFBFBD>״ΰ<D7B4><CEB0><EFBFBD>ʱ<EFBFBD><CAB1>*/
|
k->tick = get_tick(); /*<2A><>¼<EFBFBD>״ΰ<D7B4><CEB0><EFBFBD>ʱ<EFBFBD><CAB1>*/
|
||||||
}
|
}
|
||||||
} else if (k->tick) {
|
} else if (k->tick) {
|
||||||
if (is_timeout(k->tick, LONG_PRESS_TIME)) { /*<2A><><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD> */
|
if (is_timeout(k->tick, LONG_PRESS_TIME)) { /*<2A><><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD> */
|
||||||
k->event(KEY_LONG_UP, get_tick() - k->tick);
|
k->event(KEY_LONG_UP, get_tick() - k->tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*<2A>̰<EFBFBD><CCB0>ͷŲ<CDB7><C5B2><EFBFBD> ---------------------------------------------------*/
|
/*<2A>̰<EFBFBD><CCB0>ͷŲ<CDB7><C5B2><EFBFBD> ---------------------------------------------------*/
|
||||||
if (is_timeout(k->tick, KEY_DEBOUNCE_TIME) &&
|
if (is_timeout(k->tick, KEY_DEBOUNCE_TIME) &&
|
||||||
!is_timeout(k->tick, LONG_PRESS_TIME)) {
|
!is_timeout(k->tick, LONG_PRESS_TIME)) {
|
||||||
k->event(KEY_PRESS, get_tick() - k->tick);
|
k->event(KEY_PRESS, get_tick() - k->tick);
|
||||||
}
|
}
|
||||||
|
|
||||||
k->tick = 0;
|
k->tick = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,56 +1,56 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
*
|
*
|
||||||
* Copyright (c) 2017~2020, <morro_luo@163.com>
|
* Copyright (c) 2017~2020, <morro_luo@163.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2017-08-10 Morro Initial version
|
* 2017-08-10 roger.luo Initial version
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#ifndef _KEY_H_
|
#ifndef _KEY_H_
|
||||||
#define _KEY_H_
|
#define _KEY_H_
|
||||||
|
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define LONG_PRESS_TIME 1500 /*<2A><><EFBFBD><EFBFBD>ȷ<EFBFBD><C8B7>ʱ<EFBFBD><CAB1> ------------*/
|
#define LONG_PRESS_TIME 1500 /*<2A><><EFBFBD><EFBFBD>ȷ<EFBFBD><C8B7>ʱ<EFBFBD><CAB1> ------------*/
|
||||||
#define KEY_DEBOUNCE_TIME 20 /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1> ------------*/
|
#define KEY_DEBOUNCE_TIME 20 /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1> ------------*/
|
||||||
|
|
||||||
#define KEY_PRESS 0 /*<2A>̰<EFBFBD> --------------------*/
|
#define KEY_PRESS 0 /*<2A>̰<EFBFBD> --------------------*/
|
||||||
#define KEY_LONG_DOWN 1 /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ----------------*/
|
#define KEY_LONG_DOWN 1 /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> ----------------*/
|
||||||
#define KEY_LONG_UP 2 /*<2A><><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD> ----------------*/
|
#define KEY_LONG_UP 2 /*<2A><><EFBFBD><EFBFBD><EFBFBD>ͷ<EFBFBD> ----------------*/
|
||||||
|
|
||||||
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> -----------------------------------------------------------------*/
|
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> -----------------------------------------------------------------*/
|
||||||
typedef struct key_t {
|
typedef struct key_t {
|
||||||
/*
|
/*
|
||||||
*@brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD>ӿ<EFBFBD>
|
*@brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD>ӿ<EFBFBD>
|
||||||
*@param[in] none
|
*@param[in] none
|
||||||
*@return 0 - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <EFBFBD><EFBFBD>0 - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
*@return 0 - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>, <EFBFBD><EFBFBD>0 - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
*/
|
*/
|
||||||
int (*readkey)(void);
|
int (*readkey)(void);
|
||||||
/*
|
/*
|
||||||
*@brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
*@brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
*@param[in] type - <EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(KEY_SHORT_PRESS - <EFBFBD>̰<EFBFBD>, KEY_LONG_PRESS - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
*@param[in] type - <EFBFBD>¼<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(KEY_SHORT_PRESS - <EFBFBD>̰<EFBFBD>, KEY_LONG_PRESS - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
||||||
*@param[in] duration <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч
|
*@param[in] duration <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʱ<EFBFBD><EFBFBD>,<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч
|
||||||
*@return none
|
*@return none
|
||||||
*/
|
*/
|
||||||
void (*event)(int type, unsigned int duration);/*<2A><><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD> ------------*/
|
void (*event)(int type, unsigned int duration);/*<2A><><EFBFBD><EFBFBD><EFBFBD>¼<EFBFBD><C2BC><EFBFBD><EFBFBD><EFBFBD> ------------*/
|
||||||
unsigned int tick; /*<2A>δ<EFBFBD><CEB4><EFBFBD>ʱ<EFBFBD><CAB1> --------------*/
|
unsigned int tick; /*<2A>δ<EFBFBD><CEB4><EFBFBD>ʱ<EFBFBD><CAB1> --------------*/
|
||||||
struct key_t *next; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
struct key_t *next; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
}key_t;
|
}key_t;
|
||||||
|
|
||||||
bool key_create(key_t *key, int (*readkey)(void), /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
bool key_create(key_t *key, int (*readkey)(void), /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
void (*event)(int type, unsigned int duration));
|
void (*event)(int type, unsigned int duration));
|
||||||
void key_scan_process(void); /*<2A><><EFBFBD><EFBFBD>ɨ<EFBFBD>账<EFBFBD><E8B4A6>*/
|
void key_scan_process(void); /*<2A><><EFBFBD><EFBFBD>ɨ<EFBFBD>账<EFBFBD><E8B4A6>*/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,98 +1,98 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* @brief 系统模块管理(包含系统初始化,时间片轮询系统)
|
* @brief 系统模块管理(包含系统初始化,时间片轮询系统)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2017~2020, <morro_luo@163.com>
|
* Copyright (c) 2017~2020, <morro_luo@163.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2016-06-24 Morro 初版完成
|
* 2016-06-24 roger.luo 初版完成
|
||||||
* 2020-05-23 Morro 增加匿名类型,防止模块重名错误
|
* 2020-05-23 roger.luo 增加匿名类型,防止模块重名错误
|
||||||
* 2020-06-28 Morro 增加is_timeout超时判断接口
|
* 2020-06-28 roger.luo 增加is_timeout超时判断接口
|
||||||
* 2020-09-28 Morro 解决伪任务项未初始化timer,导致引用了空指针的问题!
|
* 2020-09-28 roger.luo 解决伪任务项未初始化timer,导致引用了空指针的问题!
|
||||||
*
|
*
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#include "module.h"
|
#include "module.h"
|
||||||
|
|
||||||
|
|
||||||
static volatile unsigned int tick; //系统滴答计时
|
static volatile unsigned int tick; //系统滴答计时
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief 增加系统节拍数(定时器中断中调用,1ms 1次)
|
* @brief 增加系统节拍数(定时器中断中调用,1ms 1次)
|
||||||
*/
|
*/
|
||||||
void systick_increase(unsigned int ms)
|
void systick_increase(unsigned int ms)
|
||||||
{
|
{
|
||||||
tick += ms;
|
tick += ms;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief 获取系统滴答时钟值(通常单位是1ms)
|
* @brief 获取系统滴答时钟值(通常单位是1ms)
|
||||||
*/
|
*/
|
||||||
unsigned int get_tick(void)
|
unsigned int get_tick(void)
|
||||||
{
|
{
|
||||||
return tick;
|
return tick;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief 超时判断
|
* @brief 超时判断
|
||||||
* @param[in] start - 起始时间
|
* @param[in] start - 起始时间
|
||||||
* @param[in] timeout - 超时时间(ms)
|
* @param[in] timeout - 超时时间(ms)
|
||||||
*/
|
*/
|
||||||
bool is_timeout(unsigned int start, unsigned int timeout)
|
bool is_timeout(unsigned int start, unsigned int timeout)
|
||||||
{
|
{
|
||||||
return get_tick() - start > timeout;
|
return get_tick() - start > timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief 空处理,用于定位段入口
|
* @brief 空处理,用于定位段入口
|
||||||
*/
|
*/
|
||||||
static void nop_process(void) {}
|
static void nop_process(void) {}
|
||||||
|
|
||||||
//第一个初始化项
|
//第一个初始化项
|
||||||
const init_item_t init_tbl_start SECTION("init.item.0") = {
|
const init_item_t init_tbl_start SECTION("init.item.0") = {
|
||||||
"", nop_process
|
"", nop_process
|
||||||
};
|
};
|
||||||
//最后个初始化项
|
//最后个初始化项
|
||||||
const init_item_t init_tbl_end SECTION("init.item.4") = {
|
const init_item_t init_tbl_end SECTION("init.item.4") = {
|
||||||
"", nop_process
|
"", nop_process
|
||||||
};
|
};
|
||||||
|
|
||||||
//第一个任务项
|
//第一个任务项
|
||||||
const task_item_t task_tbl_start SECTION("task.item.0") = {
|
const task_item_t task_tbl_start SECTION("task.item.0") = {
|
||||||
"", nop_process
|
"", nop_process
|
||||||
};
|
};
|
||||||
//最后个任务项
|
//最后个任务项
|
||||||
const task_item_t task_tbl_end SECTION("task.item.2") = {
|
const task_item_t task_tbl_end SECTION("task.item.2") = {
|
||||||
"", nop_process
|
"", nop_process
|
||||||
};
|
};
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief 模块初始处理
|
* @brief 模块初始处理
|
||||||
* 初始化模块优化级 system_init > driver_init > module_init
|
* 初始化模块优化级 system_init > driver_init > module_init
|
||||||
* @param[in] none
|
* @param[in] none
|
||||||
* @return none
|
* @return none
|
||||||
*/
|
*/
|
||||||
void module_task_init(void)
|
void module_task_init(void)
|
||||||
{
|
{
|
||||||
const init_item_t *it = &init_tbl_start;
|
const init_item_t *it = &init_tbl_start;
|
||||||
while (it < &init_tbl_end) {
|
while (it < &init_tbl_end) {
|
||||||
it++->init();
|
it++->init();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief 任务轮询处理
|
* @brief 任务轮询处理
|
||||||
* @param[in] none
|
* @param[in] none
|
||||||
* @return none
|
* @return none
|
||||||
*/
|
*/
|
||||||
void module_task_process(void)
|
void module_task_process(void)
|
||||||
{
|
{
|
||||||
const task_item_t *t;
|
const task_item_t *t;
|
||||||
for (t = &task_tbl_start + 1; t < &task_tbl_end; t++) {
|
for (t = &task_tbl_start + 1; t < &task_tbl_end; t++) {
|
||||||
if ((get_tick() - *t->timer) >= t->interval) {
|
if ((get_tick() - *t->timer) >= t->interval) {
|
||||||
*t->timer = get_tick();
|
*t->timer = get_tick();
|
||||||
t->handle();
|
t->handle();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,66 +1,66 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* @brief ϵͳģ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵͳ<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>,ʱ<EFBFBD><EFBFBD>Ƭ<EFBFBD><EFBFBD>ѯϵͳ)
|
* @brief ϵͳģ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ϵͳ<EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>,ʱ<EFBFBD><EFBFBD>Ƭ<EFBFBD><EFBFBD>ѯϵͳ)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2017~2020, <morro_luo@163.com>
|
* Copyright (c) 2017~2020, <morro_luo@163.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2016-06-24 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* 2016-06-24 roger.luo <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* 2020-05-23 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<EFBFBD><EFBFBD>ֹģ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* 2020-05-23 roger.luo <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>,<EFBFBD><EFBFBD>ֹģ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* 2020-06-28 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD>is_timeout<EFBFBD><EFBFBD>ʱ<EFBFBD>жϽӿ<EFBFBD>
|
* 2020-06-28 roger.luo <EFBFBD><EFBFBD><EFBFBD><EFBFBD>is_timeout<EFBFBD><EFBFBD>ʱ<EFBFBD>жϽӿ<EFBFBD>
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
|
||||||
#ifndef _MODULE_H_
|
#ifndef _MODULE_H_
|
||||||
#define _MODULE_H_
|
#define _MODULE_H_
|
||||||
|
|
||||||
#include "comdef.h"
|
#include "comdef.h"
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
/*ģ<><C4A3><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>*/
|
/*ģ<><C4A3><EFBFBD><EFBFBD>ʼ<EFBFBD><CABC><EFBFBD><EFBFBD>*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *name; //ģ<><C4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
const char *name; //ģ<><C4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
void (*init)(void); //<2F><>ʼ<EFBFBD><CABC><EFBFBD>ӿ<EFBFBD>
|
void (*init)(void); //<2F><>ʼ<EFBFBD><CABC><EFBFBD>ӿ<EFBFBD>
|
||||||
}init_item_t;
|
}init_item_t;
|
||||||
|
|
||||||
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
/*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
typedef struct {
|
typedef struct {
|
||||||
const char *name; //ģ<><C4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
const char *name; //ģ<><C4A3><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
void (*handle)(void); //<2F><>ʼ<EFBFBD><CABC><EFBFBD>ӿ<EFBFBD>
|
void (*handle)(void); //<2F><>ʼ<EFBFBD><CABC><EFBFBD>ӿ<EFBFBD>
|
||||||
unsigned int interval; //<2F><>ѯ<EFBFBD><D1AF><EFBFBD><EFBFBD>
|
unsigned int interval; //<2F><>ѯ<EFBFBD><D1AF><EFBFBD><EFBFBD>
|
||||||
unsigned int *timer; //ָ<><D6B8><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>ָ<EFBFBD><D6B8>
|
unsigned int *timer; //ָ<><D6B8><EFBFBD><EFBFBD>ʱ<EFBFBD><CAB1>ָ<EFBFBD><D6B8>
|
||||||
}task_item_t;
|
}task_item_t;
|
||||||
|
|
||||||
#define __module_initialize(name,func,level) \
|
#define __module_initialize(name,func,level) \
|
||||||
USED ANONY_TYPE(const init_item_t, init_tbl_##func)\
|
USED ANONY_TYPE(const init_item_t, init_tbl_##func)\
|
||||||
SECTION("init.item."level) = {name,func}
|
SECTION("init.item."level) = {name,func}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ע<EFBFBD><EFBFBD>
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ע<EFBFBD><EFBFBD>
|
||||||
* @param[in] name - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] name - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] handle - <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(void func(void){...})
|
* @param[in] handle - <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(void func(void){...})
|
||||||
* @param[in] interval- <EFBFBD><EFBFBD>ѯ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>(ms)
|
* @param[in] interval- <EFBFBD><EFBFBD>ѯ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>(ms)
|
||||||
*/
|
*/
|
||||||
#define task_register(name, handle,interval) \
|
#define task_register(name, handle,interval) \
|
||||||
static unsigned int __task_timer_##handle; \
|
static unsigned int __task_timer_##handle; \
|
||||||
USED ANONY_TYPE(const task_item_t, task_item_##handle) \
|
USED ANONY_TYPE(const task_item_t, task_item_##handle) \
|
||||||
SECTION("task.item.1") = \
|
SECTION("task.item.1") = \
|
||||||
{name,handle, interval, &__task_timer_##handle}
|
{name,handle, interval, &__task_timer_##handle}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* @brief ģ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>ע<EFBFBD><EFBFBD>
|
* @brief ģ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>ע<EFBFBD><EFBFBD>
|
||||||
* @param[in] name - ģ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] name - ģ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] func - <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ں<EFBFBD><EFBFBD><EFBFBD>(void func(void){...})
|
* @param[in] func - <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ں<EFBFBD><EFBFBD><EFBFBD>(void func(void){...})
|
||||||
*/
|
*/
|
||||||
#define system_init(name,func) __module_initialize(name,func,"1")
|
#define system_init(name,func) __module_initialize(name,func,"1")
|
||||||
#define driver_init(name,func) __module_initialize(name,func,"2")
|
#define driver_init(name,func) __module_initialize(name,func,"2")
|
||||||
#define module_init(name,func) __module_initialize(name,func,"3")
|
#define module_init(name,func) __module_initialize(name,func,"3")
|
||||||
|
|
||||||
void systick_increase(unsigned int ms);
|
void systick_increase(unsigned int ms);
|
||||||
unsigned int get_tick(void);
|
unsigned int get_tick(void);
|
||||||
bool is_timeout(unsigned int start, unsigned int timeout);
|
bool is_timeout(unsigned int start, unsigned int timeout);
|
||||||
void module_task_init(void);
|
void module_task_init(void);
|
||||||
void module_task_process(void);
|
void module_task_process(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,100 +1,100 @@
|
|||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* @brief <EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>(queue link)<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief <EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>(queue link)<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
*
|
*
|
||||||
* Copyright (c) 2017~2020, <morro_luo@163.com>
|
* Copyright (c) 2017~2020, <morro_luo@163.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
* Change Logs
|
* Change Logs
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2016-06-24 Morro <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>
|
* 2016-06-24 Morro <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD>
|
||||||
* 2018-03-17 Morro <EFBFBD><EFBFBD><EFBFBD>Ӷ<EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD><EFBFBD>ͳ<EFBFBD>ƹ<EFBFBD><EFBFBD><EFBFBD>
|
* 2018-03-17 Morro <EFBFBD><EFBFBD><EFBFBD>Ӷ<EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD><EFBFBD>ͳ<EFBFBD>ƹ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
*******************************************************************************/
|
*******************************************************************************/
|
||||||
#ifndef _QLINK_H_
|
#ifndef _QLINK_H_
|
||||||
#define _QLINK_H_
|
#define _QLINK_H_
|
||||||
|
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
|
|
||||||
/*<2A><>ʽ<EFBFBD><CABD><EFBFBD>н<EFBFBD><D0BD><EFBFBD> ---------------------------------------------------------------*/
|
/*<2A><>ʽ<EFBFBD><CABD><EFBFBD>н<EFBFBD><D0BD><EFBFBD> ---------------------------------------------------------------*/
|
||||||
struct qlink_node {
|
struct qlink_node {
|
||||||
struct qlink_node *next;
|
struct qlink_node *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*<2A><>ʽ<EFBFBD><CABD><EFBFBD>й<EFBFBD><D0B9><EFBFBD><EFBFBD><EFBFBD> -------------------------------------------------------------*/
|
/*<2A><>ʽ<EFBFBD><CABD><EFBFBD>й<EFBFBD><D0B9><EFBFBD><EFBFBD><EFBFBD> -------------------------------------------------------------*/
|
||||||
struct qlink {
|
struct qlink {
|
||||||
unsigned int count;
|
unsigned int count;
|
||||||
struct qlink_node *front, *rear;
|
struct qlink_node *front, *rear;
|
||||||
};
|
};
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* @brief <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @brief <EFBFBD><EFBFBD>ʼ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʽ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] q - <EFBFBD><EFBFBD><EFBFBD>й<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] q - <EFBFBD><EFBFBD><EFBFBD>й<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @return none
|
* @return none
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
static inline void qlink_init(struct qlink *q)
|
static inline void qlink_init(struct qlink *q)
|
||||||
{
|
{
|
||||||
q->front = q->rear= NULL;
|
q->front = q->rear= NULL;
|
||||||
q->count = 0;
|
q->count = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD>Ӳ<EFBFBD><EFBFBD><EFBFBD>
|
* @brief <EFBFBD><EFBFBD><EFBFBD>Ӳ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] q - <EFBFBD><EFBFBD><EFBFBD>й<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] q - <EFBFBD><EFBFBD><EFBFBD>й<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @return nond
|
* @return nond
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
static inline void qlink_put(struct qlink *q, struct qlink_node *n)
|
static inline void qlink_put(struct qlink *q, struct qlink_node *n)
|
||||||
{
|
{
|
||||||
if (q->count == 0)
|
if (q->count == 0)
|
||||||
q->front = n;
|
q->front = n;
|
||||||
else
|
else
|
||||||
q->rear->next = n;
|
q->rear->next = n;
|
||||||
q->rear = n;
|
q->rear = n;
|
||||||
n->next = NULL;
|
n->next = NULL;
|
||||||
q->count++;
|
q->count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* @brief Ԥ<EFBFBD><EFBFBD><EFBFBD>Ӳ<EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
* @brief Ԥ<EFBFBD><EFBFBD><EFBFBD>Ӳ<EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
||||||
* @param[in] q - <EFBFBD><EFBFBD><EFBFBD>й<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] q - <EFBFBD><EFBFBD><EFBFBD>й<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @return nond
|
* @return nond
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
static inline struct qlink_node *qlink_peek(struct qlink *q)
|
static inline struct qlink_node *qlink_peek(struct qlink *q)
|
||||||
{
|
{
|
||||||
return q->front;
|
return q->front;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD>Ӳ<EFBFBD><EFBFBD><EFBFBD>
|
* @brief <EFBFBD><EFBFBD><EFBFBD>Ӳ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] q - <EFBFBD><EFBFBD><EFBFBD>й<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] q - <EFBFBD><EFBFBD><EFBFBD>й<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @return nond
|
* @return nond
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
static inline struct qlink_node *qlink_get(struct qlink *q)
|
static inline struct qlink_node *qlink_get(struct qlink *q)
|
||||||
{
|
{
|
||||||
struct qlink_node *n;
|
struct qlink_node *n;
|
||||||
if (q->count == 0)
|
if (q->count == 0)
|
||||||
return NULL;
|
return NULL;
|
||||||
n = q->front;
|
n = q->front;
|
||||||
q->front = q->front->next;
|
q->front = q->front->next;
|
||||||
q->count--;
|
q->count--;
|
||||||
return n;
|
return n;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD>ظ<EFBFBD><EFBFBD><EFBFBD>
|
* @brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD>ظ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] q - <EFBFBD><EFBFBD><EFBFBD>й<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] q - <EFBFBD><EFBFBD><EFBFBD>й<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @return nond
|
* @return nond
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
static inline int qlink_count(struct qlink *q)
|
static inline int qlink_count(struct qlink *q)
|
||||||
{
|
{
|
||||||
return q->count;
|
return q->count;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,117 +1,117 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* @brief ͨ<EFBFBD>ö<EFBFBD><EFBFBD>й<EFBFBD><EFBFBD><EFBFBD>
|
* @brief ͨ<EFBFBD>ö<EFBFBD><EFBFBD>й<EFBFBD><EFBFBD><EFBFBD>
|
||||||
*
|
*
|
||||||
* Copyright (c) 2017~2020, <morro_luo@163.com>
|
* Copyright (c) 2017~2020, <morro_luo@163.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2017-03-19 Morro Initial version.
|
* 2017-03-19 roger.luo Initial version.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#include "queue.h"
|
#include "queue.h"
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
/* @brief <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
/* @brief <20><><EFBFBD><EFBFBD>һ<EFBFBD><D2BB><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] q - <EFBFBD><EFBFBD><EFBFBD>й<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] q - <EFBFBD><EFBFBD><EFBFBD>й<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] base - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ
|
* @param[in] base - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ
|
||||||
* @param[in] size - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD>ظ<EFBFBD><EFBFBD><EFBFBD>
|
* @param[in] size - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD>ظ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
* @param[in] element_size - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD>ش<EFBFBD>С(sizeof(type))
|
* @param[in] element_size - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD>ش<EFBFBD>С(sizeof(type))
|
||||||
* @return true - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɹ<EFBFBD>, false - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><EFBFBD>
|
* @return true - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ɹ<EFBFBD>, false - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>ʧ<EFBFBD><EFBFBD>
|
||||||
*/
|
*/
|
||||||
bool queue_create(queue_t *q, void *base, int size, int element_size)
|
bool queue_create(queue_t *q, void *base, int size, int element_size)
|
||||||
{
|
{
|
||||||
if (q == NULL || base == NULL || size== 0 || element_size == 0)
|
if (q == NULL || base == NULL || size== 0 || element_size == 0)
|
||||||
return false;
|
return false;
|
||||||
q->base = base;
|
q->base = base;
|
||||||
q->size = size;
|
q->size = size;
|
||||||
q->element_size = element_size;
|
q->element_size = element_size;
|
||||||
q->front = q->rear = 0;
|
q->front = q->rear = 0;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* @brief <20>ж϶<D0B6><CFB6><EFBFBD><EFBFBD>Ƿ<EFBFBD>Ϊ<EFBFBD><CEAA>
|
/* @brief <20>ж϶<D0B6><CFB6><EFBFBD><EFBFBD>Ƿ<EFBFBD>Ϊ<EFBFBD><CEAA>
|
||||||
* @return true - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD>, false - <EFBFBD><EFBFBD><EFBFBD>зǿ<EFBFBD>
|
* @return true - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD>, false - <EFBFBD><EFBFBD><EFBFBD>зǿ<EFBFBD>
|
||||||
*/
|
*/
|
||||||
bool queue_is_empty(queue_t *q)
|
bool queue_is_empty(queue_t *q)
|
||||||
{
|
{
|
||||||
return q->front == q->rear;
|
return q->front == q->rear;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @brief <20>ж϶<D0B6><CFB6><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>
|
/* @brief <20>ж϶<D0B6><CFB6><EFBFBD><EFBFBD>Ƿ<EFBFBD><C7B7><EFBFBD>
|
||||||
* @return true - <EFBFBD><EFBFBD><EFBFBD>з<EFBFBD><EFBFBD><EFBFBD>, false - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><EFBFBD>
|
* @return true - <EFBFBD><EFBFBD><EFBFBD>з<EFBFBD><EFBFBD><EFBFBD>, false - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>δ<EFBFBD><EFBFBD>
|
||||||
*/
|
*/
|
||||||
bool queue_is_full(queue_t *q)
|
bool queue_is_full(queue_t *q)
|
||||||
{
|
{
|
||||||
return (q->rear + 1) % q->size == q->front;
|
return (q->rear + 1) % q->size == q->front;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @brief <20><><EFBFBD><EFBFBD>(<28><><EFBFBD><EFBFBD>Ԫ<EFBFBD><D4AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>β)
|
/* @brief <20><><EFBFBD><EFBFBD>(<28><><EFBFBD><EFBFBD>Ԫ<EFBFBD><D4AA><EFBFBD><EFBFBD><EFBFBD><EFBFBD>β)
|
||||||
* @param[in] element - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD><EFBFBD>
|
* @param[in] element - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD><EFBFBD>
|
||||||
* @return true - <EFBFBD>ɹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, false - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* @return true - <EFBFBD>ɹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, false - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
*/
|
*/
|
||||||
bool queue_put(queue_t *q, void *element)
|
bool queue_put(queue_t *q, void *element)
|
||||||
{
|
{
|
||||||
if (queue_is_full(q))
|
if (queue_is_full(q))
|
||||||
return false;
|
return false;
|
||||||
memcpy((unsigned char *)q->base + q->rear * q->element_size, element,
|
memcpy((unsigned char *)q->base + q->rear * q->element_size, element,
|
||||||
q->element_size);
|
q->element_size);
|
||||||
q->rear = (q->rear + 1) % q->size;
|
q->rear = (q->rear + 1) % q->size;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @brief <20><><EFBFBD><EFBFBD>(<28>Ƴ<EFBFBD><C6B3><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD><D4AA>)
|
/* @brief <20><><EFBFBD><EFBFBD>(<28>Ƴ<EFBFBD><C6B3><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD><D4AA>)
|
||||||
* @param[in] element - ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD>صĵ<EFBFBD>ַ
|
* @param[in] element - ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD>صĵ<EFBFBD>ַ
|
||||||
* @return true - <EFBFBD>ɹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, false - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD>
|
* @return true - <EFBFBD>ɹ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>, false - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD>
|
||||||
*/
|
*/
|
||||||
bool queue_get(queue_t *q, void *element)
|
bool queue_get(queue_t *q, void *element)
|
||||||
{
|
{
|
||||||
if (queue_is_empty(q))
|
if (queue_is_empty(q))
|
||||||
return false;
|
return false;
|
||||||
memcpy(element, (unsigned char *)q->base + q->front * q->element_size,
|
memcpy(element, (unsigned char *)q->base + q->front * q->element_size,
|
||||||
q->element_size);
|
q->element_size);
|
||||||
q->front = (q->front + 1) % q->size;
|
q->front = (q->front + 1) % q->size;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @brief <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>Ԫ<EFBFBD>ص<EFBFBD>ַ(Ԥ<><D4A4>ȡ)
|
/* @brief <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>Ԫ<EFBFBD>ص<EFBFBD>ַ(Ԥ<><D4A4>ȡ)
|
||||||
* @param[in] element - ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD>صĵ<EFBFBD>ַ
|
* @param[in] element - ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD>صĵ<EFBFBD>ַ
|
||||||
* @return true - <EFBFBD><EFBFBD>ȡ<EFBFBD>ɹ<EFBFBD>, false - <EFBFBD><EFBFBD>ȡʧ<EFBFBD>ܶ<EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD>
|
* @return true - <EFBFBD><EFBFBD>ȡ<EFBFBD>ɹ<EFBFBD>, false - <EFBFBD><EFBFBD>ȡʧ<EFBFBD>ܶ<EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD>
|
||||||
*/
|
*/
|
||||||
bool queue_peek(queue_t *q, void **element)
|
bool queue_peek(queue_t *q, void **element)
|
||||||
{
|
{
|
||||||
if (queue_is_empty(q))
|
if (queue_is_empty(q))
|
||||||
return false;
|
return false;
|
||||||
*element = (void *)((unsigned char *)q->base + q->front *
|
*element = (void *)((unsigned char *)q->base + q->front *
|
||||||
q->element_size);
|
q->element_size);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @brief ɾ<><C9BE><EFBFBD><EFBFBD>βԪ<CEB2><D4AA>
|
/* @brief ɾ<><C9BE><EFBFBD><EFBFBD>βԪ<CEB2><D4AA>
|
||||||
* @return true - <EFBFBD>ɹ<EFBFBD><EFBFBD>Ƴ<EFBFBD>, false - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD>,
|
* @return true - <EFBFBD>ɹ<EFBFBD><EFBFBD>Ƴ<EFBFBD>, false - <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ϊ<EFBFBD><EFBFBD>,
|
||||||
*/
|
*/
|
||||||
bool queue_del(queue_t *q)
|
bool queue_del(queue_t *q)
|
||||||
{
|
{
|
||||||
if (queue_is_empty(q))
|
if (queue_is_empty(q))
|
||||||
return false;
|
return false;
|
||||||
q->front = (q->front + 1) % q->size;
|
q->front = (q->front + 1) % q->size;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @brief <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>Ԫ<EFBFBD>ظ<EFBFBD><D8B8><EFBFBD>
|
/* @brief <20><>ȡ<EFBFBD><C8A1><EFBFBD><EFBFBD>Ԫ<EFBFBD>ظ<EFBFBD><D8B8><EFBFBD>
|
||||||
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD>ظ<EFBFBD><EFBFBD><EFBFBD>
|
* @return <EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD>ظ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
*/
|
*/
|
||||||
int queue_size(queue_t *q)
|
int queue_size(queue_t *q)
|
||||||
{
|
{
|
||||||
return (q->rear + q->size - q->front ) % q->size;
|
return (q->rear + q->size - q->front ) % q->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* @brief <20><><EFBFBD>ն<EFBFBD><D5B6><EFBFBD>
|
/* @brief <20><><EFBFBD>ն<EFBFBD><D5B6><EFBFBD>
|
||||||
* @return none
|
* @return none
|
||||||
*/
|
*/
|
||||||
void queue_clr(queue_t *q)
|
void queue_clr(queue_t *q)
|
||||||
{
|
{
|
||||||
q->front = q->rear = 0;
|
q->front = q->rear = 0;
|
||||||
}
|
}
|
@ -1,41 +1,41 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* @brief ͨ<EFBFBD>ö<EFBFBD><EFBFBD>й<EFBFBD><EFBFBD><EFBFBD>
|
* @brief ͨ<EFBFBD>ö<EFBFBD><EFBFBD>й<EFBFBD><EFBFBD><EFBFBD>
|
||||||
*
|
*
|
||||||
* Copyright (c) 2017~2020, <morro_luo@163.com>
|
* Copyright (c) 2017~2020, <morro_luo@163.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2017-03-19 Morro Initial version.
|
* 2017-03-19 roger.luo Initial version.
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
#ifndef _QUEUE_H_
|
#ifndef _QUEUE_H_
|
||||||
#define _QUEUE_H_
|
#define _QUEUE_H_
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
void *base; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ*/
|
void *base; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ַ*/
|
||||||
unsigned short element_size; /*<2A><><EFBFBD><EFBFBD>Ԫ<EFBFBD>ش<EFBFBD>С*/
|
unsigned short element_size; /*<2A><><EFBFBD><EFBFBD>Ԫ<EFBFBD>ش<EFBFBD>С*/
|
||||||
unsigned short size; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD>ظ<EFBFBD><D8B8><EFBFBD>*/
|
unsigned short size; /*<2A><><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ԫ<EFBFBD>ظ<EFBFBD><D8B8><EFBFBD>*/
|
||||||
unsigned short front; /*<2A><><EFBFBD><EFBFBD>*/
|
unsigned short front; /*<2A><><EFBFBD><EFBFBD>*/
|
||||||
unsigned short rear; /*<2A><>β*/
|
unsigned short rear; /*<2A><>β*/
|
||||||
}queue_t;
|
}queue_t;
|
||||||
|
|
||||||
bool queue_create(queue_t *q, void *container, int size, int element_size);
|
bool queue_create(queue_t *q, void *container, int size, int element_size);
|
||||||
bool queue_peek (queue_t *q, void **element);
|
bool queue_peek (queue_t *q, void **element);
|
||||||
bool queue_put (queue_t *q, void *element);
|
bool queue_put (queue_t *q, void *element);
|
||||||
bool queue_get (queue_t *q, void *element);
|
bool queue_get (queue_t *q, void *element);
|
||||||
bool queue_del (queue_t *q);
|
bool queue_del (queue_t *q);
|
||||||
void queue_clr (queue_t *q);
|
void queue_clr (queue_t *q);
|
||||||
int queue_len (queue_t *q);
|
int queue_len (queue_t *q);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif
|
@ -1,89 +1,101 @@
|
|||||||
/******************************************************************************
|
/******************************************************************************
|
||||||
* @brief <EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD>ο<EFBFBD>linux/kfifo)
|
* @brief <EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD>ο<EFBFBD>linux/kfifo)
|
||||||
*
|
*
|
||||||
* Copyright (c) 2016~2020, <morro_luo@163.com>
|
* Copyright (c) 2016~2021, <morro_luo@163.com>
|
||||||
*
|
*
|
||||||
* SPDX-License-Identifier: Apache-2.0
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*
|
*
|
||||||
* Change Logs:
|
* Change Logs:
|
||||||
* Date Author Notes
|
* Date Author Notes
|
||||||
* 2016-05-30 Morro <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
* 2016-05-30 roger.luo Initial version
|
||||||
******************************************************************************/
|
* 2021-02-05 roger.luo <EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD><EFBFBD>пռ<EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD>ӿ<EFBFBD>.
|
||||||
#include "ringbuffer.h"
|
******************************************************************************/
|
||||||
#include <string.h>
|
#include "ringbuffer.h"
|
||||||
#include <stddef.h>
|
#include <string.h>
|
||||||
|
#include <stddef.h>
|
||||||
#define min(a,b) ( (a) < (b) )? (a):(b)
|
|
||||||
|
#define min(a,b) ( (a) < (b) )? (a):(b)
|
||||||
/*
|
|
||||||
*@brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
/*
|
||||||
*@param[in] r - <EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
*@brief <EFBFBD><EFBFBD><EFBFBD><EFBFBD>һ<EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
*@param[in] buf - <EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
*@param[in] r - <EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
*@param[in] len - buf<EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD><EFBFBD>N<EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
*@param[in] buf - <EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
*@retval bool
|
*@param[in] len - buf<EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>2<EFBFBD><EFBFBD>N<EFBFBD><EFBFBD><EFBFBD><EFBFBD>)
|
||||||
*/
|
*@retval bool
|
||||||
bool ring_buf_init(ring_buf_t *r,unsigned char *buf, unsigned int len)
|
*/
|
||||||
{
|
bool ring_buf_init(ring_buf_t *r,unsigned char *buf, unsigned int len)
|
||||||
r->buf = buf;
|
{
|
||||||
r->size = len;
|
r->buf = buf;
|
||||||
r->front = r->rear = 0;
|
r->size = len;
|
||||||
return buf != NULL && (len & len -1) == 0;
|
r->front = r->rear = 0;
|
||||||
}
|
return buf != NULL && (len & len -1) == 0;
|
||||||
|
}
|
||||||
/*
|
|
||||||
*@brief <EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
/*
|
||||||
*@param[in] r - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>յĻ<EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
*@brief <EFBFBD><EFBFBD><EFBFBD>ջ<EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
*@retval none
|
*@param[in] r - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>յĻ<EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
*/
|
*@retval none
|
||||||
void ring_buf_clr(ring_buf_t *r)
|
*/
|
||||||
{
|
void ring_buf_clr(ring_buf_t *r)
|
||||||
r->front = r->rear = 0;
|
{
|
||||||
}
|
r->front = r->rear = 0;
|
||||||
|
}
|
||||||
/*
|
|
||||||
*@brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݳ<EFBFBD><EFBFBD><EFBFBD>
|
/*
|
||||||
*@retval <EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD>ֽ<EFBFBD><EFBFBD><EFBFBD>
|
*@brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݳ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
*/
|
*@retval <EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>Ч<EFBFBD>ֽ<EFBFBD><EFBFBD><EFBFBD>
|
||||||
unsigned int ring_buf_len(ring_buf_t *r)
|
*/
|
||||||
{
|
unsigned int ring_buf_len(ring_buf_t *r)
|
||||||
return r->rear - r->front;
|
{
|
||||||
}
|
return r->rear - r->front;
|
||||||
|
}
|
||||||
/*
|
|
||||||
*@brief <EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݷŵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
/*
|
||||||
*@param[in] buf - <EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
*@brief <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>пռ<EFBFBD>
|
||||||
* len - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
*@retval <EFBFBD><EFBFBD><EFBFBD>пռ<EFBFBD>
|
||||||
*@retval ʵ<EFBFBD>ʷŵ<EFBFBD><EFBFBD>е<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
*/
|
||||||
*/
|
unsigned int ring_buf_free_space(ring_buf_t *r)
|
||||||
unsigned int ring_buf_put(ring_buf_t *r,unsigned char *buf,unsigned int len)
|
{
|
||||||
{
|
return r->size - (unsigned int)(r->rear - r->front);
|
||||||
unsigned int i;
|
}
|
||||||
unsigned int left;
|
|
||||||
left = r->size + r->front - r->rear;
|
/*
|
||||||
len = min(len , left);
|
*@brief <EFBFBD><EFBFBD>ָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݷŵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
i = min(len, r->size - (r->rear & r->size - 1));
|
*@param[in] buf - <EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
memcpy(r->buf + (r->rear & r->size - 1), buf, i);
|
* len - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
memcpy(r->buf, buf + i, len - i);
|
*@retval ʵ<EFBFBD>ʷŵ<EFBFBD><EFBFBD>е<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
r->rear += len;
|
*/
|
||||||
return len;
|
unsigned int ring_buf_put(ring_buf_t *r,unsigned char *buf,unsigned int len)
|
||||||
|
{
|
||||||
}
|
unsigned int i;
|
||||||
|
unsigned int left;
|
||||||
/*
|
left = r->size + r->front - r->rear;
|
||||||
*@brief <EFBFBD>ӻ<EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>ȡָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
len = min(len , left);
|
||||||
*@param[in] len - <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
i = min(len, r->size - (r->rear & r->size - 1));
|
||||||
*@param[out] buf - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
memcpy(r->buf + (r->rear & r->size - 1), buf, i);
|
||||||
*@retval ʵ<EFBFBD>ʶ<EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
memcpy(r->buf, buf + i, len - i);
|
||||||
*/
|
r->rear += len;
|
||||||
unsigned int ring_buf_get(ring_buf_t *r,unsigned char *buf,unsigned int len)
|
return len;
|
||||||
{
|
|
||||||
unsigned int i;
|
}
|
||||||
unsigned int left;
|
|
||||||
left = r->rear - r->front;
|
/*
|
||||||
len = min(len , left);
|
*@brief <EFBFBD>ӻ<EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ж<EFBFBD>ȡָ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ȵ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
i = min(len, r->size - (r->front & r->size - 1));
|
*@param[in] len - <EFBFBD><EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
memcpy(buf, r->buf + (r->front & r->size - 1), i);
|
*@param[out] buf - <EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>ݻ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
memcpy(buf + i, r->buf, len - i);
|
*@retval ʵ<EFBFBD>ʶ<EFBFBD>ȡ<EFBFBD><EFBFBD><EFBFBD><EFBFBD>
|
||||||
r->front += len;
|
*/
|
||||||
return len;
|
unsigned int ring_buf_get(ring_buf_t *r,unsigned char *buf,unsigned int len)
|
||||||
}
|
{
|
||||||
|
unsigned int i;
|
||||||
|
unsigned int left;
|
||||||
|
if (ring_buf_len(r) == 0)
|
||||||
|
return 0;
|
||||||
|
left = r->rear - r->front;
|
||||||
|
len = min(len , left);
|
||||||
|
i = min(len, r->size - (r->front & r->size - 1));
|
||||||
|
memcpy(buf, r->buf + (r->front & r->size - 1), i);
|
||||||
|
memcpy(buf + i, r->buf, len - i);
|
||||||
|
r->front += len;
|
||||||
|
return len;
|
||||||
|
}
|
47
samples/none_os/framework/ringbuffer.h
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
/******************************************************************************
|
||||||
|
* @brief <EFBFBD><EFBFBD><EFBFBD>λ<EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>(<EFBFBD>ο<EFBFBD>linux/kfifo)
|
||||||
|
*
|
||||||
|
* Copyright (c) 2016~2021, <morro_luo@163.com>
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
|
*
|
||||||
|
* Change Logs:
|
||||||
|
* Date Author Notes
|
||||||
|
* 2016-05-30 roger.luo Initial version.
|
||||||
|
* 2021-02-05 roger.luo <EFBFBD><EFBFBD><EFBFBD>ӿ<EFBFBD><EFBFBD>пռ<EFBFBD><EFBFBD><EFBFBD>ȡ<EFBFBD>ӿ<EFBFBD>.
|
||||||
|
******************************************************************************/
|
||||||
|
|
||||||
|
#ifndef _RING_BUF_H_
|
||||||
|
#define _RING_BUF_H_
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*<2A><><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD><EFBFBD>*/
|
||||||
|
typedef struct {
|
||||||
|
unsigned char *buf; /*<2A><><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
unsigned int size; /*<2A><><EFBFBD>λ<EFBFBD><CEBB><EFBFBD><EFBFBD><EFBFBD> */
|
||||||
|
unsigned int front; /*ͷָ<CDB7><D6B8> */
|
||||||
|
unsigned int rear; /*βָ<CEB2><D6B8> */
|
||||||
|
}ring_buf_t;
|
||||||
|
|
||||||
|
bool ring_buf_init(ring_buf_t *r,unsigned char *buf,unsigned int size);
|
||||||
|
|
||||||
|
void ring_buf_clr(ring_buf_t *r);
|
||||||
|
|
||||||
|
unsigned int ring_buf_len(ring_buf_t *r);
|
||||||
|
|
||||||
|
unsigned int ring_buf_put(ring_buf_t *r,unsigned char *buf,unsigned int len);
|
||||||
|
|
||||||
|
unsigned int ring_buf_get(ring_buf_t *r,unsigned char *buf,unsigned int len);
|
||||||
|
|
||||||
|
unsigned int ring_buf_free_space(ring_buf_t *r);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif
|
@ -1,10 +1,10 @@
|
|||||||
<?xml version="1.0" encoding="iso-8859-1"?>
|
<?xml version="1.0" encoding="iso-8859-1"?>
|
||||||
|
|
||||||
<workspace>
|
<workspace>
|
||||||
<project>
|
<project>
|
||||||
<path>$WS_DIR$\codebrick.ewp</path>
|
<path>$WS_DIR$\codebrick.ewp</path>
|
||||||
</project>
|
</project>
|
||||||
<batchBuild/>
|
<batchBuild/>
|
||||||
</workspace>
|
</workspace>
|
||||||
|
|
||||||
|
|
@ -1,35 +1,35 @@
|
|||||||
/* ----------------------------------------------------------------------
|
/* ----------------------------------------------------------------------
|
||||||
* Copyright (C) 2010 ARM Limited. All rights reserved.
|
* Copyright (C) 2010 ARM Limited. All rights reserved.
|
||||||
*
|
*
|
||||||
* $Date: 11. November 2010
|
* $Date: 11. November 2010
|
||||||
* $Revision: V1.0.2
|
* $Revision: V1.0.2
|
||||||
*
|
*
|
||||||
* Project: CMSIS DSP Library
|
* Project: CMSIS DSP Library
|
||||||
* Title: arm_common_tables.h
|
* Title: arm_common_tables.h
|
||||||
*
|
*
|
||||||
* Description: This file has extern declaration for common tables like Bitreverse, reciprocal etc which are used across different functions
|
* Description: This file has extern declaration for common tables like Bitreverse, reciprocal etc which are used across different functions
|
||||||
*
|
*
|
||||||
* Target Processor: Cortex-M4/Cortex-M3
|
* Target Processor: Cortex-M4/Cortex-M3
|
||||||
*
|
*
|
||||||
* Version 1.0.2 2010/11/11
|
* Version 1.0.2 2010/11/11
|
||||||
* Documentation updated.
|
* Documentation updated.
|
||||||
*
|
*
|
||||||
* Version 1.0.1 2010/10/05
|
* Version 1.0.1 2010/10/05
|
||||||
* Production release and review comments incorporated.
|
* Production release and review comments incorporated.
|
||||||
*
|
*
|
||||||
* Version 1.0.0 2010/09/20
|
* Version 1.0.0 2010/09/20
|
||||||
* Production release and review comments incorporated.
|
* Production release and review comments incorporated.
|
||||||
* -------------------------------------------------------------------- */
|
* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
#ifndef _ARM_COMMON_TABLES_H
|
#ifndef _ARM_COMMON_TABLES_H
|
||||||
#define _ARM_COMMON_TABLES_H
|
#define _ARM_COMMON_TABLES_H
|
||||||
|
|
||||||
#include "arm_math.h"
|
#include "arm_math.h"
|
||||||
|
|
||||||
extern uint16_t armBitRevTable[256];
|
extern uint16_t armBitRevTable[256];
|
||||||
extern q15_t armRecipTableQ15[64];
|
extern q15_t armRecipTableQ15[64];
|
||||||
extern q31_t armRecipTableQ31[64];
|
extern q31_t armRecipTableQ31[64];
|
||||||
extern const q31_t realCoefAQ31[1024];
|
extern const q31_t realCoefAQ31[1024];
|
||||||
extern const q31_t realCoefBQ31[1024];
|
extern const q31_t realCoefBQ31[1024];
|
||||||
|
|
||||||
#endif /* ARM_COMMON_TABLES_H */
|
#endif /* ARM_COMMON_TABLES_H */
|
@ -1,99 +1,99 @@
|
|||||||
/**
|
/**
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @file system_stm32f4xx.h
|
* @file system_stm32f4xx.h
|
||||||
* @author MCD Application Team
|
* @author MCD Application Team
|
||||||
* @version V1.0.0
|
* @version V1.0.0
|
||||||
* @date 30-September-2011
|
* @date 30-September-2011
|
||||||
* @brief CMSIS Cortex-M4 Device System Source File for STM32F4xx devices.
|
* @brief CMSIS Cortex-M4 Device System Source File for STM32F4xx devices.
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @attention
|
* @attention
|
||||||
*
|
*
|
||||||
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
||||||
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
||||||
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
||||||
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
||||||
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||||
*
|
*
|
||||||
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
|
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @addtogroup CMSIS
|
/** @addtogroup CMSIS
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @addtogroup stm32f4xx_system
|
/** @addtogroup stm32f4xx_system
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Define to prevent recursive inclusion
|
* @brief Define to prevent recursive inclusion
|
||||||
*/
|
*/
|
||||||
#ifndef __SYSTEM_STM32F4XX_H
|
#ifndef __SYSTEM_STM32F4XX_H
|
||||||
#define __SYSTEM_STM32F4XX_H
|
#define __SYSTEM_STM32F4XX_H
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/** @addtogroup STM32F4xx_System_Includes
|
/** @addtogroup STM32F4xx_System_Includes
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/** @addtogroup STM32F4xx_System_Exported_types
|
/** @addtogroup STM32F4xx_System_Exported_types
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
|
extern uint32_t SystemCoreClock; /*!< System Clock Frequency (Core Clock) */
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @addtogroup STM32F4xx_System_Exported_Constants
|
/** @addtogroup STM32F4xx_System_Exported_Constants
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @addtogroup STM32F4xx_System_Exported_Macros
|
/** @addtogroup STM32F4xx_System_Exported_Macros
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @addtogroup STM32F4xx_System_Exported_Functions
|
/** @addtogroup STM32F4xx_System_Exported_Functions
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
extern void SystemInit(void);
|
extern void SystemInit(void);
|
||||||
extern void SystemCoreClockUpdate(void);
|
extern void SystemCoreClockUpdate(void);
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /*__SYSTEM_STM32F4XX_H */
|
#endif /*__SYSTEM_STM32F4XX_H */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
|
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
|
@ -1,427 +1,427 @@
|
|||||||
;******************** (C) COPYRIGHT 2011 STMicroelectronics ********************
|
;******************** (C) COPYRIGHT 2011 STMicroelectronics ********************
|
||||||
;* File Name : startup_stm32f4xx.s
|
;* File Name : startup_stm32f4xx.s
|
||||||
;* Author : MCD Application Team
|
;* Author : MCD Application Team
|
||||||
;* Version : V1.0.0
|
;* Version : V1.0.0
|
||||||
;* Date : 30-September-2011
|
;* Date : 30-September-2011
|
||||||
;* Description : STM32F4xx devices vector table for MDK-ARM toolchain.
|
;* Description : STM32F4xx devices vector table for MDK-ARM toolchain.
|
||||||
;* This module performs:
|
;* This module performs:
|
||||||
;* - Set the initial SP
|
;* - Set the initial SP
|
||||||
;* - Set the initial PC == Reset_Handler
|
;* - Set the initial PC == Reset_Handler
|
||||||
;* - Set the vector table entries with the exceptions ISR address
|
;* - Set the vector table entries with the exceptions ISR address
|
||||||
;* - Configure the system clock and the external SRAM mounted on
|
;* - Configure the system clock and the external SRAM mounted on
|
||||||
;* STM324xG-EVAL board to be used as data memory (optional,
|
;* STM324xG-EVAL board to be used as data memory (optional,
|
||||||
;* to be enabled by user)
|
;* to be enabled by user)
|
||||||
;* - Branches to __main in the C library (which eventually
|
;* - Branches to __main in the C library (which eventually
|
||||||
;* calls main()).
|
;* calls main()).
|
||||||
;* After Reset the CortexM4 processor is in Thread mode,
|
;* After Reset the CortexM4 processor is in Thread mode,
|
||||||
;* priority is Privileged, and the Stack is set to Main.
|
;* priority is Privileged, and the Stack is set to Main.
|
||||||
;* <<< Use Configuration Wizard in Context Menu >>>
|
;* <<< Use Configuration Wizard in Context Menu >>>
|
||||||
;*******************************************************************************
|
;*******************************************************************************
|
||||||
; THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
; THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
||||||
; WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
|
; WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE TIME.
|
||||||
; AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
|
; AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY DIRECT,
|
||||||
; INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
|
; INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING FROM THE
|
||||||
; CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
|
; CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE CODING
|
||||||
; INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
; INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||||
;*******************************************************************************
|
;*******************************************************************************
|
||||||
|
|
||||||
; Amount of memory (in bytes) allocated for Stack
|
; Amount of memory (in bytes) allocated for Stack
|
||||||
; Tailor this value to your application needs
|
; Tailor this value to your application needs
|
||||||
; <h> Stack Configuration
|
; <h> Stack Configuration
|
||||||
; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
|
; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
|
||||||
; </h>
|
; </h>
|
||||||
|
|
||||||
Stack_Size EQU 0x00000400
|
Stack_Size EQU 0x00000400
|
||||||
|
|
||||||
AREA STACK, NOINIT, READWRITE, ALIGN=3
|
AREA STACK, NOINIT, READWRITE, ALIGN=3
|
||||||
Stack_Mem SPACE Stack_Size
|
Stack_Mem SPACE Stack_Size
|
||||||
__initial_sp
|
__initial_sp
|
||||||
|
|
||||||
|
|
||||||
; <h> Heap Configuration
|
; <h> Heap Configuration
|
||||||
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
|
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
|
||||||
; </h>
|
; </h>
|
||||||
|
|
||||||
Heap_Size EQU 0x00000200
|
Heap_Size EQU 0x00000200
|
||||||
|
|
||||||
AREA HEAP, NOINIT, READWRITE, ALIGN=3
|
AREA HEAP, NOINIT, READWRITE, ALIGN=3
|
||||||
__heap_base
|
__heap_base
|
||||||
Heap_Mem SPACE Heap_Size
|
Heap_Mem SPACE Heap_Size
|
||||||
__heap_limit
|
__heap_limit
|
||||||
|
|
||||||
PRESERVE8
|
PRESERVE8
|
||||||
THUMB
|
THUMB
|
||||||
|
|
||||||
|
|
||||||
; Vector Table Mapped to Address 0 at Reset
|
; Vector Table Mapped to Address 0 at Reset
|
||||||
AREA RESET, DATA, READONLY
|
AREA RESET, DATA, READONLY
|
||||||
EXPORT __Vectors
|
EXPORT __Vectors
|
||||||
EXPORT __Vectors_End
|
EXPORT __Vectors_End
|
||||||
EXPORT __Vectors_Size
|
EXPORT __Vectors_Size
|
||||||
|
|
||||||
__Vectors DCD __initial_sp ; Top of Stack
|
__Vectors DCD __initial_sp ; Top of Stack
|
||||||
DCD Reset_Handler ; Reset Handler
|
DCD Reset_Handler ; Reset Handler
|
||||||
DCD NMI_Handler ; NMI Handler
|
DCD NMI_Handler ; NMI Handler
|
||||||
DCD HardFault_Handler ; Hard Fault Handler
|
DCD HardFault_Handler ; Hard Fault Handler
|
||||||
DCD MemManage_Handler ; MPU Fault Handler
|
DCD MemManage_Handler ; MPU Fault Handler
|
||||||
DCD BusFault_Handler ; Bus Fault Handler
|
DCD BusFault_Handler ; Bus Fault Handler
|
||||||
DCD UsageFault_Handler ; Usage Fault Handler
|
DCD UsageFault_Handler ; Usage Fault Handler
|
||||||
DCD 0 ; Reserved
|
DCD 0 ; Reserved
|
||||||
DCD 0 ; Reserved
|
DCD 0 ; Reserved
|
||||||
DCD 0 ; Reserved
|
DCD 0 ; Reserved
|
||||||
DCD 0 ; Reserved
|
DCD 0 ; Reserved
|
||||||
DCD SVC_Handler ; SVCall Handler
|
DCD SVC_Handler ; SVCall Handler
|
||||||
DCD DebugMon_Handler ; Debug Monitor Handler
|
DCD DebugMon_Handler ; Debug Monitor Handler
|
||||||
DCD 0 ; Reserved
|
DCD 0 ; Reserved
|
||||||
DCD PendSV_Handler ; PendSV Handler
|
DCD PendSV_Handler ; PendSV Handler
|
||||||
DCD SysTick_Handler ; SysTick Handler
|
DCD SysTick_Handler ; SysTick Handler
|
||||||
|
|
||||||
; External Interrupts
|
; External Interrupts
|
||||||
DCD WWDG_IRQHandler ; Window WatchDog
|
DCD WWDG_IRQHandler ; Window WatchDog
|
||||||
DCD PVD_IRQHandler ; PVD through EXTI Line detection
|
DCD PVD_IRQHandler ; PVD through EXTI Line detection
|
||||||
DCD TAMP_STAMP_IRQHandler ; Tamper and TimeStamps through the EXTI line
|
DCD TAMP_STAMP_IRQHandler ; Tamper and TimeStamps through the EXTI line
|
||||||
DCD RTC_WKUP_IRQHandler ; RTC Wakeup through the EXTI line
|
DCD RTC_WKUP_IRQHandler ; RTC Wakeup through the EXTI line
|
||||||
DCD FLASH_IRQHandler ; FLASH
|
DCD FLASH_IRQHandler ; FLASH
|
||||||
DCD RCC_IRQHandler ; RCC
|
DCD RCC_IRQHandler ; RCC
|
||||||
DCD EXTI0_IRQHandler ; EXTI Line0
|
DCD EXTI0_IRQHandler ; EXTI Line0
|
||||||
DCD EXTI1_IRQHandler ; EXTI Line1
|
DCD EXTI1_IRQHandler ; EXTI Line1
|
||||||
DCD EXTI2_IRQHandler ; EXTI Line2
|
DCD EXTI2_IRQHandler ; EXTI Line2
|
||||||
DCD EXTI3_IRQHandler ; EXTI Line3
|
DCD EXTI3_IRQHandler ; EXTI Line3
|
||||||
DCD EXTI4_IRQHandler ; EXTI Line4
|
DCD EXTI4_IRQHandler ; EXTI Line4
|
||||||
DCD DMA1_Stream0_IRQHandler ; DMA1 Stream 0
|
DCD DMA1_Stream0_IRQHandler ; DMA1 Stream 0
|
||||||
DCD DMA1_Stream1_IRQHandler ; DMA1 Stream 1
|
DCD DMA1_Stream1_IRQHandler ; DMA1 Stream 1
|
||||||
DCD DMA1_Stream2_IRQHandler ; DMA1 Stream 2
|
DCD DMA1_Stream2_IRQHandler ; DMA1 Stream 2
|
||||||
DCD DMA1_Stream3_IRQHandler ; DMA1 Stream 3
|
DCD DMA1_Stream3_IRQHandler ; DMA1 Stream 3
|
||||||
DCD DMA1_Stream4_IRQHandler ; DMA1 Stream 4
|
DCD DMA1_Stream4_IRQHandler ; DMA1 Stream 4
|
||||||
DCD DMA1_Stream5_IRQHandler ; DMA1 Stream 5
|
DCD DMA1_Stream5_IRQHandler ; DMA1 Stream 5
|
||||||
DCD DMA1_Stream6_IRQHandler ; DMA1 Stream 6
|
DCD DMA1_Stream6_IRQHandler ; DMA1 Stream 6
|
||||||
DCD ADC_IRQHandler ; ADC1, ADC2 and ADC3s
|
DCD ADC_IRQHandler ; ADC1, ADC2 and ADC3s
|
||||||
DCD CAN1_TX_IRQHandler ; CAN1 TX
|
DCD CAN1_TX_IRQHandler ; CAN1 TX
|
||||||
DCD CAN1_RX0_IRQHandler ; CAN1 RX0
|
DCD CAN1_RX0_IRQHandler ; CAN1 RX0
|
||||||
DCD CAN1_RX1_IRQHandler ; CAN1 RX1
|
DCD CAN1_RX1_IRQHandler ; CAN1 RX1
|
||||||
DCD CAN1_SCE_IRQHandler ; CAN1 SCE
|
DCD CAN1_SCE_IRQHandler ; CAN1 SCE
|
||||||
DCD EXTI9_5_IRQHandler ; External Line[9:5]s
|
DCD EXTI9_5_IRQHandler ; External Line[9:5]s
|
||||||
DCD TIM1_BRK_TIM9_IRQHandler ; TIM1 Break and TIM9
|
DCD TIM1_BRK_TIM9_IRQHandler ; TIM1 Break and TIM9
|
||||||
DCD TIM1_UP_TIM10_IRQHandler ; TIM1 Update and TIM10
|
DCD TIM1_UP_TIM10_IRQHandler ; TIM1 Update and TIM10
|
||||||
DCD TIM1_TRG_COM_TIM11_IRQHandler ; TIM1 Trigger and Commutation and TIM11
|
DCD TIM1_TRG_COM_TIM11_IRQHandler ; TIM1 Trigger and Commutation and TIM11
|
||||||
DCD TIM1_CC_IRQHandler ; TIM1 Capture Compare
|
DCD TIM1_CC_IRQHandler ; TIM1 Capture Compare
|
||||||
DCD TIM2_IRQHandler ; TIM2
|
DCD TIM2_IRQHandler ; TIM2
|
||||||
DCD TIM3_IRQHandler ; TIM3
|
DCD TIM3_IRQHandler ; TIM3
|
||||||
DCD TIM4_IRQHandler ; TIM4
|
DCD TIM4_IRQHandler ; TIM4
|
||||||
DCD I2C1_EV_IRQHandler ; I2C1 Event
|
DCD I2C1_EV_IRQHandler ; I2C1 Event
|
||||||
DCD I2C1_ER_IRQHandler ; I2C1 Error
|
DCD I2C1_ER_IRQHandler ; I2C1 Error
|
||||||
DCD I2C2_EV_IRQHandler ; I2C2 Event
|
DCD I2C2_EV_IRQHandler ; I2C2 Event
|
||||||
DCD I2C2_ER_IRQHandler ; I2C2 Error
|
DCD I2C2_ER_IRQHandler ; I2C2 Error
|
||||||
DCD SPI1_IRQHandler ; SPI1
|
DCD SPI1_IRQHandler ; SPI1
|
||||||
DCD SPI2_IRQHandler ; SPI2
|
DCD SPI2_IRQHandler ; SPI2
|
||||||
DCD USART1_IRQHandler ; USART1
|
DCD USART1_IRQHandler ; USART1
|
||||||
DCD USART2_IRQHandler ; USART2
|
DCD USART2_IRQHandler ; USART2
|
||||||
DCD USART3_IRQHandler ; USART3
|
DCD USART3_IRQHandler ; USART3
|
||||||
DCD EXTI15_10_IRQHandler ; External Line[15:10]s
|
DCD EXTI15_10_IRQHandler ; External Line[15:10]s
|
||||||
DCD RTC_Alarm_IRQHandler ; RTC Alarm (A and B) through EXTI Line
|
DCD RTC_Alarm_IRQHandler ; RTC Alarm (A and B) through EXTI Line
|
||||||
DCD OTG_FS_WKUP_IRQHandler ; USB OTG FS Wakeup through EXTI line
|
DCD OTG_FS_WKUP_IRQHandler ; USB OTG FS Wakeup through EXTI line
|
||||||
DCD TIM8_BRK_TIM12_IRQHandler ; TIM8 Break and TIM12
|
DCD TIM8_BRK_TIM12_IRQHandler ; TIM8 Break and TIM12
|
||||||
DCD TIM8_UP_TIM13_IRQHandler ; TIM8 Update and TIM13
|
DCD TIM8_UP_TIM13_IRQHandler ; TIM8 Update and TIM13
|
||||||
DCD TIM8_TRG_COM_TIM14_IRQHandler ; TIM8 Trigger and Commutation and TIM14
|
DCD TIM8_TRG_COM_TIM14_IRQHandler ; TIM8 Trigger and Commutation and TIM14
|
||||||
DCD TIM8_CC_IRQHandler ; TIM8 Capture Compare
|
DCD TIM8_CC_IRQHandler ; TIM8 Capture Compare
|
||||||
DCD DMA1_Stream7_IRQHandler ; DMA1 Stream7
|
DCD DMA1_Stream7_IRQHandler ; DMA1 Stream7
|
||||||
DCD FSMC_IRQHandler ; FSMC
|
DCD FSMC_IRQHandler ; FSMC
|
||||||
DCD SDIO_IRQHandler ; SDIO
|
DCD SDIO_IRQHandler ; SDIO
|
||||||
DCD TIM5_IRQHandler ; TIM5
|
DCD TIM5_IRQHandler ; TIM5
|
||||||
DCD SPI3_IRQHandler ; SPI3
|
DCD SPI3_IRQHandler ; SPI3
|
||||||
DCD UART4_IRQHandler ; UART4
|
DCD UART4_IRQHandler ; UART4
|
||||||
DCD UART5_IRQHandler ; UART5
|
DCD UART5_IRQHandler ; UART5
|
||||||
DCD TIM6_DAC_IRQHandler ; TIM6 and DAC1&2 underrun errors
|
DCD TIM6_DAC_IRQHandler ; TIM6 and DAC1&2 underrun errors
|
||||||
DCD TIM7_IRQHandler ; TIM7
|
DCD TIM7_IRQHandler ; TIM7
|
||||||
DCD DMA2_Stream0_IRQHandler ; DMA2 Stream 0
|
DCD DMA2_Stream0_IRQHandler ; DMA2 Stream 0
|
||||||
DCD DMA2_Stream1_IRQHandler ; DMA2 Stream 1
|
DCD DMA2_Stream1_IRQHandler ; DMA2 Stream 1
|
||||||
DCD DMA2_Stream2_IRQHandler ; DMA2 Stream 2
|
DCD DMA2_Stream2_IRQHandler ; DMA2 Stream 2
|
||||||
DCD DMA2_Stream3_IRQHandler ; DMA2 Stream 3
|
DCD DMA2_Stream3_IRQHandler ; DMA2 Stream 3
|
||||||
DCD DMA2_Stream4_IRQHandler ; DMA2 Stream 4
|
DCD DMA2_Stream4_IRQHandler ; DMA2 Stream 4
|
||||||
DCD ETH_IRQHandler ; Ethernet
|
DCD ETH_IRQHandler ; Ethernet
|
||||||
DCD ETH_WKUP_IRQHandler ; Ethernet Wakeup through EXTI line
|
DCD ETH_WKUP_IRQHandler ; Ethernet Wakeup through EXTI line
|
||||||
DCD CAN2_TX_IRQHandler ; CAN2 TX
|
DCD CAN2_TX_IRQHandler ; CAN2 TX
|
||||||
DCD CAN2_RX0_IRQHandler ; CAN2 RX0
|
DCD CAN2_RX0_IRQHandler ; CAN2 RX0
|
||||||
DCD CAN2_RX1_IRQHandler ; CAN2 RX1
|
DCD CAN2_RX1_IRQHandler ; CAN2 RX1
|
||||||
DCD CAN2_SCE_IRQHandler ; CAN2 SCE
|
DCD CAN2_SCE_IRQHandler ; CAN2 SCE
|
||||||
DCD OTG_FS_IRQHandler ; USB OTG FS
|
DCD OTG_FS_IRQHandler ; USB OTG FS
|
||||||
DCD DMA2_Stream5_IRQHandler ; DMA2 Stream 5
|
DCD DMA2_Stream5_IRQHandler ; DMA2 Stream 5
|
||||||
DCD DMA2_Stream6_IRQHandler ; DMA2 Stream 6
|
DCD DMA2_Stream6_IRQHandler ; DMA2 Stream 6
|
||||||
DCD DMA2_Stream7_IRQHandler ; DMA2 Stream 7
|
DCD DMA2_Stream7_IRQHandler ; DMA2 Stream 7
|
||||||
DCD USART6_IRQHandler ; USART6
|
DCD USART6_IRQHandler ; USART6
|
||||||
DCD I2C3_EV_IRQHandler ; I2C3 event
|
DCD I2C3_EV_IRQHandler ; I2C3 event
|
||||||
DCD I2C3_ER_IRQHandler ; I2C3 error
|
DCD I2C3_ER_IRQHandler ; I2C3 error
|
||||||
DCD OTG_HS_EP1_OUT_IRQHandler ; USB OTG HS End Point 1 Out
|
DCD OTG_HS_EP1_OUT_IRQHandler ; USB OTG HS End Point 1 Out
|
||||||
DCD OTG_HS_EP1_IN_IRQHandler ; USB OTG HS End Point 1 In
|
DCD OTG_HS_EP1_IN_IRQHandler ; USB OTG HS End Point 1 In
|
||||||
DCD OTG_HS_WKUP_IRQHandler ; USB OTG HS Wakeup through EXTI
|
DCD OTG_HS_WKUP_IRQHandler ; USB OTG HS Wakeup through EXTI
|
||||||
DCD OTG_HS_IRQHandler ; USB OTG HS
|
DCD OTG_HS_IRQHandler ; USB OTG HS
|
||||||
DCD DCMI_IRQHandler ; DCMI
|
DCD DCMI_IRQHandler ; DCMI
|
||||||
DCD CRYP_IRQHandler ; CRYP crypto
|
DCD CRYP_IRQHandler ; CRYP crypto
|
||||||
DCD HASH_RNG_IRQHandler ; Hash and Rng
|
DCD HASH_RNG_IRQHandler ; Hash and Rng
|
||||||
DCD FPU_IRQHandler ; FPU
|
DCD FPU_IRQHandler ; FPU
|
||||||
|
|
||||||
__Vectors_End
|
__Vectors_End
|
||||||
|
|
||||||
__Vectors_Size EQU __Vectors_End - __Vectors
|
__Vectors_Size EQU __Vectors_End - __Vectors
|
||||||
|
|
||||||
AREA |.text|, CODE, READONLY
|
AREA |.text|, CODE, READONLY
|
||||||
|
|
||||||
; Reset handler
|
; Reset handler
|
||||||
Reset_Handler PROC
|
Reset_Handler PROC
|
||||||
EXPORT Reset_Handler [WEAK]
|
EXPORT Reset_Handler [WEAK]
|
||||||
IMPORT SystemInit
|
IMPORT SystemInit
|
||||||
IMPORT __main
|
IMPORT __main
|
||||||
|
|
||||||
LDR R0, =SystemInit
|
LDR R0, =SystemInit
|
||||||
BLX R0
|
BLX R0
|
||||||
LDR R0, =__main
|
LDR R0, =__main
|
||||||
BX R0
|
BX R0
|
||||||
ENDP
|
ENDP
|
||||||
|
|
||||||
; Dummy Exception Handlers (infinite loops which can be modified)
|
; Dummy Exception Handlers (infinite loops which can be modified)
|
||||||
|
|
||||||
NMI_Handler PROC
|
NMI_Handler PROC
|
||||||
EXPORT NMI_Handler [WEAK]
|
EXPORT NMI_Handler [WEAK]
|
||||||
B .
|
B .
|
||||||
ENDP
|
ENDP
|
||||||
HardFault_Handler\
|
HardFault_Handler\
|
||||||
PROC
|
PROC
|
||||||
EXPORT HardFault_Handler [WEAK]
|
EXPORT HardFault_Handler [WEAK]
|
||||||
B .
|
B .
|
||||||
ENDP
|
ENDP
|
||||||
MemManage_Handler\
|
MemManage_Handler\
|
||||||
PROC
|
PROC
|
||||||
EXPORT MemManage_Handler [WEAK]
|
EXPORT MemManage_Handler [WEAK]
|
||||||
B .
|
B .
|
||||||
ENDP
|
ENDP
|
||||||
BusFault_Handler\
|
BusFault_Handler\
|
||||||
PROC
|
PROC
|
||||||
EXPORT BusFault_Handler [WEAK]
|
EXPORT BusFault_Handler [WEAK]
|
||||||
B .
|
B .
|
||||||
ENDP
|
ENDP
|
||||||
UsageFault_Handler\
|
UsageFault_Handler\
|
||||||
PROC
|
PROC
|
||||||
EXPORT UsageFault_Handler [WEAK]
|
EXPORT UsageFault_Handler [WEAK]
|
||||||
B .
|
B .
|
||||||
ENDP
|
ENDP
|
||||||
SVC_Handler PROC
|
SVC_Handler PROC
|
||||||
EXPORT SVC_Handler [WEAK]
|
EXPORT SVC_Handler [WEAK]
|
||||||
B .
|
B .
|
||||||
ENDP
|
ENDP
|
||||||
DebugMon_Handler\
|
DebugMon_Handler\
|
||||||
PROC
|
PROC
|
||||||
EXPORT DebugMon_Handler [WEAK]
|
EXPORT DebugMon_Handler [WEAK]
|
||||||
B .
|
B .
|
||||||
ENDP
|
ENDP
|
||||||
PendSV_Handler PROC
|
PendSV_Handler PROC
|
||||||
EXPORT PendSV_Handler [WEAK]
|
EXPORT PendSV_Handler [WEAK]
|
||||||
B .
|
B .
|
||||||
ENDP
|
ENDP
|
||||||
SysTick_Handler PROC
|
SysTick_Handler PROC
|
||||||
EXPORT SysTick_Handler [WEAK]
|
EXPORT SysTick_Handler [WEAK]
|
||||||
B .
|
B .
|
||||||
ENDP
|
ENDP
|
||||||
|
|
||||||
Default_Handler PROC
|
Default_Handler PROC
|
||||||
|
|
||||||
EXPORT WWDG_IRQHandler [WEAK]
|
EXPORT WWDG_IRQHandler [WEAK]
|
||||||
EXPORT PVD_IRQHandler [WEAK]
|
EXPORT PVD_IRQHandler [WEAK]
|
||||||
EXPORT TAMP_STAMP_IRQHandler [WEAK]
|
EXPORT TAMP_STAMP_IRQHandler [WEAK]
|
||||||
EXPORT RTC_WKUP_IRQHandler [WEAK]
|
EXPORT RTC_WKUP_IRQHandler [WEAK]
|
||||||
EXPORT FLASH_IRQHandler [WEAK]
|
EXPORT FLASH_IRQHandler [WEAK]
|
||||||
EXPORT RCC_IRQHandler [WEAK]
|
EXPORT RCC_IRQHandler [WEAK]
|
||||||
EXPORT EXTI0_IRQHandler [WEAK]
|
EXPORT EXTI0_IRQHandler [WEAK]
|
||||||
EXPORT EXTI1_IRQHandler [WEAK]
|
EXPORT EXTI1_IRQHandler [WEAK]
|
||||||
EXPORT EXTI2_IRQHandler [WEAK]
|
EXPORT EXTI2_IRQHandler [WEAK]
|
||||||
EXPORT EXTI3_IRQHandler [WEAK]
|
EXPORT EXTI3_IRQHandler [WEAK]
|
||||||
EXPORT EXTI4_IRQHandler [WEAK]
|
EXPORT EXTI4_IRQHandler [WEAK]
|
||||||
EXPORT DMA1_Stream0_IRQHandler [WEAK]
|
EXPORT DMA1_Stream0_IRQHandler [WEAK]
|
||||||
EXPORT DMA1_Stream1_IRQHandler [WEAK]
|
EXPORT DMA1_Stream1_IRQHandler [WEAK]
|
||||||
EXPORT DMA1_Stream2_IRQHandler [WEAK]
|
EXPORT DMA1_Stream2_IRQHandler [WEAK]
|
||||||
EXPORT DMA1_Stream3_IRQHandler [WEAK]
|
EXPORT DMA1_Stream3_IRQHandler [WEAK]
|
||||||
EXPORT DMA1_Stream4_IRQHandler [WEAK]
|
EXPORT DMA1_Stream4_IRQHandler [WEAK]
|
||||||
EXPORT DMA1_Stream5_IRQHandler [WEAK]
|
EXPORT DMA1_Stream5_IRQHandler [WEAK]
|
||||||
EXPORT DMA1_Stream6_IRQHandler [WEAK]
|
EXPORT DMA1_Stream6_IRQHandler [WEAK]
|
||||||
EXPORT ADC_IRQHandler [WEAK]
|
EXPORT ADC_IRQHandler [WEAK]
|
||||||
EXPORT CAN1_TX_IRQHandler [WEAK]
|
EXPORT CAN1_TX_IRQHandler [WEAK]
|
||||||
EXPORT CAN1_RX0_IRQHandler [WEAK]
|
EXPORT CAN1_RX0_IRQHandler [WEAK]
|
||||||
EXPORT CAN1_RX1_IRQHandler [WEAK]
|
EXPORT CAN1_RX1_IRQHandler [WEAK]
|
||||||
EXPORT CAN1_SCE_IRQHandler [WEAK]
|
EXPORT CAN1_SCE_IRQHandler [WEAK]
|
||||||
EXPORT EXTI9_5_IRQHandler [WEAK]
|
EXPORT EXTI9_5_IRQHandler [WEAK]
|
||||||
EXPORT TIM1_BRK_TIM9_IRQHandler [WEAK]
|
EXPORT TIM1_BRK_TIM9_IRQHandler [WEAK]
|
||||||
EXPORT TIM1_UP_TIM10_IRQHandler [WEAK]
|
EXPORT TIM1_UP_TIM10_IRQHandler [WEAK]
|
||||||
EXPORT TIM1_TRG_COM_TIM11_IRQHandler [WEAK]
|
EXPORT TIM1_TRG_COM_TIM11_IRQHandler [WEAK]
|
||||||
EXPORT TIM1_CC_IRQHandler [WEAK]
|
EXPORT TIM1_CC_IRQHandler [WEAK]
|
||||||
EXPORT TIM2_IRQHandler [WEAK]
|
EXPORT TIM2_IRQHandler [WEAK]
|
||||||
EXPORT TIM3_IRQHandler [WEAK]
|
EXPORT TIM3_IRQHandler [WEAK]
|
||||||
EXPORT TIM4_IRQHandler [WEAK]
|
EXPORT TIM4_IRQHandler [WEAK]
|
||||||
EXPORT I2C1_EV_IRQHandler [WEAK]
|
EXPORT I2C1_EV_IRQHandler [WEAK]
|
||||||
EXPORT I2C1_ER_IRQHandler [WEAK]
|
EXPORT I2C1_ER_IRQHandler [WEAK]
|
||||||
EXPORT I2C2_EV_IRQHandler [WEAK]
|
EXPORT I2C2_EV_IRQHandler [WEAK]
|
||||||
EXPORT I2C2_ER_IRQHandler [WEAK]
|
EXPORT I2C2_ER_IRQHandler [WEAK]
|
||||||
EXPORT SPI1_IRQHandler [WEAK]
|
EXPORT SPI1_IRQHandler [WEAK]
|
||||||
EXPORT SPI2_IRQHandler [WEAK]
|
EXPORT SPI2_IRQHandler [WEAK]
|
||||||
EXPORT USART1_IRQHandler [WEAK]
|
EXPORT USART1_IRQHandler [WEAK]
|
||||||
EXPORT USART2_IRQHandler [WEAK]
|
EXPORT USART2_IRQHandler [WEAK]
|
||||||
EXPORT USART3_IRQHandler [WEAK]
|
EXPORT USART3_IRQHandler [WEAK]
|
||||||
EXPORT EXTI15_10_IRQHandler [WEAK]
|
EXPORT EXTI15_10_IRQHandler [WEAK]
|
||||||
EXPORT RTC_Alarm_IRQHandler [WEAK]
|
EXPORT RTC_Alarm_IRQHandler [WEAK]
|
||||||
EXPORT OTG_FS_WKUP_IRQHandler [WEAK]
|
EXPORT OTG_FS_WKUP_IRQHandler [WEAK]
|
||||||
EXPORT TIM8_BRK_TIM12_IRQHandler [WEAK]
|
EXPORT TIM8_BRK_TIM12_IRQHandler [WEAK]
|
||||||
EXPORT TIM8_UP_TIM13_IRQHandler [WEAK]
|
EXPORT TIM8_UP_TIM13_IRQHandler [WEAK]
|
||||||
EXPORT TIM8_TRG_COM_TIM14_IRQHandler [WEAK]
|
EXPORT TIM8_TRG_COM_TIM14_IRQHandler [WEAK]
|
||||||
EXPORT TIM8_CC_IRQHandler [WEAK]
|
EXPORT TIM8_CC_IRQHandler [WEAK]
|
||||||
EXPORT DMA1_Stream7_IRQHandler [WEAK]
|
EXPORT DMA1_Stream7_IRQHandler [WEAK]
|
||||||
EXPORT FSMC_IRQHandler [WEAK]
|
EXPORT FSMC_IRQHandler [WEAK]
|
||||||
EXPORT SDIO_IRQHandler [WEAK]
|
EXPORT SDIO_IRQHandler [WEAK]
|
||||||
EXPORT TIM5_IRQHandler [WEAK]
|
EXPORT TIM5_IRQHandler [WEAK]
|
||||||
EXPORT SPI3_IRQHandler [WEAK]
|
EXPORT SPI3_IRQHandler [WEAK]
|
||||||
EXPORT UART4_IRQHandler [WEAK]
|
EXPORT UART4_IRQHandler [WEAK]
|
||||||
EXPORT UART5_IRQHandler [WEAK]
|
EXPORT UART5_IRQHandler [WEAK]
|
||||||
EXPORT TIM6_DAC_IRQHandler [WEAK]
|
EXPORT TIM6_DAC_IRQHandler [WEAK]
|
||||||
EXPORT TIM7_IRQHandler [WEAK]
|
EXPORT TIM7_IRQHandler [WEAK]
|
||||||
EXPORT DMA2_Stream0_IRQHandler [WEAK]
|
EXPORT DMA2_Stream0_IRQHandler [WEAK]
|
||||||
EXPORT DMA2_Stream1_IRQHandler [WEAK]
|
EXPORT DMA2_Stream1_IRQHandler [WEAK]
|
||||||
EXPORT DMA2_Stream2_IRQHandler [WEAK]
|
EXPORT DMA2_Stream2_IRQHandler [WEAK]
|
||||||
EXPORT DMA2_Stream3_IRQHandler [WEAK]
|
EXPORT DMA2_Stream3_IRQHandler [WEAK]
|
||||||
EXPORT DMA2_Stream4_IRQHandler [WEAK]
|
EXPORT DMA2_Stream4_IRQHandler [WEAK]
|
||||||
EXPORT ETH_IRQHandler [WEAK]
|
EXPORT ETH_IRQHandler [WEAK]
|
||||||
EXPORT ETH_WKUP_IRQHandler [WEAK]
|
EXPORT ETH_WKUP_IRQHandler [WEAK]
|
||||||
EXPORT CAN2_TX_IRQHandler [WEAK]
|
EXPORT CAN2_TX_IRQHandler [WEAK]
|
||||||
EXPORT CAN2_RX0_IRQHandler [WEAK]
|
EXPORT CAN2_RX0_IRQHandler [WEAK]
|
||||||
EXPORT CAN2_RX1_IRQHandler [WEAK]
|
EXPORT CAN2_RX1_IRQHandler [WEAK]
|
||||||
EXPORT CAN2_SCE_IRQHandler [WEAK]
|
EXPORT CAN2_SCE_IRQHandler [WEAK]
|
||||||
EXPORT OTG_FS_IRQHandler [WEAK]
|
EXPORT OTG_FS_IRQHandler [WEAK]
|
||||||
EXPORT DMA2_Stream5_IRQHandler [WEAK]
|
EXPORT DMA2_Stream5_IRQHandler [WEAK]
|
||||||
EXPORT DMA2_Stream6_IRQHandler [WEAK]
|
EXPORT DMA2_Stream6_IRQHandler [WEAK]
|
||||||
EXPORT DMA2_Stream7_IRQHandler [WEAK]
|
EXPORT DMA2_Stream7_IRQHandler [WEAK]
|
||||||
EXPORT USART6_IRQHandler [WEAK]
|
EXPORT USART6_IRQHandler [WEAK]
|
||||||
EXPORT I2C3_EV_IRQHandler [WEAK]
|
EXPORT I2C3_EV_IRQHandler [WEAK]
|
||||||
EXPORT I2C3_ER_IRQHandler [WEAK]
|
EXPORT I2C3_ER_IRQHandler [WEAK]
|
||||||
EXPORT OTG_HS_EP1_OUT_IRQHandler [WEAK]
|
EXPORT OTG_HS_EP1_OUT_IRQHandler [WEAK]
|
||||||
EXPORT OTG_HS_EP1_IN_IRQHandler [WEAK]
|
EXPORT OTG_HS_EP1_IN_IRQHandler [WEAK]
|
||||||
EXPORT OTG_HS_WKUP_IRQHandler [WEAK]
|
EXPORT OTG_HS_WKUP_IRQHandler [WEAK]
|
||||||
EXPORT OTG_HS_IRQHandler [WEAK]
|
EXPORT OTG_HS_IRQHandler [WEAK]
|
||||||
EXPORT DCMI_IRQHandler [WEAK]
|
EXPORT DCMI_IRQHandler [WEAK]
|
||||||
EXPORT CRYP_IRQHandler [WEAK]
|
EXPORT CRYP_IRQHandler [WEAK]
|
||||||
EXPORT HASH_RNG_IRQHandler [WEAK]
|
EXPORT HASH_RNG_IRQHandler [WEAK]
|
||||||
EXPORT FPU_IRQHandler [WEAK]
|
EXPORT FPU_IRQHandler [WEAK]
|
||||||
|
|
||||||
WWDG_IRQHandler
|
WWDG_IRQHandler
|
||||||
PVD_IRQHandler
|
PVD_IRQHandler
|
||||||
TAMP_STAMP_IRQHandler
|
TAMP_STAMP_IRQHandler
|
||||||
RTC_WKUP_IRQHandler
|
RTC_WKUP_IRQHandler
|
||||||
FLASH_IRQHandler
|
FLASH_IRQHandler
|
||||||
RCC_IRQHandler
|
RCC_IRQHandler
|
||||||
EXTI0_IRQHandler
|
EXTI0_IRQHandler
|
||||||
EXTI1_IRQHandler
|
EXTI1_IRQHandler
|
||||||
EXTI2_IRQHandler
|
EXTI2_IRQHandler
|
||||||
EXTI3_IRQHandler
|
EXTI3_IRQHandler
|
||||||
EXTI4_IRQHandler
|
EXTI4_IRQHandler
|
||||||
DMA1_Stream0_IRQHandler
|
DMA1_Stream0_IRQHandler
|
||||||
DMA1_Stream1_IRQHandler
|
DMA1_Stream1_IRQHandler
|
||||||
DMA1_Stream2_IRQHandler
|
DMA1_Stream2_IRQHandler
|
||||||
DMA1_Stream3_IRQHandler
|
DMA1_Stream3_IRQHandler
|
||||||
DMA1_Stream4_IRQHandler
|
DMA1_Stream4_IRQHandler
|
||||||
DMA1_Stream5_IRQHandler
|
DMA1_Stream5_IRQHandler
|
||||||
DMA1_Stream6_IRQHandler
|
DMA1_Stream6_IRQHandler
|
||||||
ADC_IRQHandler
|
ADC_IRQHandler
|
||||||
CAN1_TX_IRQHandler
|
CAN1_TX_IRQHandler
|
||||||
CAN1_RX0_IRQHandler
|
CAN1_RX0_IRQHandler
|
||||||
CAN1_RX1_IRQHandler
|
CAN1_RX1_IRQHandler
|
||||||
CAN1_SCE_IRQHandler
|
CAN1_SCE_IRQHandler
|
||||||
EXTI9_5_IRQHandler
|
EXTI9_5_IRQHandler
|
||||||
TIM1_BRK_TIM9_IRQHandler
|
TIM1_BRK_TIM9_IRQHandler
|
||||||
TIM1_UP_TIM10_IRQHandler
|
TIM1_UP_TIM10_IRQHandler
|
||||||
TIM1_TRG_COM_TIM11_IRQHandler
|
TIM1_TRG_COM_TIM11_IRQHandler
|
||||||
TIM1_CC_IRQHandler
|
TIM1_CC_IRQHandler
|
||||||
TIM2_IRQHandler
|
TIM2_IRQHandler
|
||||||
TIM3_IRQHandler
|
TIM3_IRQHandler
|
||||||
TIM4_IRQHandler
|
TIM4_IRQHandler
|
||||||
I2C1_EV_IRQHandler
|
I2C1_EV_IRQHandler
|
||||||
I2C1_ER_IRQHandler
|
I2C1_ER_IRQHandler
|
||||||
I2C2_EV_IRQHandler
|
I2C2_EV_IRQHandler
|
||||||
I2C2_ER_IRQHandler
|
I2C2_ER_IRQHandler
|
||||||
SPI1_IRQHandler
|
SPI1_IRQHandler
|
||||||
SPI2_IRQHandler
|
SPI2_IRQHandler
|
||||||
USART1_IRQHandler
|
USART1_IRQHandler
|
||||||
USART2_IRQHandler
|
USART2_IRQHandler
|
||||||
USART3_IRQHandler
|
USART3_IRQHandler
|
||||||
EXTI15_10_IRQHandler
|
EXTI15_10_IRQHandler
|
||||||
RTC_Alarm_IRQHandler
|
RTC_Alarm_IRQHandler
|
||||||
OTG_FS_WKUP_IRQHandler
|
OTG_FS_WKUP_IRQHandler
|
||||||
TIM8_BRK_TIM12_IRQHandler
|
TIM8_BRK_TIM12_IRQHandler
|
||||||
TIM8_UP_TIM13_IRQHandler
|
TIM8_UP_TIM13_IRQHandler
|
||||||
TIM8_TRG_COM_TIM14_IRQHandler
|
TIM8_TRG_COM_TIM14_IRQHandler
|
||||||
TIM8_CC_IRQHandler
|
TIM8_CC_IRQHandler
|
||||||
DMA1_Stream7_IRQHandler
|
DMA1_Stream7_IRQHandler
|
||||||
FSMC_IRQHandler
|
FSMC_IRQHandler
|
||||||
SDIO_IRQHandler
|
SDIO_IRQHandler
|
||||||
TIM5_IRQHandler
|
TIM5_IRQHandler
|
||||||
SPI3_IRQHandler
|
SPI3_IRQHandler
|
||||||
UART4_IRQHandler
|
UART4_IRQHandler
|
||||||
UART5_IRQHandler
|
UART5_IRQHandler
|
||||||
TIM6_DAC_IRQHandler
|
TIM6_DAC_IRQHandler
|
||||||
TIM7_IRQHandler
|
TIM7_IRQHandler
|
||||||
DMA2_Stream0_IRQHandler
|
DMA2_Stream0_IRQHandler
|
||||||
DMA2_Stream1_IRQHandler
|
DMA2_Stream1_IRQHandler
|
||||||
DMA2_Stream2_IRQHandler
|
DMA2_Stream2_IRQHandler
|
||||||
DMA2_Stream3_IRQHandler
|
DMA2_Stream3_IRQHandler
|
||||||
DMA2_Stream4_IRQHandler
|
DMA2_Stream4_IRQHandler
|
||||||
ETH_IRQHandler
|
ETH_IRQHandler
|
||||||
ETH_WKUP_IRQHandler
|
ETH_WKUP_IRQHandler
|
||||||
CAN2_TX_IRQHandler
|
CAN2_TX_IRQHandler
|
||||||
CAN2_RX0_IRQHandler
|
CAN2_RX0_IRQHandler
|
||||||
CAN2_RX1_IRQHandler
|
CAN2_RX1_IRQHandler
|
||||||
CAN2_SCE_IRQHandler
|
CAN2_SCE_IRQHandler
|
||||||
OTG_FS_IRQHandler
|
OTG_FS_IRQHandler
|
||||||
DMA2_Stream5_IRQHandler
|
DMA2_Stream5_IRQHandler
|
||||||
DMA2_Stream6_IRQHandler
|
DMA2_Stream6_IRQHandler
|
||||||
DMA2_Stream7_IRQHandler
|
DMA2_Stream7_IRQHandler
|
||||||
USART6_IRQHandler
|
USART6_IRQHandler
|
||||||
I2C3_EV_IRQHandler
|
I2C3_EV_IRQHandler
|
||||||
I2C3_ER_IRQHandler
|
I2C3_ER_IRQHandler
|
||||||
OTG_HS_EP1_OUT_IRQHandler
|
OTG_HS_EP1_OUT_IRQHandler
|
||||||
OTG_HS_EP1_IN_IRQHandler
|
OTG_HS_EP1_IN_IRQHandler
|
||||||
OTG_HS_WKUP_IRQHandler
|
OTG_HS_WKUP_IRQHandler
|
||||||
OTG_HS_IRQHandler
|
OTG_HS_IRQHandler
|
||||||
DCMI_IRQHandler
|
DCMI_IRQHandler
|
||||||
CRYP_IRQHandler
|
CRYP_IRQHandler
|
||||||
HASH_RNG_IRQHandler
|
HASH_RNG_IRQHandler
|
||||||
FPU_IRQHandler
|
FPU_IRQHandler
|
||||||
|
|
||||||
B .
|
B .
|
||||||
|
|
||||||
ENDP
|
ENDP
|
||||||
|
|
||||||
ALIGN
|
ALIGN
|
||||||
|
|
||||||
;*******************************************************************************
|
;*******************************************************************************
|
||||||
; User Stack and Heap initialization
|
; User Stack and Heap initialization
|
||||||
;*******************************************************************************
|
;*******************************************************************************
|
||||||
IF :DEF:__MICROLIB
|
IF :DEF:__MICROLIB
|
||||||
|
|
||||||
EXPORT __initial_sp
|
EXPORT __initial_sp
|
||||||
EXPORT __heap_base
|
EXPORT __heap_base
|
||||||
EXPORT __heap_limit
|
EXPORT __heap_limit
|
||||||
|
|
||||||
ELSE
|
ELSE
|
||||||
|
|
||||||
IMPORT __use_two_region_memory
|
IMPORT __use_two_region_memory
|
||||||
EXPORT __user_initial_stackheap
|
EXPORT __user_initial_stackheap
|
||||||
|
|
||||||
__user_initial_stackheap
|
__user_initial_stackheap
|
||||||
|
|
||||||
LDR R0, = Heap_Mem
|
LDR R0, = Heap_Mem
|
||||||
LDR R1, =(Stack_Mem + Stack_Size)
|
LDR R1, =(Stack_Mem + Stack_Size)
|
||||||
LDR R2, = (Heap_Mem + Heap_Size)
|
LDR R2, = (Heap_Mem + Heap_Size)
|
||||||
LDR R3, = Stack_Mem
|
LDR R3, = Stack_Mem
|
||||||
BX LR
|
BX LR
|
||||||
|
|
||||||
ALIGN
|
ALIGN
|
||||||
|
|
||||||
ENDIF
|
ENDIF
|
||||||
|
|
||||||
END
|
END
|
||||||
|
|
||||||
;******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE*****
|
;******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE*****
|
@ -1,172 +1,172 @@
|
|||||||
/**
|
/**
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @file misc.h
|
* @file misc.h
|
||||||
* @author MCD Application Team
|
* @author MCD Application Team
|
||||||
* @version V1.0.0
|
* @version V1.0.0
|
||||||
* @date 30-September-2011
|
* @date 30-September-2011
|
||||||
* @brief This file contains all the functions prototypes for the miscellaneous
|
* @brief This file contains all the functions prototypes for the miscellaneous
|
||||||
* firmware library functions (add-on to CMSIS functions).
|
* firmware library functions (add-on to CMSIS functions).
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @attention
|
* @attention
|
||||||
*
|
*
|
||||||
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
||||||
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
||||||
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
||||||
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
||||||
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||||
*
|
*
|
||||||
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
|
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||||
#ifndef __MISC_H
|
#ifndef __MISC_H
|
||||||
#define __MISC_H
|
#define __MISC_H
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Includes ------------------------------------------------------------------*/
|
/* Includes ------------------------------------------------------------------*/
|
||||||
#include "stm32f4xx.h"
|
#include "stm32f4xx.h"
|
||||||
|
|
||||||
/** @addtogroup STM32F4xx_StdPeriph_Driver
|
/** @addtogroup STM32F4xx_StdPeriph_Driver
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @addtogroup MISC
|
/** @addtogroup MISC
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Exported types ------------------------------------------------------------*/
|
/* Exported types ------------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief NVIC Init Structure definition
|
* @brief NVIC Init Structure definition
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint8_t NVIC_IRQChannel; /*!< Specifies the IRQ channel to be enabled or disabled.
|
uint8_t NVIC_IRQChannel; /*!< Specifies the IRQ channel to be enabled or disabled.
|
||||||
This parameter can be an enumerator of @ref IRQn_Type
|
This parameter can be an enumerator of @ref IRQn_Type
|
||||||
enumeration (For the complete STM32 Devices IRQ Channels
|
enumeration (For the complete STM32 Devices IRQ Channels
|
||||||
list, please refer to stm32f4xx.h file) */
|
list, please refer to stm32f4xx.h file) */
|
||||||
|
|
||||||
uint8_t NVIC_IRQChannelPreemptionPriority; /*!< Specifies the pre-emption priority for the IRQ channel
|
uint8_t NVIC_IRQChannelPreemptionPriority; /*!< Specifies the pre-emption priority for the IRQ channel
|
||||||
specified in NVIC_IRQChannel. This parameter can be a value
|
specified in NVIC_IRQChannel. This parameter can be a value
|
||||||
between 0 and 15 as described in the table @ref MISC_NVIC_Priority_Table
|
between 0 and 15 as described in the table @ref MISC_NVIC_Priority_Table
|
||||||
A lower priority value indicates a higher priority */
|
A lower priority value indicates a higher priority */
|
||||||
|
|
||||||
uint8_t NVIC_IRQChannelSubPriority; /*!< Specifies the subpriority level for the IRQ channel specified
|
uint8_t NVIC_IRQChannelSubPriority; /*!< Specifies the subpriority level for the IRQ channel specified
|
||||||
in NVIC_IRQChannel. This parameter can be a value
|
in NVIC_IRQChannel. This parameter can be a value
|
||||||
between 0 and 15 as described in the table @ref MISC_NVIC_Priority_Table
|
between 0 and 15 as described in the table @ref MISC_NVIC_Priority_Table
|
||||||
A lower priority value indicates a higher priority */
|
A lower priority value indicates a higher priority */
|
||||||
|
|
||||||
FunctionalState NVIC_IRQChannelCmd; /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannel
|
FunctionalState NVIC_IRQChannelCmd; /*!< Specifies whether the IRQ channel defined in NVIC_IRQChannel
|
||||||
will be enabled or disabled.
|
will be enabled or disabled.
|
||||||
This parameter can be set either to ENABLE or DISABLE */
|
This parameter can be set either to ENABLE or DISABLE */
|
||||||
} NVIC_InitTypeDef;
|
} NVIC_InitTypeDef;
|
||||||
|
|
||||||
/* Exported constants --------------------------------------------------------*/
|
/* Exported constants --------------------------------------------------------*/
|
||||||
|
|
||||||
/** @defgroup MISC_Exported_Constants
|
/** @defgroup MISC_Exported_Constants
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @defgroup MISC_Vector_Table_Base
|
/** @defgroup MISC_Vector_Table_Base
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define NVIC_VectTab_RAM ((uint32_t)0x20000000)
|
#define NVIC_VectTab_RAM ((uint32_t)0x20000000)
|
||||||
#define NVIC_VectTab_FLASH ((uint32_t)0x08000000)
|
#define NVIC_VectTab_FLASH ((uint32_t)0x08000000)
|
||||||
#define IS_NVIC_VECTTAB(VECTTAB) (((VECTTAB) == NVIC_VectTab_RAM) || \
|
#define IS_NVIC_VECTTAB(VECTTAB) (((VECTTAB) == NVIC_VectTab_RAM) || \
|
||||||
((VECTTAB) == NVIC_VectTab_FLASH))
|
((VECTTAB) == NVIC_VectTab_FLASH))
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @defgroup MISC_System_Low_Power
|
/** @defgroup MISC_System_Low_Power
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define NVIC_LP_SEVONPEND ((uint8_t)0x10)
|
#define NVIC_LP_SEVONPEND ((uint8_t)0x10)
|
||||||
#define NVIC_LP_SLEEPDEEP ((uint8_t)0x04)
|
#define NVIC_LP_SLEEPDEEP ((uint8_t)0x04)
|
||||||
#define NVIC_LP_SLEEPONEXIT ((uint8_t)0x02)
|
#define NVIC_LP_SLEEPONEXIT ((uint8_t)0x02)
|
||||||
#define IS_NVIC_LP(LP) (((LP) == NVIC_LP_SEVONPEND) || \
|
#define IS_NVIC_LP(LP) (((LP) == NVIC_LP_SEVONPEND) || \
|
||||||
((LP) == NVIC_LP_SLEEPDEEP) || \
|
((LP) == NVIC_LP_SLEEPDEEP) || \
|
||||||
((LP) == NVIC_LP_SLEEPONEXIT))
|
((LP) == NVIC_LP_SLEEPONEXIT))
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @defgroup MISC_Preemption_Priority_Group
|
/** @defgroup MISC_Preemption_Priority_Group
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define NVIC_PriorityGroup_0 ((uint32_t)0x700) /*!< 0 bits for pre-emption priority
|
#define NVIC_PriorityGroup_0 ((uint32_t)0x700) /*!< 0 bits for pre-emption priority
|
||||||
4 bits for subpriority */
|
4 bits for subpriority */
|
||||||
#define NVIC_PriorityGroup_1 ((uint32_t)0x600) /*!< 1 bits for pre-emption priority
|
#define NVIC_PriorityGroup_1 ((uint32_t)0x600) /*!< 1 bits for pre-emption priority
|
||||||
3 bits for subpriority */
|
3 bits for subpriority */
|
||||||
#define NVIC_PriorityGroup_2 ((uint32_t)0x500) /*!< 2 bits for pre-emption priority
|
#define NVIC_PriorityGroup_2 ((uint32_t)0x500) /*!< 2 bits for pre-emption priority
|
||||||
2 bits for subpriority */
|
2 bits for subpriority */
|
||||||
#define NVIC_PriorityGroup_3 ((uint32_t)0x400) /*!< 3 bits for pre-emption priority
|
#define NVIC_PriorityGroup_3 ((uint32_t)0x400) /*!< 3 bits for pre-emption priority
|
||||||
1 bits for subpriority */
|
1 bits for subpriority */
|
||||||
#define NVIC_PriorityGroup_4 ((uint32_t)0x300) /*!< 4 bits for pre-emption priority
|
#define NVIC_PriorityGroup_4 ((uint32_t)0x300) /*!< 4 bits for pre-emption priority
|
||||||
0 bits for subpriority */
|
0 bits for subpriority */
|
||||||
|
|
||||||
#define IS_NVIC_PRIORITY_GROUP(GROUP) (((GROUP) == NVIC_PriorityGroup_0) || \
|
#define IS_NVIC_PRIORITY_GROUP(GROUP) (((GROUP) == NVIC_PriorityGroup_0) || \
|
||||||
((GROUP) == NVIC_PriorityGroup_1) || \
|
((GROUP) == NVIC_PriorityGroup_1) || \
|
||||||
((GROUP) == NVIC_PriorityGroup_2) || \
|
((GROUP) == NVIC_PriorityGroup_2) || \
|
||||||
((GROUP) == NVIC_PriorityGroup_3) || \
|
((GROUP) == NVIC_PriorityGroup_3) || \
|
||||||
((GROUP) == NVIC_PriorityGroup_4))
|
((GROUP) == NVIC_PriorityGroup_4))
|
||||||
|
|
||||||
#define IS_NVIC_PREEMPTION_PRIORITY(PRIORITY) ((PRIORITY) < 0x10)
|
#define IS_NVIC_PREEMPTION_PRIORITY(PRIORITY) ((PRIORITY) < 0x10)
|
||||||
|
|
||||||
#define IS_NVIC_SUB_PRIORITY(PRIORITY) ((PRIORITY) < 0x10)
|
#define IS_NVIC_SUB_PRIORITY(PRIORITY) ((PRIORITY) < 0x10)
|
||||||
|
|
||||||
#define IS_NVIC_OFFSET(OFFSET) ((OFFSET) < 0x000FFFFF)
|
#define IS_NVIC_OFFSET(OFFSET) ((OFFSET) < 0x000FFFFF)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @defgroup MISC_SysTick_clock_source
|
/** @defgroup MISC_SysTick_clock_source
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define SysTick_CLKSource_HCLK_Div8 ((uint32_t)0xFFFFFFFB)
|
#define SysTick_CLKSource_HCLK_Div8 ((uint32_t)0xFFFFFFFB)
|
||||||
#define SysTick_CLKSource_HCLK ((uint32_t)0x00000004)
|
#define SysTick_CLKSource_HCLK ((uint32_t)0x00000004)
|
||||||
#define IS_SYSTICK_CLK_SOURCE(SOURCE) (((SOURCE) == SysTick_CLKSource_HCLK) || \
|
#define IS_SYSTICK_CLK_SOURCE(SOURCE) (((SOURCE) == SysTick_CLKSource_HCLK) || \
|
||||||
((SOURCE) == SysTick_CLKSource_HCLK_Div8))
|
((SOURCE) == SysTick_CLKSource_HCLK_Div8))
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Exported macro ------------------------------------------------------------*/
|
/* Exported macro ------------------------------------------------------------*/
|
||||||
/* Exported functions --------------------------------------------------------*/
|
/* Exported functions --------------------------------------------------------*/
|
||||||
|
|
||||||
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
|
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
|
||||||
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
|
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
|
||||||
void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset);
|
void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset);
|
||||||
void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);
|
void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);
|
||||||
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource);
|
void SysTick_CLKSourceConfig(uint32_t SysTick_CLKSource);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __MISC_H */
|
#endif /* __MISC_H */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
|
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
|
@ -1,177 +1,177 @@
|
|||||||
/**
|
/**
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @file stm32f4xx_exti.h
|
* @file stm32f4xx_exti.h
|
||||||
* @author MCD Application Team
|
* @author MCD Application Team
|
||||||
* @version V1.0.0
|
* @version V1.0.0
|
||||||
* @date 30-September-2011
|
* @date 30-September-2011
|
||||||
* @brief This file contains all the functions prototypes for the EXTI firmware
|
* @brief This file contains all the functions prototypes for the EXTI firmware
|
||||||
* library.
|
* library.
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
* @attention
|
* @attention
|
||||||
*
|
*
|
||||||
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
|
||||||
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
|
||||||
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
|
||||||
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
|
||||||
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
|
||||||
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
|
||||||
*
|
*
|
||||||
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
|
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
|
||||||
******************************************************************************
|
******************************************************************************
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Define to prevent recursive inclusion -------------------------------------*/
|
/* Define to prevent recursive inclusion -------------------------------------*/
|
||||||
#ifndef __STM32F4xx_EXTI_H
|
#ifndef __STM32F4xx_EXTI_H
|
||||||
#define __STM32F4xx_EXTI_H
|
#define __STM32F4xx_EXTI_H
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Includes ------------------------------------------------------------------*/
|
/* Includes ------------------------------------------------------------------*/
|
||||||
#include "stm32f4xx.h"
|
#include "stm32f4xx.h"
|
||||||
|
|
||||||
/** @addtogroup STM32F4xx_StdPeriph_Driver
|
/** @addtogroup STM32F4xx_StdPeriph_Driver
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @addtogroup EXTI
|
/** @addtogroup EXTI
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Exported types ------------------------------------------------------------*/
|
/* Exported types ------------------------------------------------------------*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief EXTI mode enumeration
|
* @brief EXTI mode enumeration
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
EXTI_Mode_Interrupt = 0x00,
|
EXTI_Mode_Interrupt = 0x00,
|
||||||
EXTI_Mode_Event = 0x04
|
EXTI_Mode_Event = 0x04
|
||||||
}EXTIMode_TypeDef;
|
}EXTIMode_TypeDef;
|
||||||
|
|
||||||
#define IS_EXTI_MODE(MODE) (((MODE) == EXTI_Mode_Interrupt) || ((MODE) == EXTI_Mode_Event))
|
#define IS_EXTI_MODE(MODE) (((MODE) == EXTI_Mode_Interrupt) || ((MODE) == EXTI_Mode_Event))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief EXTI Trigger enumeration
|
* @brief EXTI Trigger enumeration
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
{
|
{
|
||||||
EXTI_Trigger_Rising = 0x08,
|
EXTI_Trigger_Rising = 0x08,
|
||||||
EXTI_Trigger_Falling = 0x0C,
|
EXTI_Trigger_Falling = 0x0C,
|
||||||
EXTI_Trigger_Rising_Falling = 0x10
|
EXTI_Trigger_Rising_Falling = 0x10
|
||||||
}EXTITrigger_TypeDef;
|
}EXTITrigger_TypeDef;
|
||||||
|
|
||||||
#define IS_EXTI_TRIGGER(TRIGGER) (((TRIGGER) == EXTI_Trigger_Rising) || \
|
#define IS_EXTI_TRIGGER(TRIGGER) (((TRIGGER) == EXTI_Trigger_Rising) || \
|
||||||
((TRIGGER) == EXTI_Trigger_Falling) || \
|
((TRIGGER) == EXTI_Trigger_Falling) || \
|
||||||
((TRIGGER) == EXTI_Trigger_Rising_Falling))
|
((TRIGGER) == EXTI_Trigger_Rising_Falling))
|
||||||
/**
|
/**
|
||||||
* @brief EXTI Init Structure definition
|
* @brief EXTI Init Structure definition
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
{
|
{
|
||||||
uint32_t EXTI_Line; /*!< Specifies the EXTI lines to be enabled or disabled.
|
uint32_t EXTI_Line; /*!< Specifies the EXTI lines to be enabled or disabled.
|
||||||
This parameter can be any combination value of @ref EXTI_Lines */
|
This parameter can be any combination value of @ref EXTI_Lines */
|
||||||
|
|
||||||
EXTIMode_TypeDef EXTI_Mode; /*!< Specifies the mode for the EXTI lines.
|
EXTIMode_TypeDef EXTI_Mode; /*!< Specifies the mode for the EXTI lines.
|
||||||
This parameter can be a value of @ref EXTIMode_TypeDef */
|
This parameter can be a value of @ref EXTIMode_TypeDef */
|
||||||
|
|
||||||
EXTITrigger_TypeDef EXTI_Trigger; /*!< Specifies the trigger signal active edge for the EXTI lines.
|
EXTITrigger_TypeDef EXTI_Trigger; /*!< Specifies the trigger signal active edge for the EXTI lines.
|
||||||
This parameter can be a value of @ref EXTITrigger_TypeDef */
|
This parameter can be a value of @ref EXTITrigger_TypeDef */
|
||||||
|
|
||||||
FunctionalState EXTI_LineCmd; /*!< Specifies the new state of the selected EXTI lines.
|
FunctionalState EXTI_LineCmd; /*!< Specifies the new state of the selected EXTI lines.
|
||||||
This parameter can be set either to ENABLE or DISABLE */
|
This parameter can be set either to ENABLE or DISABLE */
|
||||||
}EXTI_InitTypeDef;
|
}EXTI_InitTypeDef;
|
||||||
|
|
||||||
/* Exported constants --------------------------------------------------------*/
|
/* Exported constants --------------------------------------------------------*/
|
||||||
|
|
||||||
/** @defgroup EXTI_Exported_Constants
|
/** @defgroup EXTI_Exported_Constants
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @defgroup EXTI_Lines
|
/** @defgroup EXTI_Lines
|
||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define EXTI_Line0 ((uint32_t)0x00001) /*!< External interrupt line 0 */
|
#define EXTI_Line0 ((uint32_t)0x00001) /*!< External interrupt line 0 */
|
||||||
#define EXTI_Line1 ((uint32_t)0x00002) /*!< External interrupt line 1 */
|
#define EXTI_Line1 ((uint32_t)0x00002) /*!< External interrupt line 1 */
|
||||||
#define EXTI_Line2 ((uint32_t)0x00004) /*!< External interrupt line 2 */
|
#define EXTI_Line2 ((uint32_t)0x00004) /*!< External interrupt line 2 */
|
||||||
#define EXTI_Line3 ((uint32_t)0x00008) /*!< External interrupt line 3 */
|
#define EXTI_Line3 ((uint32_t)0x00008) /*!< External interrupt line 3 */
|
||||||
#define EXTI_Line4 ((uint32_t)0x00010) /*!< External interrupt line 4 */
|
#define EXTI_Line4 ((uint32_t)0x00010) /*!< External interrupt line 4 */
|
||||||
#define EXTI_Line5 ((uint32_t)0x00020) /*!< External interrupt line 5 */
|
#define EXTI_Line5 ((uint32_t)0x00020) /*!< External interrupt line 5 */
|
||||||
#define EXTI_Line6 ((uint32_t)0x00040) /*!< External interrupt line 6 */
|
#define EXTI_Line6 ((uint32_t)0x00040) /*!< External interrupt line 6 */
|
||||||
#define EXTI_Line7 ((uint32_t)0x00080) /*!< External interrupt line 7 */
|
#define EXTI_Line7 ((uint32_t)0x00080) /*!< External interrupt line 7 */
|
||||||
#define EXTI_Line8 ((uint32_t)0x00100) /*!< External interrupt line 8 */
|
#define EXTI_Line8 ((uint32_t)0x00100) /*!< External interrupt line 8 */
|
||||||
#define EXTI_Line9 ((uint32_t)0x00200) /*!< External interrupt line 9 */
|
#define EXTI_Line9 ((uint32_t)0x00200) /*!< External interrupt line 9 */
|
||||||
#define EXTI_Line10 ((uint32_t)0x00400) /*!< External interrupt line 10 */
|
#define EXTI_Line10 ((uint32_t)0x00400) /*!< External interrupt line 10 */
|
||||||
#define EXTI_Line11 ((uint32_t)0x00800) /*!< External interrupt line 11 */
|
#define EXTI_Line11 ((uint32_t)0x00800) /*!< External interrupt line 11 */
|
||||||
#define EXTI_Line12 ((uint32_t)0x01000) /*!< External interrupt line 12 */
|
#define EXTI_Line12 ((uint32_t)0x01000) /*!< External interrupt line 12 */
|
||||||
#define EXTI_Line13 ((uint32_t)0x02000) /*!< External interrupt line 13 */
|
#define EXTI_Line13 ((uint32_t)0x02000) /*!< External interrupt line 13 */
|
||||||
#define EXTI_Line14 ((uint32_t)0x04000) /*!< External interrupt line 14 */
|
#define EXTI_Line14 ((uint32_t)0x04000) /*!< External interrupt line 14 */
|
||||||
#define EXTI_Line15 ((uint32_t)0x08000) /*!< External interrupt line 15 */
|
#define EXTI_Line15 ((uint32_t)0x08000) /*!< External interrupt line 15 */
|
||||||
#define EXTI_Line16 ((uint32_t)0x10000) /*!< External interrupt line 16 Connected to the PVD Output */
|
#define EXTI_Line16 ((uint32_t)0x10000) /*!< External interrupt line 16 Connected to the PVD Output */
|
||||||
#define EXTI_Line17 ((uint32_t)0x20000) /*!< External interrupt line 17 Connected to the RTC Alarm event */
|
#define EXTI_Line17 ((uint32_t)0x20000) /*!< External interrupt line 17 Connected to the RTC Alarm event */
|
||||||
#define EXTI_Line18 ((uint32_t)0x40000) /*!< External interrupt line 18 Connected to the USB OTG FS Wakeup from suspend event */
|
#define EXTI_Line18 ((uint32_t)0x40000) /*!< External interrupt line 18 Connected to the USB OTG FS Wakeup from suspend event */
|
||||||
#define EXTI_Line19 ((uint32_t)0x80000) /*!< External interrupt line 19 Connected to the Ethernet Wakeup event */
|
#define EXTI_Line19 ((uint32_t)0x80000) /*!< External interrupt line 19 Connected to the Ethernet Wakeup event */
|
||||||
#define EXTI_Line20 ((uint32_t)0x00100000) /*!< External interrupt line 20 Connected to the USB OTG HS (configured in FS) Wakeup event */
|
#define EXTI_Line20 ((uint32_t)0x00100000) /*!< External interrupt line 20 Connected to the USB OTG HS (configured in FS) Wakeup event */
|
||||||
#define EXTI_Line21 ((uint32_t)0x00200000) /*!< External interrupt line 21 Connected to the RTC Tamper and Time Stamp events */
|
#define EXTI_Line21 ((uint32_t)0x00200000) /*!< External interrupt line 21 Connected to the RTC Tamper and Time Stamp events */
|
||||||
#define EXTI_Line22 ((uint32_t)0x00400000) /*!< External interrupt line 22 Connected to the RTC Wakeup event */
|
#define EXTI_Line22 ((uint32_t)0x00400000) /*!< External interrupt line 22 Connected to the RTC Wakeup event */
|
||||||
|
|
||||||
#define IS_EXTI_LINE(LINE) ((((LINE) & (uint32_t)0xFF800000) == 0x00) && ((LINE) != (uint16_t)0x00))
|
#define IS_EXTI_LINE(LINE) ((((LINE) & (uint32_t)0xFF800000) == 0x00) && ((LINE) != (uint16_t)0x00))
|
||||||
|
|
||||||
#define IS_GET_EXTI_LINE(LINE) (((LINE) == EXTI_Line0) || ((LINE) == EXTI_Line1) || \
|
#define IS_GET_EXTI_LINE(LINE) (((LINE) == EXTI_Line0) || ((LINE) == EXTI_Line1) || \
|
||||||
((LINE) == EXTI_Line2) || ((LINE) == EXTI_Line3) || \
|
((LINE) == EXTI_Line2) || ((LINE) == EXTI_Line3) || \
|
||||||
((LINE) == EXTI_Line4) || ((LINE) == EXTI_Line5) || \
|
((LINE) == EXTI_Line4) || ((LINE) == EXTI_Line5) || \
|
||||||
((LINE) == EXTI_Line6) || ((LINE) == EXTI_Line7) || \
|
((LINE) == EXTI_Line6) || ((LINE) == EXTI_Line7) || \
|
||||||
((LINE) == EXTI_Line8) || ((LINE) == EXTI_Line9) || \
|
((LINE) == EXTI_Line8) || ((LINE) == EXTI_Line9) || \
|
||||||
((LINE) == EXTI_Line10) || ((LINE) == EXTI_Line11) || \
|
((LINE) == EXTI_Line10) || ((LINE) == EXTI_Line11) || \
|
||||||
((LINE) == EXTI_Line12) || ((LINE) == EXTI_Line13) || \
|
((LINE) == EXTI_Line12) || ((LINE) == EXTI_Line13) || \
|
||||||
((LINE) == EXTI_Line14) || ((LINE) == EXTI_Line15) || \
|
((LINE) == EXTI_Line14) || ((LINE) == EXTI_Line15) || \
|
||||||
((LINE) == EXTI_Line16) || ((LINE) == EXTI_Line17) || \
|
((LINE) == EXTI_Line16) || ((LINE) == EXTI_Line17) || \
|
||||||
((LINE) == EXTI_Line18) || ((LINE) == EXTI_Line19) || \
|
((LINE) == EXTI_Line18) || ((LINE) == EXTI_Line19) || \
|
||||||
((LINE) == EXTI_Line20) || ((LINE) == EXTI_Line21) ||\
|
((LINE) == EXTI_Line20) || ((LINE) == EXTI_Line21) ||\
|
||||||
((LINE) == EXTI_Line22))
|
((LINE) == EXTI_Line22))
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* Exported macro ------------------------------------------------------------*/
|
/* Exported macro ------------------------------------------------------------*/
|
||||||
/* Exported functions --------------------------------------------------------*/
|
/* Exported functions --------------------------------------------------------*/
|
||||||
|
|
||||||
/* Function used to set the EXTI configuration to the default reset state *****/
|
/* Function used to set the EXTI configuration to the default reset state *****/
|
||||||
void EXTI_DeInit(void);
|
void EXTI_DeInit(void);
|
||||||
|
|
||||||
/* Initialization and Configuration functions *********************************/
|
/* Initialization and Configuration functions *********************************/
|
||||||
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
|
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
|
||||||
void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);
|
void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);
|
||||||
void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);
|
void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);
|
||||||
|
|
||||||
/* Interrupts and flags management functions **********************************/
|
/* Interrupts and flags management functions **********************************/
|
||||||
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);
|
FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);
|
||||||
void EXTI_ClearFlag(uint32_t EXTI_Line);
|
void EXTI_ClearFlag(uint32_t EXTI_Line);
|
||||||
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
|
ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
|
||||||
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
|
void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif /* __STM32F4xx_EXTI_H */
|
#endif /* __STM32F4xx_EXTI_H */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
|
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
|