This library code seems to be better than the worst that I saw at first glance, but it still has some problems. The most serious is the processing of the final result code.
The sim900_check_with_cmd function sim900_check_with_cmd conceptually exists, however just checking for OK not acceptable. He must check every possible final result code that the modem can send. From your output examples, you have the following end result codes
- Ok
- MISTAKE
- NO CARRIER
- NO ANSWERS
but there are a few more. You can see the atinout code for an example of the is_final_result_code function (you can also compare with isFinalResponseError and isFinalResponseSuccess 1 in the ST-Ericsson U300 RIL ).
Unconditional return true; at the end of GPRS::callUp is an error, but this may be deliberate due to a lack of ideas for implementing a better API so that the calling client can check the intermediate result codes. But this is the wrong way to do it. The library really has to make all the command line calls and process the final result without any exceptions. Just doing parts of this in the library and leaving some of them to the client is just a bad design.
When customers want to check or act on intermediate result codes or information text that is between the command line and the final result code, the right way to do this is to let the library βdefragmentβ everything that it receives from the modem into separate full lines and for everything, which is not the final result code, provide this to the client through a callback function.
The following is an incomplete update to my atinout program:
bool send_commandline( const char *cmdline, const char *prefix, void (*handler)(const char *response_line, void *ptr), void *ptr, FILE *modem) { int res; char response_line[1024]; DEBUG(DEBUG_MODEM_WRITE, ">%s\n", cmdline); res = fputs(cmdline, modem); if (res < 0) { error(ERR "failed to send '%s' to modem (res = %d)", cmdline, res); return false; } sleep_milliseconds(200); do { const char *line; line = fgets(response_line, (int)sizeof(response_line), modem); if (line == NULL) { error(ERR "EOF from modem"); return false; } DEBUG(DEBUG_MODEM_READ, "<%s\n", line); if (prefix[0] == '\0') { handler(response_line, ptr); } else if (STARTS_WITH(response_line, prefix)) { handler(response_line + strlen(prefix) + strlen(" "), ptr); } } while (! is_final_result(response_line)); return strcmp(response_line, "OK\r\n") == 0; }
You can use this as a basis for proper processing. If you want to get error answers from a function, add an additional callback argument and change to
success = strcmp(response_line, "OK\r\n") == 0; if (!success) { error_handler(response_line, ptr); } return success;
Tip. Read the entire chapter 5 in V.250 , it will teach you almost everything you need to know about command lines, result codes, and response handling. For example, so that the command line is also interrupted with \r rather than \r\n -
1 Note that CONNECT not the final result code, it is an intermediate result code, therefore the name isFinalResponseSuccess is strictly not 100% correct.