diff --git a/gatchat/gatsyntax.c b/gatchat/gatsyntax.c index d7c9ee23..a02f326d 100644 --- a/gatchat/gatsyntax.c +++ b/gatchat/gatsyntax.c @@ -27,7 +27,7 @@ #include "gatsyntax.h" -enum GSMV1_STATE_ { +enum GSMV1_STATE { GSMV1_STATE_IDLE = 0, GSMV1_STATE_INITIAL_CR, GSMV1_STATE_INITIAL_LF, @@ -45,6 +45,14 @@ enum GSMV1_STATE_ { GSMV1_STATE_GARBAGE_CHECK_LF, }; +enum GSM_PERMISSIVE_STATE { + GSM_PERMISSIVE_STATE_IDLE = 0, + GSM_PERMISSIVE_STATE_RESPONSE, + GSM_PERMISSIVE_STATE_GUESS_PDU, + GSM_PERMISSIVE_STATE_PDU, + GSM_PERMISSIVE_STATE_PROMPT, +}; + static void gsmv1_hint(GAtSyntax *syntax, GAtSyntaxExpectHint hint) { switch (hint) { @@ -215,6 +223,79 @@ out: return res; } +static void gsm_permissive_hint(GAtSyntax *syntax, GAtSyntaxExpectHint hint) +{ + if (hint == G_AT_SYNTAX_EXPECT_PDU) + syntax->state = GSM_PERMISSIVE_STATE_GUESS_PDU; +} + +static GAtSyntaxResult gsm_permissive_feed(GAtSyntax *syntax, + const char *bytes, gsize *len) +{ + gsize i = 0; + GAtSyntaxResult res = G_AT_SYNTAX_RESULT_UNSURE; + + while (i < *len) { + char byte = bytes[i]; + + switch (syntax->state) { + case GSM_PERMISSIVE_STATE_IDLE: + if (byte == '\r' || byte == '\n') + /* ignore */; + else if (byte == '>') + syntax->state = GSM_PERMISSIVE_STATE_PROMPT; + else + syntax->state = GSM_PERMISSIVE_STATE_RESPONSE; + break; + + case GSM_PERMISSIVE_STATE_RESPONSE: + if (byte == '\r') { + syntax->state = GSM_PERMISSIVE_STATE_IDLE; + + i += 1; + res = G_AT_SYNTAX_RESULT_LINE; + goto out; + } + break; + + case GSM_PERMISSIVE_STATE_GUESS_PDU: + if (byte != '\r' && byte != '\n') + syntax->state = GSM_PERMISSIVE_STATE_PDU; + break; + + case GSM_PERMISSIVE_STATE_PDU: + if (byte == '\r') { + syntax->state = GSM_PERMISSIVE_STATE_IDLE; + + i += 1; + res = G_AT_SYNTAX_RESULT_PDU; + goto out; + } + break; + + case GSM_PERMISSIVE_STATE_PROMPT: + if (byte == ' ') { + syntax->state = GSM_PERMISSIVE_STATE_IDLE; + i += 1; + res = G_AT_SYNTAX_RESULT_PROMPT; + goto out; + } + + syntax->state = GSM_PERMISSIVE_STATE_RESPONSE; + return G_AT_SYNTAX_RESULT_UNSURE; + + default: + break; + }; + + i += 1; + } + +out: + *len = i; + return res; +} + GAtSyntax *g_at_syntax_new_full(GAtSyntaxFeedFunc feed, GAtSyntaxSetHintFunc hint, int initial_state) @@ -237,6 +318,12 @@ GAtSyntax *g_at_syntax_new_gsmv1() return g_at_syntax_new_full(gsmv1_feed, gsmv1_hint, GSMV1_STATE_IDLE); } +GAtSyntax *g_at_syntax_new_gsm_permissive() +{ + return g_at_syntax_new_full(gsm_permissive_feed, gsm_permissive_hint, + GSM_PERMISSIVE_STATE_IDLE); +} + GAtSyntax *g_at_syntax_ref(GAtSyntax *syntax) { if (syntax == NULL) diff --git a/gatchat/gatsyntax.h b/gatchat/gatsyntax.h index 57edeade..d0d9254b 100644 --- a/gatchat/gatsyntax.h +++ b/gatchat/gatsyntax.h @@ -63,8 +63,20 @@ struct _GAtSyntax { GAtSyntax *g_at_syntax_new_full(GAtSyntaxFeedFunc feed, GAtSyntaxSetHintFunc hint, int initial_state); + +/* This syntax implements very strict checking of 27.007 standard, which means + * it might not work with a majority of modems. However, it does handle echo + * properly and can be used to detect a modem's deviations from the relevant + * standards. + */ GAtSyntax *g_at_syntax_new_gsmv1(); +/* This syntax implements an extremely lax parser that can handle a variety + * of modems. Unfortunately it does not deal with echo at all, so echo must + * be explicitly turned off before using the parser + */ +GAtSyntax *g_at_syntax_new_gsm_permissive(); + GAtSyntax *g_at_syntax_ref(GAtSyntax *syntax); void g_at_syntax_unref(GAtSyntax *syntax);