10

私は GSM モデムを 2 つのうちの 1 つに使用するアプリケーションに取り組んできました。GET 要求をサーバーに送信するか、(UDP を使用して) サーバーにデータを送信することにより、組み込みの HTTP スタックを使用してステータスを確認します。これを可能な限り信頼できるものにするために、いくつかの異なる方法を試しましたが、ついに助けを求める準備が整いました。

私のアプリケーションは、SIMCOM908 モジュールと PIC18 プラットフォーム用に作成されています (開発には PIC18 Explorer を使用しています)。

そのため、問題は、モデムが何かをしているときにビジー状態になり、コマンドを見逃してしまうことがあります。人間として、私はそれを見て、コマンドを再送信します. MCU がタイムアウトして再送信するための機能を追加することは問題ではありません。

問題は、モデムがさまざまなイベントの後に未承諾の応答を送信することです。+CGREG: 1, ...モデムが (セル タワーで) 登録ステータスを変更すると、または GPS の準備ができたときに応答しGPS Readyます。これらの応答は、コマンドの途中 (IP 接続の作成など) を含め、いつでも発生する可能性があります。

これに対処する方法を考えていなかったので、これは問題です。私のアプリケーションはコマンドを送信する必要があります (たとえば、サーバーに接続するためAT+CIPSTART="UDP","example.com",5000)。このコマンドは「OK」で応答し、コマンドが完了すると「CONNECT OK」と応答します。ただし、他の多くの可能な応答に対応できるようにする必要があり、これを行う方法がわかりません。コードで何をする必要がありますか。モデムからの応答を待ち、応答を確認し、その応答に基づいてアクションを実行しますか?

私はコードに制限があり (8 ビットのマイクロコントローラーです!)、keep の繰り返しを最小限に抑えたいと考えています。GSM モジュールからの応答 (要求されたものまたは現在のもの) を取得し、プログラムの残りの部分に何が起こっているかを知らせる応答関数を作成するにはどうすればよいですか?

理想的には、それらの応答で何かをしたいと思います。内部状態を維持するのと同じように ( を聞くGPS Readyと、GPS などに電力を供給できることがわかります。

考えなければならないことがいくつかあるのでしょうか、それともこの問題をすでに解決しているオープンソース プロジェクトがあるのでしょうか?

これが私がこれまでに持っているものです:

/* 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;
}

単純なコマンドは、具体的に探している、OKまたはERROR応答している任意の AT コマンドです。のようなものAT。ただし、より高度なコマンドにも使用します。AT+CPIN?これは、応答全体をキャプチャし、+CPIN: READY. ただし、これらのいずれも、未承諾の応答に対する実際の応答ではありません。実際、gsm_sendCommand()未承諾の応答が受信されると、関数は早期に戻ります。

このような複雑で、場合によっては未承諾のステータス メッセージを管理するには、どのような良い方法があるでしょうか? このアプリケーションは C で書かれており、8 ビットのマイクロコントローラーで動作することに注意してください。

4

1 に答える 1

3

着信ストリームを逆多重化し、結果を適切なハンドラーにディスパッチする必要があるため、非請求メッセージと要求への応答の両方を同じデータ ストリームで処理するのは困難です。これは、実行していたことを破棄して、必ずしも予期していなかったこの別の情報を処理する必要があるという点で、割り込みハンドラーに少し似ています。

一部のモジュールには、メッセージにも使用できるセカンダリ シリアル ポートがあります。これが可能である場合、メイン ポートが AT コマンド用である間に、任意のメッセージを 1 つのシリアル ポートにのみ表示することができます。これは不可能な場合があり、一部の GSM モジュールはセカンダリ ポートで完全なコマンド セットをサポートしていません。

おそらく、より良いアプローチは、未承諾メッセージを無効にすることです。ほとんどのコマンドは、すべての状態を要求します。たとえば、登録を待っている間は、未承諾の登録メッセージが表示されるのを待つ代わりに、現在の登録状態についてモジュールをポーリングするだけです。これにより、常に制御できるようになり、送信したばかりのコマンドの応答を処理するだけで済みます。複数のイベントを待っている場合は、アイテムごとに順番にループでポーリングできます。これにより、一度に 1 つの応答を処理するだけで済むため、通常はコードが単純になります。欠点は、応答時間がポーリング レートによって制限されることです。

未承諾メッセージのアプローチを継続する場合は、未承諾メッセージ用の小さなキューを実装することをお勧めします。コマンドへの応答を待っているときに、応答がコマンドと一致しない場合は、応答をキューにプッシュします。次に、AT コマンドへの応答を受信したか、タイムアウトになったときに、非請求メッセージ キューを後で処理できます。

于 2013-02-03T11:56:16.403 に答える