From 9c329270bd96e15fb2e84dad434ce793b6eebf6f Mon Sep 17 00:00:00 2001 From: Mateusz Lubecki Date: Sun, 11 Jun 2023 12:25:50 +0200 Subject: [PATCH] more reliable way of disconnecting tcp connection and establishing APRS-IS connection --- .cproject | 8 +- .settings/language.settings.xml | 4 +- src/aprsis.c | 33 ++++--- src/main.c | 4 +- src/packet_tx_handler.c | 3 + system/include/gsm/sim800_return_t.h | 27 +++--- system/include/gsm/sim800c_poolers.h | 2 +- system/include/gsm/sim800c_tcpip.h | 2 +- system/include/text.h | 125 +++++++++++++++++++++++++++ system/src/gsm/sim800c.c | 51 ++--------- system/src/gsm/sim800c_poolers.c | 13 ++- system/src/gsm/sim800c_tcpip.c | 122 ++++++++++++++++---------- 12 files changed, 263 insertions(+), 131 deletions(-) create mode 100644 system/include/text.h diff --git a/.cproject b/.cproject index e361735..f76a2de 100644 --- a/.cproject +++ b/.cproject @@ -14,7 +14,7 @@ - + - + @@ -495,7 +495,7 @@ - + diff --git a/.settings/language.settings.xml b/.settings/language.settings.xml index 0b32f64..0548b18 100644 --- a/.settings/language.settings.xml +++ b/.settings/language.settings.xml @@ -2,7 +2,7 @@ - + @@ -13,7 +13,7 @@ - + diff --git a/src/aprsis.c b/src/aprsis.c index 7194a71..029b749 100644 --- a/src/aprsis.c +++ b/src/aprsis.c @@ -7,6 +7,9 @@ #include "aprsis.h" #include "main.h" +#include "text.h" + +#include "gsm/sim800c.h" #include #include @@ -120,12 +123,15 @@ aprsis_return_t aprsis_connect_and_login(const char * address, uint8_t address_l int8_t retval = 0xFF; - uint8_t offset = 0; + int offset = 0; memset(port_str, 0x00, 0x6); snprintf(port_str, 6, "%d", port); + // result of a disconnecting from APRS-IS server + sim800_return_t disconnection_result = SIM800_UNSET; + // connecting has blocking I/O retval = gsm_sim800_tcpip_connect(address, address_ln, port_str, 0x6, aprsis_serial_port, aprsis_gsm_modem_state); @@ -137,8 +143,12 @@ aprsis_return_t aprsis_connect_and_login(const char * address, uint8_t address_l if (retval == 0) { receive_buff = srl_get_rx_buffer(aprsis_serial_port); + // check if receive buffer starts from printable character and needs fast forward or not + // maybe APRS-IS put a newline before hello message + offset = text_fast_forward_to_first_printable((char*)receive_buff, srl_get_num_bytes_rxed(aprsis_serial_port)); + // if hello message has been received - if (*receive_buff == '#' && *(receive_buff + 1) == ' ') { + if (offset >= 0 && (*(receive_buff + offset) == '#' && *(receive_buff + offset + 1) == ' ')) { // send long string to server gsm_sim800_tcpip_write((uint8_t *)aprsis_login_string, strlen(aprsis_login_string), aprsis_serial_port, aprsis_gsm_modem_state); @@ -150,12 +160,8 @@ aprsis_return_t aprsis_connect_and_login(const char * address, uint8_t address_l aprsis_connected = 1; - // fast forward to beginning of response - for (offset = 0; offset < 8; offset++) { - if (*(receive_buff + offset) == '#') { - break; - } - } + // fast forward to the beginning of a response + offset = text_fast_forward_to_first_printable((char*)receive_buff, srl_get_num_bytes_rxed(aprsis_serial_port)); // check if authorization has been successfull retval = strncmp(aprsis_sucessfull_login, (const char * )(receive_buff + offset), (size_t)9); @@ -180,18 +186,23 @@ aprsis_return_t aprsis_connect_and_login(const char * address, uint8_t address_l } else { // if authoruzation wasn't successfull drop a connection - gsm_sim800_tcpip_close(aprsis_serial_port, aprsis_gsm_modem_state, 0); + disconnection_result = gsm_sim800_tcpip_close(aprsis_serial_port, aprsis_gsm_modem_state, 0); } } } else { - gsm_sim800_tcpip_close(aprsis_serial_port, aprsis_gsm_modem_state, 0); + disconnection_result = gsm_sim800_tcpip_close(aprsis_serial_port, aprsis_gsm_modem_state, 0); } } else { - gsm_sim800_tcpip_close(aprsis_serial_port, aprsis_gsm_modem_state, 1); + disconnection_result = gsm_sim800_tcpip_close(aprsis_serial_port, aprsis_gsm_modem_state, 1); } } + + // if a connection has been ordered to close, but there were severe errors during that + if (disconnection_result == SIM800_TCP_CLOSE_UNCERTAIN || disconnection_result == SIM800_RECEIVING_TIMEOUT) { + gsm_sim800_reset(aprsis_gsm_modem_state); + } } return out; diff --git a/src/main.c b/src/main.c index 64da8ab..a8916ac 100644 --- a/src/main.c +++ b/src/main.c @@ -1411,8 +1411,6 @@ int main(int argc, char* argv[]){ NVIC_SystemReset(); } - gsm_sim800_poolers_one_minute(main_gsm_srl_ctx_ptr, &main_gsm_state); - //aprsis_connect_and_login_default(1); // if (gsm_sim800_gprs_ready == 1) { @@ -1547,6 +1545,8 @@ int main(int argc, char* argv[]){ #ifdef STM32L471xx if (main_config_data_mode->gsm == 1) { + gsm_sim800_poolers_ten_seconds(main_gsm_srl_ctx_ptr, &main_gsm_state); + packet_tx_tcp_handler(); } #endif diff --git a/src/packet_tx_handler.c b/src/packet_tx_handler.c index 7290520..062ad7a 100644 --- a/src/packet_tx_handler.c +++ b/src/packet_tx_handler.c @@ -271,6 +271,9 @@ void packet_tx_handler(const config_data_basic_t * const config_basic, const con // and trigger API wx packet transmission packet_tx_trigger_tcp |= API_TRIGGER_METEO; } + else if (main_config_data_gsm->aprsis_enable == 1 && main_config_data_gsm->api_enable == 0) { + packet_tx_trigger_tcp |= APRSIS_TRIGGER_METEO; + } else { packet_tx_trigger_tcp = 0; } diff --git a/system/include/gsm/sim800_return_t.h b/system/include/gsm/sim800_return_t.h index 4adb89e..1165470 100644 --- a/system/include/gsm/sim800_return_t.h +++ b/system/include/gsm/sim800_return_t.h @@ -8,19 +8,26 @@ #ifndef INCLUDE_GSM_SIM800_RETURN_T_H_ #define INCLUDE_GSM_SIM800_RETURN_T_H_ +/** + * Possible return values from any SIM800 GPRS module related function + */ typedef enum sim800_return_t { - SIM800_OK = 0, - SIM800_RX_TERMINATED = 1, - SIM800_WRONG_STATE_TO_RX = 100, - SIM800_WRONG_STATE_TO_TX = 101, - SIM800_WRONG_STATE_TO_CONNECT = 102, - SIM800_ADDRESS_AND_PORT_TO_LONG = 103, - SIM800_CONNECTING_FAILED = 104, - SIM800_RECEIVING_TIMEOUT = 105, - SIM800_SEND_FAILED = 106, + SIM800_OK = 0, /**< SIM800_OK */ + SIM800_RX_TERMINATED = 1, /**< SIM800_RX_TERMINATED */ + SIM800_WRONG_STATE_TO_RX = 100, /**< SIM800_WRONG_STATE_TO_RX */ + SIM800_WRONG_STATE_TO_TX = 101, /**< SIM800_WRONG_STATE_TO_TX */ + SIM800_WRONG_STATE_TO_CONNECT = 102, /**< SIM800_WRONG_STATE_TO_CONNECT */ + SIM800_WRONG_STATE_TO_CLOSE = 103, /**< SIM800_WRONG_STATE_TO_CLOSE */ + SIM800_ADDRESS_AND_PORT_TO_LONG = 104, /**< SIM800_ADDRESS_AND_PORT_TO_LONG */ + SIM800_CONNECTING_FAILED = 105, /**< SIM800_CONNECTING_FAILED */ + SIM800_RECEIVING_TIMEOUT = 106, /**< SIM800_RECEIVING_TIMEOUT Timeout during waiting for GPRS module response, if TCP connection is established + in the transparent mode this might be also caused by no response from remote server */ + SIM800_SEND_FAILED = 107, /**< SIM800_SEND_FAILED */ + SIM800_TCP_CLOSE_UNCERTAIN = 108, /**< SIM800_TCP_CLOSE_UNCERTAIN */ + SIM800_TCP_CLOSE_ALREADY = 109, /**< SIM800_TCP_CLOSE_ALREADY */ - SIM800_UNSET = -1 + SIM800_UNSET = -1 /**< SIM800_UNSET */ } sim800_return_t; diff --git a/system/include/gsm/sim800c_poolers.h b/system/include/gsm/sim800c_poolers.h index 5a477cf..4bd07dc 100644 --- a/system/include/gsm/sim800c_poolers.h +++ b/system/include/gsm/sim800c_poolers.h @@ -12,7 +12,7 @@ #include "gsm/sim800_state_t.h" #include "config_data.h" -void gsm_sim800_poolers_one_minute(srl_context_t * srl_context, gsm_sim800_state_t * state); +void gsm_sim800_poolers_ten_seconds(srl_context_t * srl_context, gsm_sim800_state_t * state); void gsm_sim800_poolers_one_second(srl_context_t * srl_context, gsm_sim800_state_t * state, const config_data_gsm_t * config); #endif /* INCLUDE_GSM_SIM800C_POOLERS_H_ */ diff --git a/system/include/gsm/sim800c_tcpip.h b/system/include/gsm/sim800c_tcpip.h index ad635bd..e6b81c2 100644 --- a/system/include/gsm/sim800c_tcpip.h +++ b/system/include/gsm/sim800c_tcpip.h @@ -29,7 +29,7 @@ sim800_return_t gsm_sim800_tcpip_async_receive(srl_context_t * srl_context, gsm_ sim800_return_t gsm_sim800_tcpip_receive(uint8_t * buffer, uint16_t buffer_size, srl_context_t * srl_context, gsm_sim800_state_t * state, srl_rx_termination_callback_t rx_callback, uint32_t timeout); sim800_return_t gsm_sim800_tcpip_async_write(uint8_t * data, uint16_t data_len, srl_context_t * srl_context, gsm_sim800_state_t * state); sim800_return_t gsm_sim800_tcpip_write(uint8_t * data, uint16_t data_len, srl_context_t * srl_context, gsm_sim800_state_t * state); -void gsm_sim800_tcpip_close(srl_context_t * srl_context, gsm_sim800_state_t * state, uint8_t force); +sim800_return_t gsm_sim800_tcpip_close(srl_context_t * srl_context, gsm_sim800_state_t * state, uint8_t force); void gsm_sim800_tcpip_rx_done_callback(srl_context_t * srl_context, gsm_sim800_state_t * state); void gsm_sim800_tcpip_tx_done_callback(srl_context_t * srl_context, gsm_sim800_state_t * state); diff --git a/system/include/text.h b/system/include/text.h new file mode 100644 index 0000000..6a0a80a --- /dev/null +++ b/system/include/text.h @@ -0,0 +1,125 @@ +/* + * text.h + * + * Auxiliary functions to do weird things with text strings + * + * Created on: Jun 10, 2023 + * Author: mateusz + */ + +#ifndef INCLUDE_TEXT_H_ +#define INCLUDE_TEXT_H_ + +#include + +/** + * Replace all non printable TABs, NEWLINEs etc with a space. Stops on null terminator + * or a size of an input string + * @param str pointer to a string to be modified + * @param size its size + */ +inline static void text_replace_non_printable_with_space(char * str, uint16_t size) { + for (int i = 0; i < size; i++) { + // currently processed character + char current = *(str + i); + + if (current != 0x00) { + if (current < 0x21 || current > 0x7A) { + *(str + i) = ' '; + } + } + else { + // stop processing on null terminator + break; + } + } +} + +inline static void text_replace_space_with_null(char * str, uint16_t size) { + + // it goes from the end of a buffer towards its begining + for (int i = size - 1; i > 0; i--) { + char current = *(str + i); + + if (current == '\"') { + // also replace this with null terminator + *(str + i) = 0x00; + break; + } + + if (current == 0x20) { + *(str + i) = 0x00; + } + } +} + +/** + * Fast forward text string to first printable character if it not begin from it. + * NULL terminator ends processing + * @param str pointer to string to process + * @param size lenght of a text although if null terminator will be detected before + * processing will finish before reaching this size. + * @return an offset from the beginning of the text where first printable character is. + * if the text starts from printable character zero is returned. + * if null is detected before first printable character negative is returned. + */ +inline static int text_fast_forward_to_first_printable(char * str, uint16_t size) { + + int out = 0; + + // check if input pointer is set to something + if (str != 0) { + + while (*(str + out) < 0x21 || *(str + out) > 0x7F) { + + // if null terminator is detected before a printable character + if (*(str + out) == 0x00) { + out = -1; + + break; + } + + // the same if an end of string is reached + if (out >= size) { + out = -1; + + break; + } + + // move iterator forward + out++; + } + } + + return out; +} + +inline static int text_rewind_front_end_till_first_printable(char * str, uint16_t size) { + + int out = size; + + if (str != 0) { + + while (*(str + out) < 0x21 || *(str + out) > 0x7F) { + // end and return if a begining of a text is reached + // and no printable character is found + if (out < 0) { + break; + } + + // if null terminator is detected before a printable character + if (*(str + out) == 0x00) { + out = -1; + + break; + } + + // move iterator forward + out--; + } + } + + return out; +} + +#endif /* INCLUDE_TEXT_H_ */ diff --git a/system/src/gsm/sim800c.c b/system/src/gsm/sim800c.c index b997358..4e0cf61 100644 --- a/system/src/gsm/sim800c.c +++ b/system/src/gsm/sim800c.c @@ -18,6 +18,8 @@ #include "main.h" #include "io.h" +#include "text.h" + #include #include @@ -95,47 +97,6 @@ char gsm_sim800_cellid[5] = {0, 0, 0, 0, 0}; char gsm_sim800_lac[5] = {0, 0, 0, 0, 0}; -/** - * Replace all non printable TABs, NEWLINEs etc with a space. Stops on null terminator - * or a size of an input string - * @param str pointer to a string to be modified - * @param size its size - */ -inline static void gsm_sim800_replace_non_printable_with_space(char * str, int8_t size) { - for (int i = 0; i < size; i++) { - // currently processed character - char current = *(str + i); - - if (current != 0x00) { - if (current < 0x21 || current > 0x7A) { - *(str + i) = ' '; - } - } - else { - // stop processing on null terminator - break; - } - } -} - -inline static void gsm_sim800_replace_space_with_null(char * str, int8_t size) { - - // it goes from the end of a buffer towards its begining - for (int i = size - 1; i > 0; i--) { - char current = *(str + i); - - if (current == '\"') { - // also replace this with null terminator - *(str + i) = 0x00; - break; - } - - if (current == 0x20) { - *(str + i) = 0x00; - } - } -} - inline static void gsm_sim800_power_off(void) { io___cntrl_vbat_g_disable(); } @@ -777,9 +738,9 @@ void gsm_sim800_rx_done_event_handler(srl_context_t * srl_context, gsm_sim800_st if (comparision_result == 0) { strncpy(gsm_sim800_simcard_status_string, (const char *)(srl_context->srl_rx_buf_pointer + gsm_response_start_idx + 7), 10); - gsm_sim800_replace_non_printable_with_space(gsm_sim800_simcard_status_string, SIM_STATUS_LENGHT); + text_replace_non_printable_with_space(gsm_sim800_simcard_status_string, SIM_STATUS_LENGHT); - gsm_sim800_replace_space_with_null(gsm_sim800_simcard_status_string, SIM_STATUS_LENGHT); + text_replace_space_with_null(gsm_sim800_simcard_status_string, SIM_STATUS_LENGHT); gsm_sim800_simcard_status = SIMCARD_READY; } @@ -809,9 +770,9 @@ void gsm_sim800_rx_done_event_handler(srl_context_t * srl_context, gsm_sim800_st strncpy(gsm_sim800_registered_network, (const char *)(srl_context->srl_rx_buf_pointer + gsm_response_start_idx + 12), 16); - gsm_sim800_replace_non_printable_with_space(gsm_sim800_registered_network, REGISTERED_NETWORK_LN); + text_replace_non_printable_with_space(gsm_sim800_registered_network, REGISTERED_NETWORK_LN); - gsm_sim800_replace_space_with_null(gsm_sim800_registered_network, REGISTERED_NETWORK_LN); + text_replace_space_with_null(gsm_sim800_registered_network, REGISTERED_NETWORK_LN); } } diff --git a/system/src/gsm/sim800c_poolers.c b/system/src/gsm/sim800c_poolers.c index 9920b44..0d1e4bd 100644 --- a/system/src/gsm/sim800c_poolers.c +++ b/system/src/gsm/sim800c_poolers.c @@ -16,8 +16,13 @@ uint8_t sim800_poolers_five = 3; -void gsm_sim800_poolers_one_minute(srl_context_t * srl_context, gsm_sim800_state_t * state){ +void gsm_sim800_poolers_ten_seconds(srl_context_t * srl_context, gsm_sim800_state_t * state){ + if ( gsm_sim800_engineering_is_enabled == 0 && + gsm_sim800_gprs_ready == 1 && + aprsis_connected == 0) { + aprsis_connect_and_login_default(1); + } // gsm_sim800_tcpip_connect(TEST_IP, strlen(TEST_IP), TEST_PORT, strlen(TEST_PORT), srl_context, state); // //gsm_sim800_engineering_enable(srl_context, state); @@ -45,12 +50,6 @@ void gsm_sim800_poolers_one_second(srl_context_t * srl_context, gsm_sim800_state return; } - - if ( gsm_sim800_engineering_is_enabled == 0 && - gsm_sim800_gprs_ready == 1 && - aprsis_connected == 0) { - aprsis_connect_and_login_default(1); - } } } diff --git a/system/src/gsm/sim800c_tcpip.c b/system/src/gsm/sim800c_tcpip.c index 00c07e4..d0a6922 100644 --- a/system/src/gsm/sim800c_tcpip.c +++ b/system/src/gsm/sim800c_tcpip.c @@ -5,6 +5,7 @@ #include "main.h" #include "delay.h" #include "io.h" +#include "text.h" #include @@ -15,12 +16,13 @@ const static char * QUOTATION_MARK = "\"\0"; const static char * NEWLINE = "\r\0"; const static char * CLOSE_TCP = "AT+CIPCLOSE\r\0"; - -//static const char * ESCAPE = "+++\0"; +#define CLOSED_TCP_LN 8 +const static char * CLOSED_TCP = "CLOSE OK\0"; +#define CLOSED_ERROR_LN 5 +const static char * CLOSED_ERROR = "ERROR\0"; #define CONNECT_LN 13 static const char * CONNECT = "OK\r\n\r\nCONNECT\0"; -//static const char * OK = "OK\0"; #define DISCONNECTED_LN 6 static const char * DISCONNECTED = "CLOSED\0"; @@ -182,7 +184,7 @@ sim800_return_t gsm_sim800_tcpip_async_receive(srl_context_t * srl_context, gsm_ } // check if library is in state when reception could be done - if (state == SIM800_TCP_CONNECTED || gsm_sim800_tcpip_receiving == 0) { + if (*state == SIM800_TCP_CONNECTED || gsm_sim800_tcpip_receiving == 0) { gsm_sim800_tcpip_async_receive_cbk = rx_done_callback; @@ -242,7 +244,6 @@ sim800_return_t gsm_sim800_tcpip_receive(uint8_t * buffer, uint16_t buffer_size, } return out; -// return waiting_result; } sim800_return_t gsm_sim800_tcpip_async_write(uint8_t * data, uint16_t data_len, srl_context_t * srl_context, gsm_sim800_state_t * state) { @@ -285,51 +286,33 @@ sim800_return_t gsm_sim800_tcpip_write(uint8_t * data, uint16_t data_len, srl_co return out; } -void gsm_sim800_tcpip_close(srl_context_t * srl_context, gsm_sim800_state_t * state, uint8_t force) { +/** + * Closes established TCP connection + * @param srl_context pointer to serial context used to communication with gprs module + * @param state + * @param force force changing internal connection state even if there + * were problems with a response to diconnection AT command. + * @return SIM800_OK connection was closed successfully + * SIM800_TCP_CLOSE_ALREADY connection has been closed in the meantime by remote server + * SIM800_TCP_CLOSE_UNCERTAIN no valid response was received from gprs module on disconnect request + * SIM800_WRONG_STATE_TO_CLOSE no connection has been + */ +sim800_return_t gsm_sim800_tcpip_close(srl_context_t * srl_context, gsm_sim800_state_t * state, uint8_t force) { + + /** + * Name : srl_rx_buf_pointer + Details:0x20000828 "AT+CIPCLOSE\r\r\nERROR\r\n" + * + *Name : srl_rx_buf_pointer + Details:0x20000828 "AT+CIPCLOSE\r\r\nCLOSE OK" + * + */ + + sim800_return_t out = SIM800_UNSET; uint8_t receive_result = 0; - if (*state == SIM800_TCP_CONNECTED || force == 1) { - -// do { -// // set default timeout of 1200msec -// srl_switch_timeout(srl_context, SRL_TIMEOUT_ENABLE, 2222); -// -// // send escape sequence to exit connection mode -// srl_send_data(srl_context, (const uint8_t*) ESCAPE, SRL_MODE_ZERO, strlen(ESCAPE), SRL_INTERNAL); -// -// // wait for transmission to finish -// srl_wait_for_tx_completion(srl_context); -// -// // wait for OK to be received -// srl_receive_data(srl_context, 4, SRL_NO_START_CHR, SRL_NO_STOP_CHR, SRL_ECHO_DISABLE, 0x7F, 0); -// -// // start timeout calculation -// srl_switch_timeout_for_waiting(srl_context, SRL_TIMEOUT_ENABLE); -// -// // wait for it to finish -// srl_wait_for_rx_completion_or_timeout(srl_context, & receive_result); -// -// // check if we escaped from data mode -// if (strncmp((const char *) (srl_context->srl_rx_buf_pointer), NEWLINE, 1) == 0) { -// break; -// } -// else if (strncmp((const char *) (srl_context->srl_rx_buf_pointer), OK, 2) == 0) { -// break; -// } -// else if (strncmp((const char *) (srl_context->srl_rx_buf_pointer), ESCAPE, 3) == 0) { -// // if module has already returned to command mode it will echo all input -// break; -// } -// else { -// if (receive_result == SRL_OK) { -// delay_fixed(200); -// -// } -// } -// -// -// } while(escape_counter++ < 3); + if (*state == SIM800_TCP_CONNECTED) { io___cntrl_gprs_dtr_low(); @@ -356,11 +339,54 @@ void gsm_sim800_tcpip_close(srl_context_t * srl_context, gsm_sim800_state_t * st // wait for it to finish srl_wait_for_rx_completion_or_timeout(srl_context, & receive_result); - if (receive_result == SRL_OK) { + // if force is set to one ignore a result and just set the state + // to alive, assuming that connection was closed + if (force == 1) { *state = SIM800_ALIVE; + + out = SIM800_OK; + } + else { + if (receive_result == SRL_OK) { + + // go back to the last character in case that they are some newlines after response + const int offset = text_rewind_front_end_till_first_printable((char*)srl_get_rx_buffer(srl_context), srl_get_num_bytes_rxed(srl_context)); + + int result = strncmp((char*)srl_get_rx_buffer(srl_context) + offset - CLOSED_TCP_LN, CLOSED_TCP, CLOSED_TCP_LN); + + // connection was closed successfully + if (result == 0) { + out = SIM800_OK; + } + else { + // if not check if it is maybe already closed and gprs module returned ERROR + result = strncmp((char*)srl_get_rx_buffer(srl_context) + offset - CLOSED_ERROR_LN, CLOSED_ERROR, CLOSED_ERROR_LN); + + if (result == 0) { + out = SIM800_TCP_CLOSE_ALREADY; + } + else { + // something weird happened + out = SIM800_TCP_CLOSE_UNCERTAIN; + } + } + + *state = SIM800_ALIVE; + } + else { + // something weird happened + out = SIM800_RECEIVING_TIMEOUT; + } } + + } + else { + out = SIM800_WRONG_STATE_TO_CLOSE; + } + + return out; } void gsm_sim800_tcpip_rx_done_callback(srl_context_t * srl_context, gsm_sim800_state_t * state) {