1 /*
2 This example code is in the Public Domain (or CC0 licensed, at your option.)
3
4 Unless required by applicable law or agreed to in writing, this
5 software is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
6 CONDITIONS OF ANY KIND, either express or implied.
7 */
8
9 #include <ctype.h>
10 #include <stdio.h>
11 #include <stdint.h>
12 #include <stdbool.h>
13 #include <string.h>
14 #include <stdlib.h>
15 #include "app_spp_msg_prs.h"
16 #include "app_spp_msg_set.h"
17
18 #define SPP_MSG_HDR_LEN (4)
19 const static char spp_msg_hdr[SPP_MSG_HDR_LEN] = {'s', 'p', 'p', ' '};
20 #define SPP_MSG_TAIL_LEN (1)
21 const static char spp_msg_tail[SPP_MSG_TAIL_LEN] = {';'};
22
spp_msg_parser_reset_state(spp_msg_prs_cb_t * prs)23 void spp_msg_parser_reset_state(spp_msg_prs_cb_t *prs)
24 {
25 prs->state = SPP_MSG_PRS_IDLE;
26 prs->cnt = 0;
27 prs->h_idx = 0;
28 prs->t_idx = 0;
29 }
30
spp_msg_parser_register_callback(spp_msg_prs_cb_t * prs,spp_msg_callback cb)31 void spp_msg_parser_register_callback(spp_msg_prs_cb_t *prs, spp_msg_callback cb)
32 {
33 prs->callback = cb;
34 }
35
spp_msg_parse(char c,spp_msg_prs_cb_t * prs)36 spp_msg_prs_err_t spp_msg_parse(char c, spp_msg_prs_cb_t *prs)
37 {
38 spp_msg_prs_err_t err = SPP_MSG_PRS_ERR_IN_PROGRESS;
39 switch (prs->state) {
40 case SPP_MSG_PRS_IDLE:
41 {
42 if (c == spp_msg_hdr[0]) {
43 prs->state = SPP_MSG_PRS_HDR;
44 prs->buf[0] = c;
45 prs->cnt = 1;
46 prs->h_idx = 1;
47 } else {
48 err = SPP_MSG_PRS_ERR_HDR_UNDETECTED;
49 }
50 break;
51 }
52
53 case SPP_MSG_PRS_HDR:
54 {
55 if (c == spp_msg_hdr[prs->h_idx]) {
56 prs->buf[prs->cnt++] = c;
57 if (++(prs->h_idx) == SPP_MSG_HDR_LEN) {
58 prs->state = SPP_MSG_PRS_PAYL;
59 prs->t_idx = 0;
60 }
61 } else {
62 spp_msg_parser_reset_state(prs);
63 err = SPP_MSG_PRS_ERR_HDR_SYNC_FAILED;
64 }
65 break;
66 }
67
68 case SPP_MSG_PRS_PAYL:
69 {
70 prs->buf[prs->cnt++] = c;
71 if (c == spp_msg_tail[prs->t_idx]) {
72 if (++(prs->t_idx) == SPP_MSG_TAIL_LEN) {
73 prs->buf[prs->cnt] = '\0';
74 prs->callback(prs->buf, prs->cnt);
75 spp_msg_parser_reset_state(prs);
76 err = SPP_MSG_PRS_ERR_OK;
77 break;
78 }
79 } else {
80 prs->t_idx = 0;
81 }
82
83 if (prs->cnt >= SPP_MSG_LEN_MAX-1) {
84 spp_msg_parser_reset_state(prs);
85 err = SPP_MSG_PRS_ERR_BUF_OVERFLOW;
86 }
87 break;
88 }
89 }
90 return err;
91 }
92
93
spp_msg_split_args(char * start,char * end,char ** argv,int * argn)94 void spp_msg_split_args(char *start, char *end, char **argv, int *argn)
95 {
96 if (argn == NULL || *argn == 0) {
97 return;
98 }
99
100 memset(argv, 0, (*argn) * sizeof(void *));
101
102 int max_argn = *argn;
103 *argn = 0;
104
105 char *p = start;
106 for (int i = 0; i < max_argn; ++i) {
107 while (isspace((int)*p) && p != end) {
108 ++p;
109 }
110 if (p == end) {
111 return;
112 }
113
114 argv[i] = p++;
115 ++(*argn);
116
117 while (!isspace((int)*p) && p != end) {
118 ++p;
119 }
120
121 if (p == end) {
122 return;
123 } else {
124 *p = '\0';
125 ++p;
126 }
127 }
128 }
129
spp_msg_args_parser(char * buf,int len)130 void spp_msg_args_parser(char *buf, int len)
131 {
132 char *argv[SPP_MSG_ARGS_MAX];
133 int argn = SPP_MSG_ARGS_MAX;
134 char *start = buf + SPP_MSG_HDR_LEN;
135 // set the command terminator to '\0'
136 char *end = buf + len - SPP_MSG_TAIL_LEN;
137 *end = '\0';
138
139 spp_msg_split_args(start, end, argv, &argn);
140
141 if (argn == 0) {
142 return;
143 }
144
145 bool cmd_supported = false;
146
147 spp_msg_hdl_t *cmd_tbl = spp_get_cmd_tbl();
148 size_t cmd_tbl_size = spp_get_cmd_tbl_size();
149 for (int i = 0; i < cmd_tbl_size; ++i) {
150 spp_msg_hdl_t *hdl = &cmd_tbl[i];
151 if (strcmp(argv[0], hdl->str) == 0) {
152 if (hdl->handler) {
153 hdl->handler(argn, argv);
154 cmd_supported = true;
155 break;
156 }
157 }
158 }
159 if (!cmd_supported) {
160 printf("unsupported command\n");
161 spp_msg_show_usage();
162 }
163 return;
164 }
165