2013-02-03 25 views
10

Pracuję nad aplikacją, która używa modemu GSM do jednej z dwóch rzeczy; sprawdź jego status za pomocą wbudowanego stosu HTTP, wysyłając żądanie GET do serwera lub wysyłając dane do serwera (przy użyciu protokołu UDP). Wypróbowałem kilka różnych metod, aby było to tak wiarygodne, jak to tylko możliwe, a na koniec jestem gotów poprosić o pomoc.Zapisywanie sterownika modemu GSM?

Moja aplikacja napisana jest dla modułu SIMCOM908 i platformy PIC18 (do projektowania używam Eksploratora PIC18).

Problem polega więc na tym, że modem jest zajęty robieniem czegoś i pomija polecenie. Jako człowiek, zobaczyłbym to i po prostu ponownie wysłałem polecenie. Dodanie obiektu do MCU do limitu czasu i ponowne wysłanie nie jest problemem.

Problem polega na tym, że modem wysyła niezamawiane odpowiedzi po różnych zdarzeniach. Gdy modem zmieni status rejestracji (z wieżą komórki), odpowie: +CGREG: 1, ... lub gdy GPS będzie gotowy GPS Ready. Odpowiedzi te mogą się zdarzyć w dowolnym czasie, w tym w środku polecenia (np. Tworzenie połączenia IP).

To jest problem, ponieważ nie wymyśliłem sposobu, aby sobie z tym poradzić. Moja aplikacja musi wysłać polecenie (aby połączyć się z serwerem, na przykład, AT+CIPSTART="UDP","example.com",5000) To polecenie odpowie "OK", a następnie po zakończeniu polecenia "CONNECT OK". Jednak muszę być w stanie reagować na wiele innych możliwych reakcji i nie znalazłem sposobu na zrobienie tego. Co muszę zrobić z moim kodem; czekać na odpowiedź z modemu, sprawdzić odpowiedź, wykonać akcję na podstawie tej odpowiedzi?

Mam ograniczony kod (jako 8-bitowy mikrokontroler!) I chciałbym, aby powtarzanie było minimalne. Jak mogę napisać funkcję odpowiedzi, która przyjmie odpowiedź z modułu GSM (zamówiona lub teraz), a następnie niech reszta mojego programu wie, co się dzieje?

Idealnie, chciałbym zrobić coś z tymi odpowiedziami. Jak zachować wewnętrzny stan (kiedy słyszę GPS Ready, wiem, że mogę zasilać GPS itp

Być może istnieją pewne rzeczy, mam o tym myśleć, czy może jest projektem open source, które już rozwiązuje ten problem?

Oto co mam do tej pory..

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

prosta komenda ma żadnych komend AT, która jest specjalnie szuka OK lub ERROR w odpowiedzi Coś AT jednak ja również użyć go do bardziej zaawansowanych poleceń jak AT+CPIN? ponieważ to m eScale złapię całą odpowiedź i mogę dalej szukać +CPIN: READY. Jednak żadna z tych faktycznych odpowiedzi na niechciane odpowiedzi. W rzeczywistości funkcja gsm_sendCommand() powróci wcześniej, gdy otrzyma niezamawianą odpowiedź.

Co to jest dobry sposób na zarządzanie złożonymi, czasami niezamawianymi wiadomościami o statusie? Proszę zauważyć, że ta aplikacja jest napisana w języku C i działa na mikrokontroleru 8-bitowym!

+1

Prawdopodobnie musisz zaimplementować automat stanów (FSM): 'newstate = oldstate [message]', i może uznać drugi koniec za stanowy. – wildplasser

+0

To będzie część tego, jak myślę. Jednak pełny FSM w tym przypadku nie wydaje się najlepszą opcją. Muszę śledzić stan binarny kilku różnych niezamówionych kodów, a nie wielu stanów pojedynczego systemu. Po prostu będę mieć kilka globalnych typów boolowskich do śledzenia. – dantheman

Odpowiedz

2

Obsługa zarówno niezamówionych wiadomości, jak i odpowiedzi na żądania w tym samym strumieniu danych jest trudna, ponieważ trzeba zdemultipleksować strumień przychodzący i wysłać wyniki do odpowiedniego programu obsługi. To trochę tak, jak obsługa przerwań, że musisz rzucić to, co robiłeś i poradzić sobie z tą inną informacją, której nie oczekiwałeś.

Niektóre moduły mają dodatkowy port szeregowy, który może być również używany do wiadomości. Jeśli jest to możliwe, możesz wyświetlać niechciane wiadomości tylko na jednym porcie szeregowym, podczas gdy główny port służy do poleceń AT. To może nie być możliwe, a niektóre moduły GSM nie obsługują kompletnego zestawu poleceń na porcie drugorzędnym.

Być może lepszym rozwiązaniem jest po prostu wyłączenie niechcianych wiadomości. Większość poleceń wymaga podania całego stanu. np. Podczas oczekiwania na rejestrację, zamiast czekać na pojawienie się niezamówionego komunikatu rejestracyjnego, po prostu odpytuj moduł dla bieżącego stanu rejestracji. Dzięki temu możesz zawsze mieć kontrolę i musisz tylko obsługiwać odpowiedzi dla właśnie wysłanej komendy. Jeśli czekasz na wiele wydarzeń, możesz sondować w pętli dla każdego elementu po kolei. Dzięki temu kod stanie się prostszy, ponieważ będziesz musiał obsługiwać tylko jedną odpowiedź naraz. Wadą jest to, że twoje czasy reakcji są ograniczone przez twoją stawkę odpytywania.

Jeśli nadal używasz niezapowiedzianej metody przesyłania komunikatów, proponuję zaimplementować małą kolejkę dla niechcianych wiadomości. Podczas oczekiwania na odpowiedzi na polecenie, jeśli odpowiedź nie jest zgodna z poleceniem, wystarczy nacisnąć odpowiedź w kolejce. Następnie, po otrzymaniu odpowiedzi na polecenie AT lub przekroczeniu limitu czasu, można przetworzyć niechcianą kolejkę komunikatów.

+0

To brzmi jak naprawdę świetna droga. Z tego modułu wiem, że dodatkowy port szeregowy nie nadaje się do wysyłania poleceń. Jak dotąd, widziałem tylko wiadomości "GPS Ready" i "+ CGREG: 1". Wiem, że możesz wyłączyć CGREG. Mój stary kod służył do odpytywania, a to było dobre, ponieważ oznaczało to, że gdybym przeoczył niechcianą odpowiedź, mój kod nadal by na nie nie czekał. – dantheman

+1

Tak więc, chociaż nie jestem entuzjastycznie nastawiony do realizacji kolejki jako takiej (jako aplikacja o ograniczonej pamięci), wyłączenie niechcianych odpowiedzi nie jest całkowicie możliwe. Nie podoba mi się pomysł dodania możliwości przetwarzania do wszystkich funkcji poleceń, aby uwzględnić możliwość przerwania, więc kolejka ma dużo więcej sensu. Dziękuję za Twoją odpowiedź! – dantheman

+1

@dantheman Mam nadzieję, że twoja kolejka może być mała. Prawdopodobnie możesz ustawić kolejkę na stosie, jeśli chcesz, aby 'gsm_sendCommand' wziął dodatkową parę parametrów dla' char * buf' i 'size_t bufLen'. Funkcje, które wywołują 'gsm_sendCommand' mogą przydzielić tymczasowy bufor na stosie i po zwróceniu' gsm_sendCommand', przetworzyć kolejkę. Wiele sposobów na zrobienie tego. –

Powiązane problemy