2013-02-03 23 views
10

Ich habe an einer Anwendung gearbeitet, die ein GSM-Modem für eines von zwei Dingen verwendet; Überprüfen Sie den Status mithilfe des integrierten HTTP-Stacks, indem Sie eine GET-Anforderung an den Server senden oder Daten an den Server senden (mithilfe von UDP). Ich habe verschiedene Methoden ausprobiert, um dies so zuverlässig wie möglich zu halten, und bin endlich bereit, um Hilfe zu bitten.Einen GSM-Modem-Treiber schreiben?

Meine Anwendung ist für das SIMCOM908-Modul und die PIC18-Plattform geschrieben (ich verwende einen PIC18 Explorer für die Entwicklung).

So ist das Problem manchmal das Modem ist beschäftigt, etwas zu tun, und verfehlt einen Befehl. Als Mensch würde ich das sehen und den Befehl einfach erneut senden. Das Hinzufügen einer Einrichtung für meine MCU zu Zeitüberschreitung und erneutem Senden ist kein Problem.

Ein Problem ist, dass das Modem unerwünschte Antworten nach verschiedenen Ereignissen sendet. Wenn das Modem den Registrierungsstatus ändert (mit dem Mobilfunkmast), antwortet es mit +CGREG: 1, ... oder wenn das GPS bereit ist GPS Ready. Diese Antworten können jederzeit auftreten, auch mitten in einem Befehl (z. B. beim Erstellen einer IP-Verbindung).

Das ist ein Problem, weil ich nicht über eine Möglichkeit nachgedacht habe, damit umzugehen. Meine Anwendung muss einen Befehl senden (um eine Verbindung zum Server herzustellen, z. B. AT+CIPSTART="UDP","example.com",5000). Dieser Befehl antwortet mit 'OK' und dann, wenn der Befehl 'CONNECT OK' beendet ist. Ich muss jedoch in der Lage sein, auf die vielen anderen möglichen Antworten zu reagieren, und ich habe keinen Weg gefunden, dies zu tun. Was muss ich mit meinem Code tun? Warten Sie auf eine Antwort vom Modem, überprüfen Sie die Antwort, führen Sie eine Aktion basierend auf dieser Antwort durch?

Ich bin Code-begrenzt (ein 8-Bit-Mikrocontroller!) Und möchte die Keep-Wiederholung auf ein Minimum reduzieren. Wie kann ich eine Antwortfunktion schreiben, die eine Antwort vom GSM-Modul (angefordert oder jetzt) ​​nimmt und dann den Rest meines Programms weiß, was passiert?

Idealerweise möchte ich etwas mit diesen Antworten tun. Wie halten einen internen Zustand (wenn ich GPS Ready hören, ich weiß, dass ich die GPS mit Strom versorgen usw.

Vielleicht gibt es einige Dinge, die ich denken soll, oder vielleicht ist es ein Open-Source-Projekt, das bereits dieses Problem löst?

Hier ist, was ich bisher:..

/* Command responses */ 
enum { 
    // Common 
    OK = 0, 
    ERROR, 
    TIMEOUT, 
    OTHER, 
    // CGREG 
    NOT_REGISTERED, 
    // CGATT 
    NOT_ATTACHED, 
    // Network Status 
    NO_NETWORK, 
    // GPRS status 
    NO_ADDRESS, 
    // HTTP ACTION 
    NETWORK_ERROR, 
    // IP Stack State 
    IP_INITIAL, 
    IP_STATUS, 
    IP_CONFIG, 
    UDP_CLOSING, 
    UDP_CLOSED, 
    UDP_CONNECTING 
} gsmResponse; 

int gsm_sendCommand(const char * cmd) { 
    unsigned long timeout = timer_getCurrentTime() + 5000; 

    uart_clearb(GSM_UART); // Clear the input buffer 
    uart_puts(GSM_UART, cmd); // Send the command to the module 
    while (strstr(bf2, "\r") == NULL) { // Keep waiting for a response from the module 
     if (timeout < timer_getCurrentTime()) { // Check we haven't timed out yet 
      printf("Command timed out: %s\r\n", cmd); 
      return TIMEOUT; 
     } 
    } 
    timer_delay(100); // Let the rest of the response be received. 

    return OK; 
} 

int gsm_simpleCommand(const char * cmd) { 
    if (gsm_sendCommand(cmd) == TIMEOUT) 
     return TIMEOUT; 

    // Getting an ERROR response is quick, so if there is a response, this will be there 
    if (strstr(bf2, "ERROR") != NULL) 
     return ERROR; 

    // Sometimes the OK (meaning the command ran) can take a while 
    // As long as there wasn't an error, we can wait for the OK 
    while (strstr(bf2, "OK") == NULL); 
    return OK; 
} 

Ein einfacher Befehl ist jeder AT-Befehl, der speziell für OK oder ERROR in Antwort sucht so etwas wie AT Allerdings habe ich es auch wie AT+CPIN? für erweiterte Befehle verwenden, da es m eans Ich habe die ganze Antwort erfasst und kann weiter nach dersuchen. Nichts davon reagiert jedoch auf die unaufgeforderten Antworten. In der Tat wird die gsm_sendCommand() Funktion früh zurückkehren, wenn die unaufgeforderte Antwort empfangen wird.

Was für eine gute Möglichkeit, komplexe, gelegentlich unerwünschte Statusmeldungen wie diese zu verwalten? Bitte beachten Sie, dass diese Anwendung in C geschrieben ist und auf einem 8-Bit-Mikrocontroller läuft!

+1

Sie müssen wahrscheinlich eine Zustandsmaschine (FSM) implementieren: 'newstate = oldstate [message]', und vielleicht betrachten Sie das andere Ende auch als Zustandsmaschine. – wildplasser

+0

Das wird ein Teil davon sein, denke ich. Eine vollständige FSM scheint in diesem Fall jedoch nicht die beste Option zu sein. Ich muss den binären Zustand einiger unangeforderter Codes verfolgen und nicht die verschiedenen Zustände eines einzelnen Systems. Ich werde einfach ein paar globale boolesche Typen haben, um den Überblick zu behalten. – dantheman

Antwort

2

Es ist schwierig, sowohl nicht angeforderte Nachrichten als auch Antworten auf Anforderungen im selben Datenstrom zu verarbeiten, da Sie den eingehenden Datenstrom demultiplexen und die Ergebnisse an den entsprechenden Handler senden müssen. Es ist ein bisschen wie ein Interrupt-Handler, in dem Sie das, was Sie getan haben, fallen lassen und mit dieser anderen Information umgehen müssen, die Sie nicht unbedingt erwartet haben.

Einige Module haben einen sekundären seriellen Port, der auch für Nachrichten verwendet werden kann. Wenn dies möglich ist, könnten Sie unerwünschte Nachrichten nur an einem einzigen seriellen Port anzeigen, während der Hauptport für Ihre AT-Befehle vorgesehen ist. Dies ist möglicherweise nicht möglich, und einige GSM-Module unterstützen nicht den kompletten Befehlssatz an einem sekundären Port.

Vielleicht ist ein besserer Ansatz, einfach unerwünschte Nachrichten zu deaktivieren. Die meisten Befehle befehlen den gesamten Status. Wenn Sie zum Beispiel auf die Registrierung warten, müssen Sie nicht einfach auf eine unerwünschte Registrierungsnachricht warten, sondern einfach das Modul für den aktuellen Registrierungsstatus abfragen. Auf diese Weise haben Sie stets die Kontrolle und müssen nur die Antworten für den gerade gesendeten Befehl verarbeiten. Wenn Sie auf mehrere Ereignisse warten, können Sie für jedes Element nacheinander Schleifen abrufen. Dies macht den Code im Allgemeinen einfacher, da Sie jeweils nur eine Antwort bearbeiten müssen. Der Nachteil ist, dass Ihre Antwortzeiten durch Ihre Wahlrate begrenzt sind.

Wenn Sie mit dem Ansatz der unaufgeforderten Nachricht fortfahren, würde ich vorschlagen, eine kleine Warteschlange für unerwünschte Nachrichten zu implementieren. Warten Sie auf Antworten auf einen Befehl. Wenn die Antwort nicht mit dem Befehl übereinstimmt, drücken Sie einfach die Antwort in einer Warteschlange. Wenn Sie dann eine Antwort auf Ihren AT-Befehl erhalten haben oder eine Zeitüberschreitung aufgetreten ist, können Sie die unerwünschte Nachrichtenwarteschlange anschließend verarbeiten.

+0

Das klingt nach einer wirklich guten Möglichkeit zu gehen. Ich weiß mit diesem Modul, dass der sekundäre serielle Port nicht zum Senden von Befehlen geeignet ist. Bis jetzt habe ich wirklich nur 'GPS Ready' und' + CGREG: 1' Nachrichten gesehen. Ich weiß, dass du den CGREG deaktivieren kannst. Mein alter Code wurde verwendet, um abzufragen, und das war gut, weil es bedeutete, dass mein Code nicht darauf warten würde, wenn ich die unaufgeforderte Antwort verpasste. – dantheman

+1

Also, während ich nicht daran interessiert bin, eine Warteschlange als solche zu implementieren (eine ziemlich speicherbeschränkte Anwendung zu sein), ist die Deaktivierung der unerwünschten Antworten nicht vollständig möglich. Ich mag die Idee nicht, allen Befehlsfunktionen Verarbeitungsfähigkeiten hinzuzufügen, um die Möglichkeit der Unterbrechung zu berücksichtigen, so dass die Warteschlange viel mehr Sinn macht. Vielen Dank für Ihre Antwort! – dantheman

+1

@dantheman Hoffentlich kann Ihre Warteschlange klein sein. Sie könnten wahrscheinlich dafür sorgen, dass sich die Warteschlange auf dem Stapel befindet, wenn Sie möchten, dass Ihr 'gsm_sendCommand' zusätzliche Parameter für' char * buf' und 'size_t bufLen' enthält. Funktionen, die 'gsm_sendCommand' aufrufen, können einen temporären Puffer auf dem Stack zuweisen und nachdem 'gsm_sendCommand' zurückgegeben wurde, die Warteschlange verarbeiten. Viele Möglichkeiten, dies zu tun. –