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 static void gsmv1_hint(GAtSyntax *syntax, GAtSyntaxExpectHint hint)
51 case G_AT_SYNTAX_EXPECT_PDU:
52 syntax->state = GSMV1_STATE_PDU_CHECK_EXTRA_CR;
54 case G_AT_SYNTAX_EXPECT_MULTILINE:
55 syntax->state = GSMV1_STATE_GUESS_MULTILINE_RESPONSE;
62 static GAtSyntaxResult gsmv1_feed(GAtSyntax *syntax,
63 const char *bytes, gsize *len)
66 GAtSyntaxResult res = G_AT_SYNTAX_RESULT_UNSURE;
71 switch (syntax->state) {
72 case GSMV1_STATE_IDLE:
74 syntax->state = GSMV1_STATE_INITIAL_CR;
76 syntax->state = GSMV1_STATE_GARBAGE;
79 case GSMV1_STATE_INITIAL_CR:
81 syntax->state = GSMV1_STATE_INITIAL_LF;
83 syntax->state = GSMV1_STATE_GARBAGE;
86 case GSMV1_STATE_INITIAL_LF:
88 syntax->state = GSMV1_STATE_TERMINATOR_CR;
90 syntax->state = GSMV1_STATE_PROMPT;
92 syntax->state = GSMV1_STATE_RESPONSE;
95 case GSMV1_STATE_RESPONSE:
97 syntax->state = GSMV1_STATE_TERMINATOR_CR;
100 case GSMV1_STATE_TERMINATOR_CR:
101 syntax->state = GSMV1_STATE_IDLE;
105 res = G_AT_SYNTAX_RESULT_LINE;
107 res = G_AT_SYNTAX_RESULT_UNRECOGNIZED;
111 case GSMV1_STATE_GUESS_MULTILINE_RESPONSE:
113 syntax->state = GSMV1_STATE_INITIAL_CR;
115 syntax->state = GSMV1_STATE_MULTILINE_RESPONSE;
118 case GSMV1_STATE_MULTILINE_RESPONSE:
120 syntax->state = GSMV1_STATE_MULTILINE_TERMINATOR_CR;
123 case GSMV1_STATE_MULTILINE_TERMINATOR_CR:
124 syntax->state = GSMV1_STATE_IDLE;
128 res = G_AT_SYNTAX_RESULT_MULTILINE;
130 res = G_AT_SYNTAX_RESULT_UNRECOGNIZED;
134 /* Some 27.007 compliant modems still get this wrong. They
135 * insert an extra CRLF between the command and he PDU,
136 * in effect making them two separate lines. We try to
137 * handle this case gracefully
139 case GSMV1_STATE_PDU_CHECK_EXTRA_CR:
141 syntax->state = GSMV1_STATE_PDU_CHECK_EXTRA_LF;
143 syntax->state = GSMV1_STATE_PDU;
146 case GSMV1_STATE_PDU_CHECK_EXTRA_LF:
147 res = G_AT_SYNTAX_RESULT_UNRECOGNIZED;
148 syntax->state = GSMV1_STATE_PDU;
155 case GSMV1_STATE_PDU:
157 syntax->state = GSMV1_STATE_PDU_CR;
160 case GSMV1_STATE_PDU_CR:
161 syntax->state = GSMV1_STATE_IDLE;
165 res = G_AT_SYNTAX_RESULT_PDU;
167 res = G_AT_SYNTAX_RESULT_UNRECOGNIZED;
171 case GSMV1_STATE_PROMPT:
173 syntax->state = GSMV1_STATE_IDLE;
175 res = G_AT_SYNTAX_RESULT_PROMPT;
179 syntax->state = GSMV1_STATE_RESPONSE;
180 return G_AT_SYNTAX_RESULT_UNSURE;
182 case GSMV1_STATE_GARBAGE:
184 syntax->state = GSMV1_STATE_GARBAGE_CHECK_LF;
185 /* This handles the case of echo of the PDU terminated
188 else if (byte == 26) {
189 syntax->state = GSMV1_STATE_IDLE;
190 res = G_AT_SYNTAX_RESULT_UNRECOGNIZED;
197 case GSMV1_STATE_GARBAGE_CHECK_LF:
198 syntax->state = GSMV1_STATE_IDLE;
199 res = G_AT_SYNTAX_RESULT_UNRECOGNIZED;
218 GAtSyntax *g_at_syntax_new_full(GAtSyntaxFeedFunc feed,
219 GAtSyntaxSetHintFunc hint,
224 syntax = g_new0(GAtSyntax, 1);
227 syntax->set_hint = hint;
228 syntax->state = initial_state;
229 syntax->ref_count = 1;
235 GAtSyntax *g_at_syntax_new_gsmv1()
237 return g_at_syntax_new_full(gsmv1_feed, gsmv1_hint, GSMV1_STATE_IDLE);
240 GAtSyntax *g_at_syntax_ref(GAtSyntax *syntax)
245 g_atomic_int_inc(&syntax->ref_count);
250 void g_at_syntax_unref(GAtSyntax *syntax)
257 is_zero = g_atomic_int_dec_and_test(&syntax->ref_count);