3 * AT chat library with GLib integration
5 * Copyright (C) 2008-2009 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_TERMINATOR_CR,
36 GSMV1_STATE_GUESS_MULTILINE_RESPONSE,
37 GSMV1_STATE_MULTILINE_RESPONSE,
38 GSMV1_STATE_MULTILINE_TERMINATOR_CR,
39 GSMV1_STATE_PDU_CHECK_EXTRA_CR,
40 GSMV1_STATE_PDU_CHECK_EXTRA_LF,
45 GSMV1_STATE_GARBAGE_CHECK_LF,
48 enum GSM_PERMISSIVE_STATE {
49 GSM_PERMISSIVE_STATE_IDLE = 0,
50 GSM_PERMISSIVE_STATE_RESPONSE,
51 GSM_PERMISSIVE_STATE_GUESS_PDU,
52 GSM_PERMISSIVE_STATE_PDU,
53 GSM_PERMISSIVE_STATE_PROMPT,
56 static void gsmv1_hint(GAtSyntax *syntax, GAtSyntaxExpectHint hint)
59 case G_AT_SYNTAX_EXPECT_PDU:
60 syntax->state = GSMV1_STATE_PDU_CHECK_EXTRA_CR;
62 case G_AT_SYNTAX_EXPECT_MULTILINE:
63 syntax->state = GSMV1_STATE_GUESS_MULTILINE_RESPONSE;
70 static GAtSyntaxResult gsmv1_feed(GAtSyntax *syntax,
71 const char *bytes, gsize *len)
74 GAtSyntaxResult res = G_AT_SYNTAX_RESULT_UNSURE;
79 switch (syntax->state) {
80 case GSMV1_STATE_IDLE:
82 syntax->state = GSMV1_STATE_INITIAL_CR;
84 syntax->state = GSMV1_STATE_GARBAGE;
87 case GSMV1_STATE_INITIAL_CR:
89 syntax->state = GSMV1_STATE_INITIAL_LF;
91 syntax->state = GSMV1_STATE_GARBAGE;
94 case GSMV1_STATE_INITIAL_LF:
96 syntax->state = GSMV1_STATE_TERMINATOR_CR;
98 syntax->state = GSMV1_STATE_PROMPT;
100 syntax->state = GSMV1_STATE_RESPONSE;
103 case GSMV1_STATE_RESPONSE:
105 syntax->state = GSMV1_STATE_TERMINATOR_CR;
108 case GSMV1_STATE_TERMINATOR_CR:
109 syntax->state = GSMV1_STATE_IDLE;
113 res = G_AT_SYNTAX_RESULT_LINE;
115 res = G_AT_SYNTAX_RESULT_UNRECOGNIZED;
119 case GSMV1_STATE_GUESS_MULTILINE_RESPONSE:
121 syntax->state = GSMV1_STATE_INITIAL_CR;
123 syntax->state = GSMV1_STATE_MULTILINE_RESPONSE;
126 case GSMV1_STATE_MULTILINE_RESPONSE:
128 syntax->state = GSMV1_STATE_MULTILINE_TERMINATOR_CR;
131 case GSMV1_STATE_MULTILINE_TERMINATOR_CR:
132 syntax->state = GSMV1_STATE_IDLE;
136 res = G_AT_SYNTAX_RESULT_MULTILINE;
138 res = G_AT_SYNTAX_RESULT_UNRECOGNIZED;
142 /* Some 27.007 compliant modems still get this wrong. They
143 * insert an extra CRLF between the command and he PDU,
144 * in effect making them two separate lines. We try to
145 * handle this case gracefully
147 case GSMV1_STATE_PDU_CHECK_EXTRA_CR:
149 syntax->state = GSMV1_STATE_PDU_CHECK_EXTRA_LF;
151 syntax->state = GSMV1_STATE_PDU;
154 case GSMV1_STATE_PDU_CHECK_EXTRA_LF:
155 res = G_AT_SYNTAX_RESULT_UNRECOGNIZED;
156 syntax->state = GSMV1_STATE_PDU;
163 case GSMV1_STATE_PDU:
165 syntax->state = GSMV1_STATE_PDU_CR;
168 case GSMV1_STATE_PDU_CR:
169 syntax->state = GSMV1_STATE_IDLE;
173 res = G_AT_SYNTAX_RESULT_PDU;
175 res = G_AT_SYNTAX_RESULT_UNRECOGNIZED;
179 case GSMV1_STATE_PROMPT:
181 syntax->state = GSMV1_STATE_IDLE;
183 res = G_AT_SYNTAX_RESULT_PROMPT;
187 syntax->state = GSMV1_STATE_RESPONSE;
188 return G_AT_SYNTAX_RESULT_UNSURE;
190 case GSMV1_STATE_GARBAGE:
192 syntax->state = GSMV1_STATE_GARBAGE_CHECK_LF;
193 /* This handles the case of echo of the PDU terminated
196 else if (byte == 26) {
197 syntax->state = GSMV1_STATE_IDLE;
198 res = G_AT_SYNTAX_RESULT_UNRECOGNIZED;
205 case GSMV1_STATE_GARBAGE_CHECK_LF:
206 syntax->state = GSMV1_STATE_IDLE;
207 res = G_AT_SYNTAX_RESULT_UNRECOGNIZED;
226 static void gsm_permissive_hint(GAtSyntax *syntax, GAtSyntaxExpectHint hint)
228 if (hint == G_AT_SYNTAX_EXPECT_PDU)
229 syntax->state = GSM_PERMISSIVE_STATE_GUESS_PDU;
232 static GAtSyntaxResult gsm_permissive_feed(GAtSyntax *syntax,
233 const char *bytes, gsize *len)
236 GAtSyntaxResult res = G_AT_SYNTAX_RESULT_UNSURE;
239 char byte = bytes[i];
241 switch (syntax->state) {
242 case GSM_PERMISSIVE_STATE_IDLE:
243 if (byte == '\r' || byte == '\n')
245 else if (byte == '>')
246 syntax->state = GSM_PERMISSIVE_STATE_PROMPT;
248 syntax->state = GSM_PERMISSIVE_STATE_RESPONSE;
251 case GSM_PERMISSIVE_STATE_RESPONSE:
253 syntax->state = GSM_PERMISSIVE_STATE_IDLE;
256 res = G_AT_SYNTAX_RESULT_LINE;
261 case GSM_PERMISSIVE_STATE_GUESS_PDU:
262 if (byte != '\r' && byte != '\n')
263 syntax->state = GSM_PERMISSIVE_STATE_PDU;
266 case GSM_PERMISSIVE_STATE_PDU:
268 syntax->state = GSM_PERMISSIVE_STATE_IDLE;
271 res = G_AT_SYNTAX_RESULT_PDU;
276 case GSM_PERMISSIVE_STATE_PROMPT:
278 syntax->state = GSM_PERMISSIVE_STATE_IDLE;
280 res = G_AT_SYNTAX_RESULT_PROMPT;
284 syntax->state = GSM_PERMISSIVE_STATE_RESPONSE;
285 return G_AT_SYNTAX_RESULT_UNSURE;
299 GAtSyntax *g_at_syntax_new_full(GAtSyntaxFeedFunc feed,
300 GAtSyntaxSetHintFunc hint,
305 syntax = g_new0(GAtSyntax, 1);
308 syntax->set_hint = hint;
309 syntax->state = initial_state;
310 syntax->ref_count = 1;
316 GAtSyntax *g_at_syntax_new_gsmv1()
318 return g_at_syntax_new_full(gsmv1_feed, gsmv1_hint, GSMV1_STATE_IDLE);
321 GAtSyntax *g_at_syntax_new_gsm_permissive()
323 return g_at_syntax_new_full(gsm_permissive_feed, gsm_permissive_hint,
324 GSM_PERMISSIVE_STATE_IDLE);
327 GAtSyntax *g_at_syntax_ref(GAtSyntax *syntax)
332 g_atomic_int_inc(&syntax->ref_count);
337 void g_at_syntax_unref(GAtSyntax *syntax)
344 is_zero = g_atomic_int_dec_and_test(&syntax->ref_count);