amobbs.com 阿莫电子技术论坛

标题: 也发一个AT解析引擎源码【Yet Another AT Engine】 [打印本页]

作者: armstrong    时间: 2019-12-10 11:30
标题: 也发一个AT解析引擎源码【Yet Another AT Engine】
本帖最后由 armstrong 于 2019-12-10 18:01 编辑

坛友之前发过一个AT解析代码,不是很全;而且不能很好的解析传入的参数,我发一个很好用的:
[attach]490833[/attach]
atengine.h
  1. /*
  2.   这是作者声明信息:反正源码给你了,随便你怎么改!
  3.   作者: 洪旭耀
  4.   Q  Q: 26750452
  5. */
  6. #ifndef __AT_ENGINE_H__
  7. #define __AT_ENGINE_H__

  8. ////////////////////////////////////////////////////////////////////////////////
  9. #ifdef __cplusplus
  10. extern "C"  {
  11. #endif

  12. void ATE_Exec(void);


  13. /* 以下函数需要移植代码来完成适配 */
  14. void ATE__ConsolePurgeRx(void);     // 清空接收缓冲区
  15. int  ATE__ConsoleRead(void);        // 从接收缓冲区读取一个字节,返回-1表示EOF
  16. void ATE__ConsoleWrite(char const* p, unsigned num);  // 发送一串数据到AT输出接口
  17. void ATE__ConsoleFlushTx(void);     // 确保发送缓冲区已空
  18. void ATE__PostInvoke(void (*pf)(void*), void* arg);

  19. #ifdef __cplusplus
  20. }
  21. #endif
  22. ////////////////////////////////////////////////////////////////////////////////
  23. #endif /* __AT_ENGINE_H__ */
复制代码


atengine.c
  1. /*
  2.   这是作者声明信息:反正源码给你了,随便你怎么改!
  3.   作者: 洪旭耀
  4.   Q  Q: 26750452
  5. */
  6. #include "atengine.h"
  7. #define JSMN_STATIC
  8. #define JSMN_STRICT
  9. #include "jsmn.h"
  10. #include <stdarg.h>

  11. ////////////////////////////////////////////////////////////////////////////////
  12. #ifndef CRLF
  13. #define CRLF "\r\n"
  14. #endif

  15. enum {
  16.   ATE_ERR_NONE = 0,
  17.   ATE_ERR_OOM,    /* Out Of Memory */
  18.   ATE_ERR_BADCMD, /* Bad Command */
  19.   ATE_ERR_BADARG, /* Bad Argument */

  20. };

  21. typedef struct {
  22.   void (*handler)(int argc, char const* argv[]);
  23.   char const* name;
  24. } ATCmdItem;

  25. static struct {
  26.   unsigned atCmdInd;
  27.   char atCmdLine[128];
  28.   jsmntok_t tokens[16];
  29.   char const* arglist[16];
  30.   __IO bool_t echoEnable;
  31.   __IO uint8_t errorCode;
  32. } cobj = {
  33.   .echoEnable = 1,
  34. };

  35. static void ATE_Echo(int c);
  36. static void ATE_SendResult(void);
  37. static void ATE_ExecuteCommand(void);
  38. static void ATE_SendString(char const s[]);
  39. static void ATE_SendStringFormat(char const* fmt, ...);
  40. static void ATE_ParseCommand(char cl[]);
  41. static bool_t FTK_IsHeadOfString(char const* strMain, char const* strSub);
  42. static bool_t FTK_IsHeadOfStringEx(char const* strMain, char const* strSub, int* pLen);
  43. ////////////////////////////////////////////////////////////////////////////////
  44. //|          |
  45. //| 函数名称 |: ATE_Exec
  46. //| 功能描述 |: 执行ATE输入,如果收到CRLF就解析并执行
  47. //|          |:
  48. //| 参数列表 |:
  49. //|          |:
  50. //| 返    回 |:
  51. //|          |:
  52. //| 备注信息 |:
  53. //|          |:
  54. ////////////////////////////////////////////////////////////////////////////////
  55. void ATE_Exec(void)
  56. {
  57.   unsigned i;
  58.   int ch;

  59.   while ((ch = ATE__ConsoleRead()) > 0) {
  60.     cobj.atCmdLine[cobj.atCmdInd++] = ch;
  61.     ATE_Echo(ch);
  62.     if (cobj.atCmdInd < 2) {
  63.       continue;
  64.     }
  65.     i = cobj.atCmdInd;
  66.     if (cobj.atCmdLine[i - 2] == '\r' && cobj.atCmdLine[i - 1] == '\n') {
  67.       // 收到AT命令结束符CRLF
  68.       if (cobj.errorCode == ATE_ERR_NONE) {
  69.         /*
  70.         把CRLF都修改为0,很重要!
  71.         因为后续代码里会利用这个 */
  72.         cobj.atCmdLine[i - 2] = 0;
  73.         cobj.atCmdLine[i - 1] = 0;
  74.         ATE_ExecuteCommand();
  75.       }
  76.       ATE_SendResult();
  77.       ATE__ConsolePurgeRx();
  78.       cobj.errorCode = ATE_ERR_NONE;
  79.       cobj.atCmdInd = 0;
  80.       return;
  81.     } else if (i == sizeof(cobj.atCmdLine)) {
  82.       // AT命令缓冲区已满却还没遇到CRLF,记录错误!
  83.       cobj.errorCode = ATE_ERR_OOM;
  84.       cobj.atCmdInd = 0;
  85.       continue;
  86.     }
  87.   }
  88. }

  89. static void ATE_SendString(char const s[])
  90. {
  91.   size_t len = strlen(s);
  92.   ATE__ConsoleFlushTx();
  93.   ATE__ConsoleWrite(s, len);
  94. }

  95. static void ATE_SendStringFormat(char const* fmt, ...)
  96. {
  97.   static char sbuffer[128];
  98.   va_list arp;
  99.   int len;

  100.   ATE__ConsoleFlushTx();
  101.   va_start(arp, fmt);
  102.   len = vsnprintf(sbuffer, sizeof(sbuffer) - 1, fmt, arp);
  103.   va_end(arp);
  104.   if (len > 0) {
  105.     ATE__ConsoleWrite(sbuffer, len);
  106.   }
  107. }

  108. static void ATE_Echo(int c)
  109. {
  110.   static char cbuf[2];
  111.   if (cobj.echoEnable) {
  112.     cbuf[0] = c;
  113.     ATE__ConsoleFlushTx();
  114.     ATE__ConsoleWrite(cbuf, 1);
  115.   }
  116. }

  117. static void ATE_SendResult(void)
  118. {
  119.   if (cobj.errorCode == ATE_ERR_NONE) {
  120.     ATE_SendString("OK"CRLF);
  121.   } else {
  122.     ATE_SendString("ERROR"CRLF);
  123.   }
  124. }

  125. static void ATE_ExecuteCommand(void)
  126. {
  127.   char* pCmdLine = cobj.atCmdLine;
  128.   if (FTK_IsHeadOfString(pCmdLine, "AT+")) {
  129.     pCmdLine += 3;
  130.     ATE_ParseCommand(pCmdLine);
  131.   } else if (!strcmp(pCmdLine, "ATE1")) {
  132.     cobj.echoEnable = TRUE;
  133.   } else if (!strcmp(pCmdLine, "ATE0")) {
  134.     cobj.echoEnable = FALSE;
  135.   } else if (!strcmp(pCmdLine, "AT")) {
  136.   } else {
  137.     cobj.errorCode = ATE_ERR_BADCMD;
  138.   }
  139. }

  140. bool_t FTK_IsHeadOfString(char const* strMain, char const* strSub)
  141. {
  142.   return FTK_IsHeadOfStringEx(strMain, strSub, NULL);
  143. }

  144. bool_t FTK_IsHeadOfStringEx(char const* strMain, char const* strSub, int* pLen)
  145. {
  146.   unsigned i;
  147.   for (i = 0; strSub[i]; i++) {
  148.     if (strMain[i] != strSub[i]) {
  149.       return false;
  150.     }
  151.   }
  152.   if (pLen) {
  153.     *pLen = i;
  154.   }
  155.   return true;
  156. }


  157. ////////////////////////////////////////////////////////////////////////////////
  158. #define DECL_ATCMD(nam) static void ATE_CMD_##nam(int argc, char const* argv[])
  159. #define REG_ATCMD(nam)  { .name = #nam, .handler = ATE_CMD_##nam }
  160. ////////////////////////////////////////////////////////////////////////////////
  161. DECL_ATCMD(HELLO);
  162. static ATCmdItem const atCmdLst[] = {
  163.   REG_ATCMD(HELLO),
  164.   {}
  165. };

  166. static void ATE_ParseCommand(char cl[])
  167. {
  168.   static char arg0[2] = "=";
  169.   ATCmdItem const* cmd;
  170.   jsmn_parser parser;
  171.   jsmntok_t* tok;
  172.   int len;

  173.   for (cmd = atCmdLst; cmd->handler; cmd++) {
  174.     if (FTK_IsHeadOfStringEx(cl, cmd->name, &len)) {
  175.       cl += len;
  176.       if (cl[0] == '\0' || cl[0] == '?') {
  177.         cobj.arglist[0] = cl;
  178.         cmd->handler(1, cobj.arglist);
  179.         return;
  180.       } else if (cl[0] == '=') {
  181.         len = strlen(cl);
  182.         cl[0] = '[';
  183.         cl[len++] = ']';
  184.         jsmn_init(&parser);
  185.         len = jsmn_parse(&parser, cl, len, cobj.tokens, COUNTOF(cobj.tokens));
  186.         if (len <= 0) {
  187.           // 参数解析失败,返回错误!
  188.           cobj.errorCode = ATE_ERR_BADARG;
  189.           return;
  190.         } else {
  191.           cobj.arglist[0] = arg0;
  192.           for (int i = 1; i < len; i++) {
  193.             tok = &cobj.tokens[i];
  194.             cobj.arglist[i] = cl + tok->start;
  195.             cl[tok->end] = 0;
  196.           }
  197.           cmd->handler(len, cobj.arglist);
  198.         }
  199.         return;
  200.       }
  201.     }
  202.   }
  203.   cobj.errorCode = ATE_ERR_BADCMD;
  204. }

  205. DECL_ATCMD(HELLO)
  206. {
  207.   ATE_SendString("The ArgList:"CRLF);
  208.   for (int i = 0; i < argc; i++) {
  209.     ATE_SendStringFormat("[%2u]: %s"CRLF, i, argv[i]);
  210.   }
  211. }


  212. ////////////////////////////////////////////////////////////////////////////////

复制代码


[attach]490834[/attach]

Win32 Console 演示,串口输入输出适配接口也可参考里面的代码:
[attach]490837[/attach]

编辑理由:更新了代码。
作者: armstrong    时间: 2019-12-10 11:33
本帖最后由 armstrong 于 2019-12-10 12:16 编辑

添加AT命令的方式很简单,参考atengine.c文件下部的代码,比如加入XXX命令就如下:

  1. DECL_ATCMD(HELLO);
  2. DECL_ATCMD(XXX);
  3. static ATCmdItem const atCmdLst[] = {
  4.   REG_ATCMD(HELLO),
  5.   REG_ATCMD(XXX),
  6.   {}
  7. };

  8. DECL_ATCMD(HELLO)
  9. {
  10.   ATE_SendString("The ArgList:"CRLF);
  11.   for (int i = 0; i < argc; i++) {
  12.     ATE_SendStringFormat("[%2u]: %s"CRLF, i, argv[i]);
  13.   }
  14. }

  15. DECL_ATCMD(XXX)
  16. {
  17.   // TODO...
  18. }
复制代码


可能需要你定义的几个宏和类型:
  1. #ifndef __IO
  2. #define __IO volatile
  3. #endif

  4. #ifndef TRUE
  5. #define TRUE 1
  6. #endif

  7. #ifndef FALSE
  8. #define FALSE 0
  9. #endif

  10. #define true TRUE
  11. #define false FALSE

  12. #define COUNTOF(ar) (sizeof(ar)/sizeof(ar[0]))

  13. typedef uint8_t bool_t;
复制代码


作者: anjiyifan    时间: 2019-12-10 12:03
不错!下载下来仔细看看。
作者: armstrong    时间: 2019-12-10 12:10
anjiyifan 发表于 2019-12-10 12:03
不错!下载下来仔细看看。

传了个win32命令行的演示【yatengine-win32.zip】,里面有串口收发接口适配的代码,可供参考。

作者: armstrong    时间: 2019-12-10 12:25
yatengine-win32.zip演示效果:
[attach]490839[/attach]
作者: jiaowoxiaolu    时间: 2019-12-10 13:29
看起来不错
作者: easier    时间: 2019-12-10 14:01
看起来不错 ; Mark
作者: lnskngdc    时间: 2019-12-10 14:44
早想做at指令配置参数了,哈哈
作者: yanyanyan168    时间: 2019-12-10 15:22
Mark,备用,多谢分享

作者: Mrp_Young    时间: 2019-12-10 15:43
MARK,肯定会用到
作者: armstrong    时间: 2019-12-10 15:47
这是我刚刚用yatengine做的“红外学习播放模块”命令,使用很方便:
[attach]490877[/attach]
作者: armstrong    时间: 2019-12-10 17:51
稍微改了一下win32演示,让ATE__ConsoleWrite函数调用fwrite输出,这样才可以输出非字符数据,这才是ATE__ConsoleWrite定义num参数的初衷。
[attach]490881[/attach]
  1. void ATE__ConsolePurgeRx(void)
  2. {
  3.   // Nothing todo on win32
  4. }
  5. int  ATE__ConsoleRead(void)
  6. {
  7.   // win32 console 回车键是'\n',
  8.   // 以下逻辑为了在'\n'之前插入'\r'
  9.   static int bak = 0;
  10.   if (bak) {
  11.     int r = bak;
  12.     bak = 0;
  13.     return r;
  14.   }
  15.   int ch = getchar();
  16.   if (ch == '\n') {
  17.     bak = '\n';
  18.     ch = '\r';
  19.   }
  20.   return ch;
  21. }

  22. void ATE__ConsoleWrite(char const* p, unsigned num)
  23. {
  24.   fwrite(p, 1, num, stdout);
  25.   fflush(stdout);
  26. }

  27. void ATE__ConsoleFlushTx(void)
  28. {
  29.   fflush(stdout);
  30. }
复制代码

作者: honami520    时间: 2019-12-10 19:00
不错,准备在项目里面使用看看
作者: bad_fpga    时间: 2019-12-10 19:17
感谢分享AT解析,学习了
作者: 负西弱    时间: 2019-12-10 19:27
谢谢楼主分享
作者: 一号纵队    时间: 2019-12-10 19:36
下来学习下,谢了。
作者: dragonbbc    时间: 2019-12-10 20:09
mark先,用到的时候再研究
作者: genhao2    时间: 2019-12-10 23:13
效果不错,学习一下
作者: 关于以后    时间: 2019-12-10 23:31
样子不错啊。
作者: ztg328    时间: 2019-12-11 06:33
mark 刚在找at解析
作者: lrzxc    时间: 2019-12-11 06:39
谢谢分享,markPC端的软件
作者: blueice1108    时间: 2019-12-11 07:19
能弄個stm32 的例程嗎
作者: mypc16888    时间: 2019-12-11 07:41
不错,at解析
作者: 52avr    时间: 2019-12-11 08:43
AT命令解析引擎,谢谢楼主分享
作者: 落叶知秋    时间: 2019-12-11 08:49
看到这个帖子想起了以前写过的那个BASIC解释器
作者: 我是一个大白菜    时间: 2019-12-11 08:52
谢谢楼主分享,应该会用到
作者: jxn98310    时间: 2019-12-11 09:07
感谢分享
作者: wx-ta    时间: 2019-12-11 09:12
竟然看不懂用途,谁来科普下
作者: armstrong    时间: 2019-12-11 09:16
本帖最后由 armstrong 于 2019-12-11 09:26 编辑
wx-ta 发表于 2019-12-11 09:12
竟然看不懂用途,谁来科普下


AT命令的产品还是很多的,很多行业的成品模块都用AT操纵和配置。
当开发类似ESP8266这样的产品,需要实现AT操作接口就用得上。
yatengine把你登记的命令处理成大家熟知的C项目main入口一样:
void AT_XXX(int argc, char const* argv[])
{
  // todo...
}
这样,就不用花费时间考虑怎么设计这么个框架,直接加命令就是了;当然如果硬是想自己设计,那也会给你提供思路。总之是有价值的。
作者: makathy    时间: 2019-12-11 09:22

感谢分享,
作者: armstrong    时间: 2019-12-11 09:23
本帖最后由 armstrong 于 2019-12-11 09:55 编辑
honami520 发表于 2019-12-10 19:00
不错,准备在项目里面使用看看


可以放心应用,我也是用在产品里的。
在RTOS中,可以等待到串口数据到来时才调用ATE_Exec,不需要不停循环。
我的AT引擎专门一个线程,如下内容【仅供参考】:
  1. #include "usrinc.h"
  2. #include "cTinyFIFO.h"
  3. #include "atengine.h"

  4. static U64 __Stack1[1024 / 8] MEM_PI_STACK;
  5. static __task void __ThreadService(void);
  6. ////////////////////////////////////////////////////////////////////////////////
  7. //|          |
  8. //| 函数名称 |: APP_CreateATService
  9. //| 功能描述 |: 创建AT命令交互服务
  10. //|          |:
  11. //| 参数列表 |:
  12. //|          |:
  13. //| 返    回 |:
  14. //|          |:
  15. //| 备注信息 |:
  16. //|          |:
  17. ////////////////////////////////////////////////////////////////////////////////
  18. void APP_CreateATService(void)
  19. {
  20.   OS_TID tid = os_tsk_create_user(
  21.                    __ThreadService,
  22.                    TSK_PRIO_NORMAL,
  23.                    __Stack1,
  24.                    sizeof(__Stack1));

  25.   if (tid == 0) {
  26.     DBG_PUTS("AT failed.\n");
  27.     sys_suspend();
  28.   }
  29. }

  30. ////////////////////////////////////////////////////////////////////////////////
  31. //|          |
  32. //| 函数名称 |: __ThreadService
  33. //| 功能描述 |: 服务线程主循环
  34. //|          |:
  35. //| 参数列表 |:
  36. //|          |:
  37. //| 返    回 |:
  38. //|          |:
  39. //| 备注信息 |:
  40. //|          |:
  41. ////////////////////////////////////////////////////////////////////////////////
  42. #define EV_FLAG_TX      (0x0001)
  43. #define EV_FLAG_RX      (0x0002)
  44. #define EV_FLAG_INVOKE  (0x0004)
  45. static struct {
  46.   OS_TID serviceTID;
  47.   __IO uint8_t bPolling;
  48.   uint16_t rxLength;
  49.   __IO uint8_t* pRead;
  50.   uint8_t  rxBuffer[64];
  51.   void* invokeQueue;
  52. } cobj;
  53. static TickNodeType ticker;
  54. static InvokeItem invokelist[16];
  55. static void RX__Poller(void);
  56. static void TX__Signal(void);
  57. static void __ThreadService(void)
  58. {
  59.   U16 events;

  60.   cobj.rxLength = 0;
  61.   cobj.serviceTID = os_tsk_self();
  62.   cobj.bPolling = TRUE;

  63.   cobj.invokeQueue = FIFO_InvokeItemGetObject();
  64.   FIFO_InvokeItemCreate(cobj.invokeQueue, invokelist, COUNTOF(invokelist));
  65.   DRV_HOSTCOM_PurgeRxFifo();
  66.   DRV_HOSTCOM_RegTxSignal(TX__Signal);
  67.   os_evt_set(EV_FLAG_TX, cobj.serviceTID);

  68.   ticker.callback = RX__Poller;
  69.   TICK_Add(&ticker);

  70.   ATE__PostInvoke(0, 0);

  71.   while (1) {
  72.     if (OS_R_EVT == os_evt_wait_or(EV_FLAG_RX | EV_FLAG_INVOKE, TWAIT_FOREVER)) {
  73.       events = os_evt_get();
  74.       if (events & EV_FLAG_RX) {
  75.         ATE_Exec();
  76.         cobj.bPolling = TRUE;
  77.       }
  78.       if (events & EV_FLAG_INVOKE) {
  79.         InvokeItem obj;
  80.         while (FIFO_InvokeItemDequeue(cobj.invokeQueue, &obj)) {
  81.           if (obj.pf) {
  82.             obj.pf(obj.arg);
  83.           }
  84.         }
  85.       }
  86.     }
  87.   }
  88. }

  89. static void TX__Signal(void)
  90. {
  91.   // 该函数被ISR调用,所以必须ISR专用API
  92.   isr_evt_set(EV_FLAG_TX, cobj.serviceTID);
  93. }

  94. static void RX__Poller(void)
  95. {
  96.   // 该函数被Tick中断调用,所以必须ISR专用API
  97.   if (cobj.bPolling && DRV_HOSTCOM_GetRxFifoCount()) {
  98.     cobj.bPolling = FALSE;
  99.     isr_evt_set(EV_FLAG_RX, cobj.serviceTID);
  100.   }
  101. }

  102. void ATE__ConsolePurgeRx(void)
  103. {
  104.   DRV_HOSTCOM_PurgeRxFifo();
  105.   cobj.rxLength = 0;
  106. }

  107. int  ATE__ConsoleRead(void)
  108. {
  109.   unsigned i;
  110.   if (cobj.rxLength == 0) {
  111.     i = DRV_HOSTCOM_ReadFifo(cobj.rxBuffer, sizeof(cobj.rxBuffer));
  112.     if (i == 0) {
  113.       return -1;
  114.     }
  115.     cobj.pRead = cobj.rxBuffer;
  116.     cobj.rxLength = i;
  117.   }
  118.   i = *cobj.pRead++;
  119.   cobj.rxLength--;
  120.   return i;
  121. }

  122. void ATE__ConsoleWrite(char const* p, unsigned num)
  123. {
  124.   DRV_HOSTCOM_TxStream((uint8_t const*)p, num);
  125. }

  126. void ATE__ConsoleFlushTx(void)
  127. {
  128.   while (DRV_HOSTCOM_TxIsBusy()) {
  129.     os_evt_wait_or(EV_FLAG_TX, 10);
  130.   }
  131. }

  132. void ATE__PostInvoke(void (*pf)(void*), void* arg)
  133. {
  134.   InvokeItem obj;
  135.   obj.pf = pf;
  136.   obj.arg = arg;
  137.   if (FIFO_InvokeItemEnqueue(cobj.invokeQueue, &obj)) {
  138.     os_evt_set(EV_FLAG_INVOKE, cobj.serviceTID);
  139.   }
  140. }

  141. void ATE__PostInvokeISR(void (*pf)(void*), void* arg)
  142. {
  143.   InvokeItem obj;
  144.   obj.pf = pf;
  145.   obj.arg = arg;
  146.   if (FIFO_InvokeItemEnqueue(cobj.invokeQueue, &obj)) {
  147.     isr_evt_set(EV_FLAG_INVOKE, cobj.serviceTID);
  148.   }
  149. }


  150. ////////////////////////////////////////////////////////////////////////////////

复制代码


作者: armstrong    时间: 2019-12-11 09:29
blueice1108 发表于 2019-12-11 07:19
能弄個stm32 的例程嗎

看31楼回复,这是RTX下使用代码,就差USART驱动没贴出来了。
作者: nydxsydt0    时间: 2019-12-11 14:05
好东西先收藏
作者: kinsno    时间: 2019-12-11 17:45
armstrong 发表于 2019-12-11 09:29
看31楼回复,这是RTX下使用代码,就差USART驱动没贴出来了。

可以的

AT 引擎源码

赞1个。。

RTX刚使用了一个项目,感觉现在封装起来的CMSIS不如以前的RTX简洁了,简直是个臃肿的大包裹。

作者: 捷胜    时间: 2019-12-11 19:03
不错,收藏了
作者: dukelec    时间: 2019-12-11 19:10
本帖最后由 dukelec 于 2019-12-11 19:12 编辑

這個只是做服務器?支持做客戶端嗎?

我表示自己做東西優先選擇二進制協議,字符的太麻煩。
作者: lizuqing    时间: 2019-12-11 22:16

谢谢楼主分享,应该会用到
作者: blueice1108    时间: 2019-12-12 13:28
armstrong 发表于 2019-12-11 09:29
看31楼回复,这是RTX下使用代码,就差USART驱动没贴出来了。

谢谢 最近正好项目要用上~
作者: atonghua    时间: 2019-12-12 13:36
谢谢楼主分享  刚好公司搞软件的写了一个字符串协议  应该能用到
作者: huangqi412    时间: 2019-12-12 15:51
AT感觉好麻烦
作者: fdcnuaa    时间: 2019-12-16 09:57
mark at解析
作者: zhongsandaoren    时间: 2019-12-16 10:05
AT 服务 指令 mark
作者: heimareed    时间: 2019-12-17 10:57
万能的坛友,一直想弄一个,今天又拿来主义了~谢过!
作者: Ray______    时间: 2019-12-17 11:02
解析完的数据也是要遍历么。AT+XXX,XXX那部分
作者: abutter    时间: 2019-12-17 11:12
依赖 jsmn 库吗?
作者: armstrong    时间: 2019-12-17 11:16
abutter 发表于 2019-12-17 11:12
依赖 jsmn 库吗?

就一个头文件,已经在zip里了
作者: adlkkang    时间: 2019-12-17 12:42
楼主用的是可变参数,这样程序可靠吗
作者: denike    时间: 2019-12-17 15:42
Mark,备用,多谢分享

作者: qmsolo2004    时间: 2019-12-17 17:44
备用,多谢分享!
作者: armstrong    时间: 2019-12-17 22:28
Ray______ 发表于 2019-12-17 11:02
解析完的数据也是要遍历么。AT+XXX,XXX那部分

应用代码不需要再遍历了,框架会把AT+XXX=a,b,c,d,...
处理成void XXX_handler(int argc, char const* argv[])
的argc和argv参数传入,代码拿来用即可。
作者: n_mos    时间: 2020-3-2 21:59
AT 服务 指令 mark
作者: chewy    时间: 2020-3-2 22:05

AT 服务 指令 mark , 估计下个项目中 可以用的到了
作者: jackjiao    时间: 2020-3-2 23:34
学习下,一直在找AT解析架构相关的
作者: ponder2077    时间: 2020-3-12 01:14
学习了,也许用得着
作者: lihq97    时间: 2020-3-12 07:58
学习一下,刚好最近会用到。
作者: altim_li    时间: 2020-3-12 09:20
不错,收藏了
作者: dongwang_fl    时间: 2020-3-12 10:28
这个很好啊。
作者: lyg407    时间: 2020-3-12 13:57
一直想了解 AT 命令如何解析,操作的。想学习一下,竟然今天才看到文章。

收藏学习了!  谢谢楼主分享!
作者: zcllom    时间: 2020-7-24 16:44
armstrong 发表于 2019-12-10 17:51
稍微改了一下win32演示,让ATE__ConsoleWrite函数调用fwrite输出,这样才可以输出非字符数据,这才是ATE__C ...

在keil中编译的时候报错
作者: oooios    时间: 2020-9-22 08:13
多谢分享,拿来主义了
作者: xuekcd    时间: 2020-9-22 09:13
biu特否!非常好!
作者: 血刃修罗    时间: 2020-9-22 09:15
感谢分享,AT学习
作者: tyxjl    时间: 2020-9-22 09:21
收藏下,谢谢楼主了
作者: oooios    时间: 2020-9-30 08:52
有没有MDK例子?谢谢分享
作者: oooios    时间: 2020-9-30 11:40
本帖最后由 oooios 于 2020-9-30 14:47 编辑

你好,麻烦看看这个是怎么会事,谢谢
作者: oooios    时间: 2020-9-30 11:46
本帖最后由 oooios 于 2020-9-30 14:47 编辑

以解决;重写了void ATE_Exec1(unsigned char *in,unsigned short len),就可以了;
谢谢分享。
The ArgList:
[ 0]: =
[ 1]: 1
[ 2]: 2
[ 3]: 3
[ 4]: 4
[ 5]: true
[ 6]: abc
OK
OK
OK
作者: GNMXD    时间: 2020-9-30 17:23
不错,
参数设置中,既然人为加入“[ ]”,转换为json来解析,好方法!
作者: Felix725    时间: 2020-12-10 15:34
学习了,jsmn.h要花点时间研究一下。




欢迎光临 amobbs.com 阿莫电子技术论坛 (https://www.amobbs.com/) Powered by Discuz! X3.4