搜索
bottom↓
回复: 68

也发一个AT解析引擎源码【Yet Another AT Engine】

  [复制链接]

出870入263汤圆

发表于 2019-12-10 11:30:36 | 显示全部楼层 |阅读模式
本帖最后由 armstrong 于 2019-12-10 18:01 编辑

坛友之前发过一个AT解析代码,不是很全;而且不能很好的解析传入的参数,我发一个很好用的:

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. ////////////////////////////////////////////////////////////////////////////////

复制代码




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


编辑理由:更新了代码。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2020-12-10 15:34:37 | 显示全部楼层
学习了,jsmn.h要花点时间研究一下。

出0入0汤圆

发表于 2020-9-30 17:23:46 | 显示全部楼层
不错,
参数设置中,既然人为加入“[ ]”,转换为json来解析,好方法!

出0入0汤圆

发表于 2020-9-30 11:46:34 | 显示全部楼层
本帖最后由 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

出0入0汤圆

发表于 2020-9-30 11:40:39 | 显示全部楼层
本帖最后由 oooios 于 2020-9-30 14:47 编辑

你好,麻烦看看这个是怎么会事,谢谢

出0入0汤圆

发表于 2020-9-30 08:52:45 | 显示全部楼层
有没有MDK例子?谢谢分享

出0入0汤圆

发表于 2020-9-22 09:21:07 | 显示全部楼层
收藏下,谢谢楼主了

出0入0汤圆

发表于 2020-9-22 09:15:20 来自手机 | 显示全部楼层
感谢分享,AT学习

出0入0汤圆

发表于 2020-9-22 09:13:34 来自手机 | 显示全部楼层
biu特否!非常好!

出0入0汤圆

发表于 2020-9-22 08:13:17 来自手机 | 显示全部楼层
多谢分享,拿来主义了

出330入0汤圆

发表于 2020-7-24 16:44:32 | 显示全部楼层
armstrong 发表于 2019-12-10 17:51
稍微改了一下win32演示,让ATE__ConsoleWrite函数调用fwrite输出,这样才可以输出非字符数据,这才是ATE__C ...

在keil中编译的时候报错

出0入0汤圆

发表于 2020-3-12 13:57:28 | 显示全部楼层
一直想了解 AT 命令如何解析,操作的。想学习一下,竟然今天才看到文章。

收藏学习了!  谢谢楼主分享!

出0入0汤圆

发表于 2020-3-12 10:28:48 | 显示全部楼层
这个很好啊。

出0入0汤圆

发表于 2020-3-12 09:20:45 | 显示全部楼层
不错,收藏了

出0入0汤圆

发表于 2020-3-12 07:58:30 | 显示全部楼层
学习一下,刚好最近会用到。

出0入0汤圆

发表于 2020-3-12 01:14:01 来自手机 | 显示全部楼层
学习了,也许用得着

出0入0汤圆

发表于 2020-3-2 23:34:52 | 显示全部楼层
学习下,一直在找AT解析架构相关的

出0入0汤圆

发表于 2020-3-2 22:05:09 | 显示全部楼层

AT 服务 指令 mark , 估计下个项目中 可以用的到了

出0入0汤圆

发表于 2020-3-2 21:59:24 | 显示全部楼层
AT 服务 指令 mark

出870入263汤圆

 楼主| 发表于 2019-12-17 22:28:15 | 显示全部楼层
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参数传入,代码拿来用即可。

出0入0汤圆

发表于 2019-12-17 17:44:11 | 显示全部楼层
备用,多谢分享!

出0入0汤圆

发表于 2019-12-17 15:42:59 | 显示全部楼层
Mark,备用,多谢分享

出0入0汤圆

发表于 2019-12-17 12:42:23 | 显示全部楼层
楼主用的是可变参数,这样程序可靠吗

出870入263汤圆

 楼主| 发表于 2019-12-17 11:16:50 | 显示全部楼层

就一个头文件,已经在zip里了

出0入12汤圆

发表于 2019-12-17 11:12:45 | 显示全部楼层
依赖 jsmn 库吗?

出0入0汤圆

发表于 2019-12-17 11:02:09 | 显示全部楼层
解析完的数据也是要遍历么。AT+XXX,XXX那部分

出0入0汤圆

发表于 2019-12-17 10:57:52 | 显示全部楼层
万能的坛友,一直想弄一个,今天又拿来主义了~谢过!

出0入0汤圆

发表于 2019-12-16 10:05:56 | 显示全部楼层
AT 服务 指令 mark

出0入4汤圆

发表于 2019-12-16 09:57:26 来自手机 | 显示全部楼层
mark at解析

出0入0汤圆

发表于 2019-12-12 15:51:53 | 显示全部楼层
AT感觉好麻烦

出0入0汤圆

发表于 2019-12-12 13:36:13 | 显示全部楼层
谢谢楼主分享  刚好公司搞软件的写了一个字符串协议  应该能用到

出0入0汤圆

发表于 2019-12-12 13:28:06 | 显示全部楼层
armstrong 发表于 2019-12-11 09:29
看31楼回复,这是RTX下使用代码,就差USART驱动没贴出来了。

谢谢 最近正好项目要用上~

出0入0汤圆

发表于 2019-12-11 22:16:36 | 显示全部楼层

谢谢楼主分享,应该会用到

出615入1076汤圆

发表于 2019-12-11 19:10:31 来自手机 | 显示全部楼层
本帖最后由 dukelec 于 2019-12-11 19:12 编辑

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

我表示自己做東西優先選擇二進制協議,字符的太麻煩。

出5入4汤圆

发表于 2019-12-11 19:03:21 | 显示全部楼层
不错,收藏了

出0入0汤圆

发表于 2019-12-11 17:45:10 | 显示全部楼层
armstrong 发表于 2019-12-11 09:29
看31楼回复,这是RTX下使用代码,就差USART驱动没贴出来了。

可以的

AT 引擎源码

赞1个。。

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

出0入0汤圆

发表于 2019-12-11 14:05:31 | 显示全部楼层
好东西先收藏

出870入263汤圆

 楼主| 发表于 2019-12-11 09:29:15 | 显示全部楼层
blueice1108 发表于 2019-12-11 07:19
能弄個stm32 的例程嗎

看31楼回复,这是RTX下使用代码,就差USART驱动没贴出来了。

出870入263汤圆

 楼主| 发表于 2019-12-11 09:23:32 | 显示全部楼层
本帖最后由 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. ////////////////////////////////////////////////////////////////////////////////

复制代码

出0入0汤圆

发表于 2019-12-11 09:22:20 | 显示全部楼层

感谢分享,

出870入263汤圆

 楼主| 发表于 2019-12-11 09:16:34 | 显示全部楼层
本帖最后由 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...
}
这样,就不用花费时间考虑怎么设计这么个框架,直接加命令就是了;当然如果硬是想自己设计,那也会给你提供思路。总之是有价值的。

出0入0汤圆

发表于 2019-12-11 09:12:52 来自手机 | 显示全部楼层
竟然看不懂用途,谁来科普下

出0入0汤圆

发表于 2019-12-11 09:07:32 | 显示全部楼层
感谢分享

出0入42汤圆

发表于 2019-12-11 08:52:29 | 显示全部楼层
谢谢楼主分享,应该会用到

出40入42汤圆

发表于 2019-12-11 08:49:50 | 显示全部楼层
看到这个帖子想起了以前写过的那个BASIC解释器

出0入0汤圆

发表于 2019-12-11 08:43:51 | 显示全部楼层
AT命令解析引擎,谢谢楼主分享

出0入0汤圆

发表于 2019-12-11 07:41:25 来自手机 | 显示全部楼层
不错,at解析

出0入0汤圆

发表于 2019-12-11 07:19:22 来自手机 | 显示全部楼层
能弄個stm32 的例程嗎

出0入0汤圆

发表于 2019-12-11 06:39:14 来自手机 | 显示全部楼层
谢谢分享,markPC端的软件

出20入118汤圆

发表于 2019-12-11 06:33:36 来自手机 | 显示全部楼层
mark 刚在找at解析

出0入0汤圆

发表于 2019-12-10 23:31:02 | 显示全部楼层
样子不错啊。

出0入0汤圆

发表于 2019-12-10 23:13:43 来自手机 | 显示全部楼层
效果不错,学习一下

出0入0汤圆

发表于 2019-12-10 20:09:08 | 显示全部楼层
mark先,用到的时候再研究

出0入0汤圆

发表于 2019-12-10 19:36:32 | 显示全部楼层
下来学习下,谢了。

出0入0汤圆

发表于 2019-12-10 19:27:28 | 显示全部楼层
谢谢楼主分享

出0入0汤圆

发表于 2019-12-10 19:17:08 | 显示全部楼层
感谢分享AT解析,学习了

出0入90汤圆

发表于 2019-12-10 19:00:03 | 显示全部楼层
不错,准备在项目里面使用看看

出870入263汤圆

 楼主| 发表于 2019-12-10 17:51:23 | 显示全部楼层
稍微改了一下win32演示,让ATE__ConsoleWrite函数调用fwrite输出,这样才可以输出非字符数据,这才是ATE__ConsoleWrite定义num参数的初衷。

  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. }
复制代码

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出870入263汤圆

 楼主| 发表于 2019-12-10 15:47:09 | 显示全部楼层
这是我刚刚用yatengine做的“红外学习播放模块”命令,使用很方便:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出0入0汤圆

发表于 2019-12-10 15:43:55 | 显示全部楼层
MARK,肯定会用到

出140入115汤圆

发表于 2019-12-10 15:22:35 | 显示全部楼层
Mark,备用,多谢分享

出0入0汤圆

发表于 2019-12-10 14:44:52 | 显示全部楼层
早想做at指令配置参数了,哈哈

出0入0汤圆

发表于 2019-12-10 14:01:26 | 显示全部楼层
看起来不错 ; Mark

出0入22汤圆

发表于 2019-12-10 13:29:40 | 显示全部楼层
看起来不错

出870入263汤圆

 楼主| 发表于 2019-12-10 12:25:15 | 显示全部楼层
yatengine-win32.zip演示效果:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

出870入263汤圆

 楼主| 发表于 2019-12-10 12:10:26 | 显示全部楼层
anjiyifan 发表于 2019-12-10 12:03
不错!下载下来仔细看看。

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

出0入0汤圆

发表于 2019-12-10 12:03:59 | 显示全部楼层
不错!下载下来仔细看看。

出870入263汤圆

 楼主| 发表于 2019-12-10 11:33:45 | 显示全部楼层
本帖最后由 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;
复制代码

回帖提示: 反政府言论将被立即封锁ID 在按“提交”前,请自问一下:我这样表达会给举报吗,会给自己惹麻烦吗? 另外:尽量不要使用Mark、顶等没有意义的回复。不得大量使用大字体和彩色字。【本论坛不允许直接上传手机拍摄图片,浪费大家下载带宽和论坛服务器空间,请压缩后(图片小于1兆)才上传。压缩方法可以在微信里面发给自己(不要勾选“原图),然后下载,就能得到压缩后的图片】。另外,手机版只能上传图片,要上传附件需要切换到电脑版(不需要使用电脑,手机上切换到电脑版就行,页面底部)。
您需要登录后才可以回帖 登录 | 注册

本版积分规则

手机版|Archiver|amobbs.com 阿莫电子技术论坛 ( 粤ICP备2022115958号, 版权所有:东莞阿莫电子贸易商行 创办于2004年 (公安交互式论坛备案:44190002001997 ) )

GMT+8, 2024-4-19 23:20

© Since 2004 www.amobbs.com, 原www.ourdev.cn, 原www.ouravr.com

快速回复 返回顶部 返回列表