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