3 * AT chat library with GLib integration
5 * Copyright (C) 2008-2011 Intel Corporation. All rights reserved.
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License version 2 as
9 * published by the Free Software Foundation.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
28 #include "gatsyntax.h"
32 GSMV1_STATE_INITIAL_CR,
33 GSMV1_STATE_INITIAL_LF,
35 GSMV1_STATE_RESPONSE_STRING,
36 GSMV1_STATE_TERMINATOR_CR,
37 GSMV1_STATE_GUESS_MULTILINE_RESPONSE,
38 GSMV1_STATE_MULTILINE_RESPONSE,
39 GSMV1_STATE_MULTILINE_TERMINATOR_CR,
40 GSMV1_STATE_PDU_CHECK_EXTRA_CR,
41 GSMV1_STATE_PDU_CHECK_EXTRA_LF,
47 GSMV1_STATE_SHORT_PROMPT,
48 GSMV1_STATE_SHORT_PROMPT_CR,
51 enum GSM_PERMISSIVE_STATE {
52 GSM_PERMISSIVE_STATE_IDLE = 0,
53 GSM_PERMISSIVE_STATE_RESPONSE,
54 GSM_PERMISSIVE_STATE_RESPONSE_STRING,
55 GSM_PERMISSIVE_STATE_GUESS_PDU,
56 GSM_PERMISSIVE_STATE_PDU,
57 GSM_PERMISSIVE_STATE_PROMPT,
58 GSM_PERMISSIVE_STATE_GUESS_SHORT_PROMPT,
59 GSM_PERMISSIVE_STATE_SHORT_PROMPT,
62 static void gsmv1_hint(GAtSyntax *syntax, GAtSyntaxExpectHint hint)
65 case G_AT_SYNTAX_EXPECT_PDU:
66 syntax->state = GSMV1_STATE_PDU_CHECK_EXTRA_CR;
68 case G_AT_SYNTAX_EXPECT_MULTILINE:
69 syntax->state = GSMV1_STATE_GUESS_MULTILINE_RESPONSE;
71 case G_AT_SYNTAX_EXPECT_SHORT_PROMPT:
72 syntax->state = GSMV1_STATE_SHORT_PROMPT;
79 static GAtSyntaxResult gsmv1_feed(GAtSyntax *syntax,
80 const char *bytes, gsize *len)
83 GAtSyntaxResult res = G_AT_SYNTAX_RESULT_UNSURE;
88 switch (syntax->state) {
89 case GSMV1_STATE_IDLE:
91 syntax->state = GSMV1_STATE_INITIAL_CR;
93 syntax->state = GSMV1_STATE_PPP_DATA;
95 syntax->state = GSMV1_STATE_ECHO;
98 case GSMV1_STATE_INITIAL_CR:
100 syntax->state = GSMV1_STATE_INITIAL_LF;
101 else if (byte == '\r') {
102 syntax->state = GSMV1_STATE_IDLE;
103 return G_AT_SYNTAX_RESULT_UNRECOGNIZED;
105 syntax->state = GSMV1_STATE_ECHO;
108 case GSMV1_STATE_INITIAL_LF:
110 syntax->state = GSMV1_STATE_TERMINATOR_CR;
111 else if (byte == '>')
112 syntax->state = GSMV1_STATE_PROMPT;
113 else if (byte == '"')
114 syntax->state = GSMV1_STATE_RESPONSE_STRING;
116 syntax->state = GSMV1_STATE_RESPONSE;
119 case GSMV1_STATE_RESPONSE:
121 syntax->state = GSMV1_STATE_TERMINATOR_CR;
122 else if (byte == '"')
123 syntax->state = GSMV1_STATE_RESPONSE_STRING;
126 case GSMV1_STATE_RESPONSE_STRING:
128 syntax->state = GSMV1_STATE_RESPONSE;
131 case GSMV1_STATE_TERMINATOR_CR:
132 syntax->state = GSMV1_STATE_IDLE;
136 res = G_AT_SYNTAX_RESULT_LINE;
138 res = G_AT_SYNTAX_RESULT_UNRECOGNIZED;
142 case GSMV1_STATE_GUESS_MULTILINE_RESPONSE:
144 syntax->state = GSMV1_STATE_INITIAL_CR;
146 syntax->state = GSMV1_STATE_MULTILINE_RESPONSE;
149 case GSMV1_STATE_MULTILINE_RESPONSE:
151 syntax->state = GSMV1_STATE_MULTILINE_TERMINATOR_CR;
154 case GSMV1_STATE_MULTILINE_TERMINATOR_CR:
155 syntax->state = GSMV1_STATE_IDLE;
159 res = G_AT_SYNTAX_RESULT_MULTILINE;
161 res = G_AT_SYNTAX_RESULT_UNRECOGNIZED;
165 /* Some 27.007 compliant modems still get this wrong. They
166 * insert an extra CRLF between the command and he PDU,
167 * in effect making them two separate lines. We try to
168 * handle this case gracefully
170 case GSMV1_STATE_PDU_CHECK_EXTRA_CR:
172 syntax->state = GSMV1_STATE_PDU_CHECK_EXTRA_LF;
174 syntax->state = GSMV1_STATE_PDU;
177 case GSMV1_STATE_PDU_CHECK_EXTRA_LF:
178 res = G_AT_SYNTAX_RESULT_UNRECOGNIZED;
179 syntax->state = GSMV1_STATE_PDU;
186 case GSMV1_STATE_PDU:
188 syntax->state = GSMV1_STATE_PDU_CR;
191 case GSMV1_STATE_PDU_CR:
192 syntax->state = GSMV1_STATE_IDLE;
196 res = G_AT_SYNTAX_RESULT_PDU;
198 res = G_AT_SYNTAX_RESULT_UNRECOGNIZED;
202 case GSMV1_STATE_PROMPT:
204 syntax->state = GSMV1_STATE_IDLE;
206 res = G_AT_SYNTAX_RESULT_PROMPT;
210 syntax->state = GSMV1_STATE_RESPONSE;
211 return G_AT_SYNTAX_RESULT_UNSURE;
213 case GSMV1_STATE_ECHO:
214 /* This handles the case of echo of the PDU terminated
217 if (byte == 26 || byte == '\r') {
218 syntax->state = GSMV1_STATE_IDLE;
219 res = G_AT_SYNTAX_RESULT_UNRECOGNIZED;
226 case GSMV1_STATE_PPP_DATA:
228 syntax->state = GSMV1_STATE_IDLE;
229 res = G_AT_SYNTAX_RESULT_UNRECOGNIZED;
236 case GSMV1_STATE_SHORT_PROMPT:
238 syntax->state = GSMV1_STATE_SHORT_PROMPT_CR;
240 syntax->state = GSMV1_STATE_ECHO;
244 case GSMV1_STATE_SHORT_PROMPT_CR:
246 syntax->state = GSMV1_STATE_IDLE;
248 res = G_AT_SYNTAX_RESULT_PROMPT;
252 syntax->state = GSMV1_STATE_RESPONSE;
253 return G_AT_SYNTAX_RESULT_UNSURE;
267 static void gsm_permissive_hint(GAtSyntax *syntax, GAtSyntaxExpectHint hint)
269 if (hint == G_AT_SYNTAX_EXPECT_PDU)
270 syntax->state = GSM_PERMISSIVE_STATE_GUESS_PDU;
271 else if (hint == G_AT_SYNTAX_EXPECT_SHORT_PROMPT)
272 syntax->state = GSM_PERMISSIVE_STATE_GUESS_SHORT_PROMPT;
275 static GAtSyntaxResult gsm_permissive_feed(GAtSyntax *syntax,
276 const char *bytes, gsize *len)
279 GAtSyntaxResult res = G_AT_SYNTAX_RESULT_UNSURE;
282 char byte = bytes[i];
284 switch (syntax->state) {
285 case GSM_PERMISSIVE_STATE_IDLE:
286 if (byte == '\r' || byte == '\n')
288 else if (byte == '>')
289 syntax->state = GSM_PERMISSIVE_STATE_PROMPT;
290 else if (byte == '"')
292 GSM_PERMISSIVE_STATE_RESPONSE_STRING;
294 syntax->state = GSM_PERMISSIVE_STATE_RESPONSE;
297 case GSM_PERMISSIVE_STATE_RESPONSE:
299 syntax->state = GSM_PERMISSIVE_STATE_IDLE;
302 res = G_AT_SYNTAX_RESULT_LINE;
304 } else if (byte == '"')
306 GSM_PERMISSIVE_STATE_RESPONSE_STRING;
309 case GSM_PERMISSIVE_STATE_RESPONSE_STRING:
311 syntax->state = GSM_PERMISSIVE_STATE_RESPONSE;
314 case GSM_PERMISSIVE_STATE_GUESS_PDU:
315 if (byte != '\r' && byte != '\n')
316 syntax->state = GSM_PERMISSIVE_STATE_PDU;
319 case GSM_PERMISSIVE_STATE_PDU:
321 syntax->state = GSM_PERMISSIVE_STATE_IDLE;
324 res = G_AT_SYNTAX_RESULT_PDU;
329 case GSM_PERMISSIVE_STATE_PROMPT:
331 syntax->state = GSM_PERMISSIVE_STATE_IDLE;
333 res = G_AT_SYNTAX_RESULT_PROMPT;
337 syntax->state = GSM_PERMISSIVE_STATE_RESPONSE;
338 return G_AT_SYNTAX_RESULT_UNSURE;
340 case GSM_PERMISSIVE_STATE_GUESS_SHORT_PROMPT:
343 else if (byte == '\r')
345 GSM_PERMISSIVE_STATE_SHORT_PROMPT;
347 syntax->state = GSM_PERMISSIVE_STATE_RESPONSE;
350 case GSM_PERMISSIVE_STATE_SHORT_PROMPT:
352 syntax->state = GSM_PERMISSIVE_STATE_IDLE;
354 res = G_AT_SYNTAX_RESULT_PROMPT;
358 syntax->state = GSM_PERMISSIVE_STATE_RESPONSE;
359 return G_AT_SYNTAX_RESULT_UNSURE;
373 GAtSyntax *g_at_syntax_new_full(GAtSyntaxFeedFunc feed,
374 GAtSyntaxSetHintFunc hint,
379 syntax = g_new0(GAtSyntax, 1);
382 syntax->set_hint = hint;
383 syntax->state = initial_state;
384 syntax->ref_count = 1;
390 GAtSyntax *g_at_syntax_new_gsmv1(void)
392 return g_at_syntax_new_full(gsmv1_feed, gsmv1_hint, GSMV1_STATE_IDLE);
395 GAtSyntax *g_at_syntax_new_gsm_permissive(void)
397 return g_at_syntax_new_full(gsm_permissive_feed, gsm_permissive_hint,
398 GSM_PERMISSIVE_STATE_IDLE);
401 GAtSyntax *g_at_syntax_ref(GAtSyntax *syntax)
406 g_atomic_int_inc(&syntax->ref_count);
411 void g_at_syntax_unref(GAtSyntax *syntax)
418 is_zero = g_atomic_int_dec_and_test(&syntax->ref_count);