static int telit2_socket_close(struct cellular *modem, int connid) { at_set_timeout(modem->at, 150); at_command_simple(modem->at, "AT#SH=%d", connid); return 0; }
static int telit2_locate(struct cellular *modem, float *latitude, float *longitude, float *altitude) { struct cellular_telit2 *priv = (struct cellular_telit2 *) modem; priv->locate_status = -1; at_set_timeout(modem->at, 150); cellular_command_simple_pdp(modem, "AT#AGPSSND"); for (int i=0; i<TELIT2_LOCATE_TIMEOUT; i++) { sleep(1); if (priv->locate_status == 200) { *latitude = priv->latitude; *longitude = priv->longitude; *altitude = priv->altitude; return 0; } if (priv->locate_status != -1) { errno = ECONNABORTED; return -1; } } errno = ETIMEDOUT; return -1; }
static int telit2_ftp_close(struct cellular *modem) { at_set_timeout(modem->at, 90); at_command_simple(modem->at, "AT#FTPCLOSE"); return 0; }
/** * SIM800 IP configuration commands fail if the IP application is running, * even though the configuration settings are already right. The following * monkey dance is therefore needed. */ static int sim800_config(struct cellular *modem, const char *option, const char *value, int attempts) { at_set_timeout(modem->at, 10); for (int i=0; i<attempts; i++) { /* Blindly try to set the configuration option. */ at_command(modem->at, "AT+%s=%s", option, value); /* Query the setting status. */ const char *response = at_command(modem->at, "AT+%s?", option); /* Bail out on timeouts. */ if (response == NULL) return -1; /* Check if the setting has the correct value. */ char expected[16]; if (snprintf(expected, sizeof(expected), "+%s: %s", option, value) >= (int) sizeof(expected)) { return -1; } if (!strcmp(response, expected)) return 0; vTaskDelay(pdMS_TO_TICKS(1000)); } return -1; }
static int telit2_pdp_close(struct cellular *modem) { at_set_timeout(modem->at, 150); at_command_simple(modem->at, "AT#SGACT=1,0"); return 0; }
static int telit2_socket_waitack(struct cellular *modem, int connid) { const char *response; at_set_timeout(modem->at, 5); for (int i=0; i<TELIT2_WAITACK_TIMEOUT; i++) { /* Read number of bytes waiting. */ int ack_waiting; response = at_command(modem->at, "AT#SI=%d", connid); at_simple_scanf(response, "#SI: %*d,%*d,%*d,%*d,%d", &ack_waiting); /* ack_waiting is meaningless if socket is not connected. Check this. */ int socket_status; response = at_command(modem->at, "AT#SS=%d", connid); at_simple_scanf(response, "#SS: %*d,%d", &socket_status); if (socket_status == 0) { errno = ECONNRESET; return -1; } /* Return if all bytes were acknowledged. */ if (ack_waiting == 0) return 0; sleep(1); } errno = ETIMEDOUT; return -1; }
static ssize_t sim800_socket_send(struct cellular *modem, int connid, const void *buffer, size_t amount, int flags) { struct cellular_sim800 *priv = (struct cellular_sim800 *) modem; (void) flags; if(connid == SIM800_NSOCKETS) { if(priv->spp_status != SIM800_SOCKET_STATUS_CONNECTED) { return -1; } if(amount > 1024) { return -1; } /* Request transmission. */ at_send_raw(modem->at, buffer, amount); return amount; } else if(connid < SIM800_NSOCKETS) { if(priv->socket_status[connid] != SIM800_SOCKET_STATUS_CONNECTED) { return -1; } amount = amount > 1460 ? 1460 : amount; /* Request transmission. */ at_set_timeout(modem->at, SET_TIMEOUT); at_expect_dataprompt(modem->at); at_command_simple(modem->at, "AT+CIPSEND=%d,%zu", connid, amount); /* Send raw data. */ at_set_command_scanner(modem->at, scanner_cipsend); at_command_raw_simple(modem->at, buffer, amount); } else { return 0; } return amount; }
static int sim800_socket_connect(struct cellular *modem, int connid, const char *host, uint16_t port) { struct cellular_sim800 *priv = (struct cellular_sim800 *) modem; if(connid == SIM800_NSOCKETS) { return !(SIM800_SOCKET_STATUS_CONNECTED == priv->spp_status); } else if(connid < SIM800_NSOCKETS) { /* Send connection request. */ at_set_timeout(modem->at, SET_TIMEOUT); priv->socket_status[connid] = SIM800_SOCKET_STATUS_UNKNOWN; cellular_command_simple_pdp(modem, "AT+CIPSTART=%d,TCP,\"%s\",%d", connid, host, port); /* Wait for socket status URC. */ for (int i=0; i<SIM800_CONNECT_TIMEOUT; i++) { if (priv->socket_status[connid] == SIM800_SOCKET_STATUS_CONNECTED) { return 0; } else if (priv->socket_status[connid] == SIM800_SOCKET_STATUS_ERROR) { return -1; } vTaskDelay(pdMS_TO_TICKS(1000)); } } return -1; }
static int sim800_pdp_open(struct cellular *modem, const char *apn) { at_set_timeout(modem->at, SET_TIMEOUT); /* Configure and open context for FTP/HTTP applications. */ at_command_simple(modem->at, "AT+SAPBR=3,1,APN,\"%s\"", apn); at_command(modem->at, "AT+SAPBR=1,1"); /* Skip the configuration if context is already open. */ if (sim800_ipstatus(modem) == 0) return 0; /* Commands below don't check the response. This is intentional; instead * of trying to stay in sync with the GPRS state machine we blindly issue * the command sequence needed to transition through all the states and * reach IP STATUS. See SIM800 Series_TCPIP_Application Note_V1.01.pdf for * the GPRS states documentation. */ /* Configure context for TCP/IP applications. */ at_command(modem->at, "AT+CSTT=\"%s\"", apn); /* Establish context. */ at_command(modem->at, "AT+CIICR"); /* Read local IP address. Switches modem to IP STATUS state. */ at_set_command_scanner(modem->at, scanner_cifsr); at_command(modem->at, "AT+CIFSR"); return sim800_ipstatus(modem); }
static int telit2_ftp_get(struct cellular *modem, const char *filename) { at_set_timeout(modem->at, 90); at_command_simple(modem->at, "AT#FTPGETPKT=\"%s\",0", filename); return 0; }
static int sim800_pdp_close(struct cellular *modem) { at_set_timeout(modem->at, SET_TIMEOUT); at_set_command_scanner(modem->at, scanner_cipshut); at_command_simple(modem->at, "AT+CIPSHUT"); return 0; }
static int telit2_pdp_open(struct cellular *modem, const char *apn) { at_set_timeout(modem->at, 5); at_command_simple(modem->at, "AT+CGDCONT=1,IP,\"%s\"", apn); at_set_timeout(modem->at, 150); const char *response = at_command(modem->at, "AT#SGACT=1,1"); if (response == NULL) return -1; if (!strcmp(response, "+CME ERROR: context already activated")) return 0; int ip[4]; at_simple_scanf(response, "#SGACT: %d.%d.%d.%d", &ip[0], &ip[1], &ip[2], &ip[3]); return 0; }
static int telit2_socket_connect(struct cellular *modem, int connid, const char *host, uint16_t port) { /* Reset socket configuration to default. */ at_set_timeout(modem->at, 5); at_command_simple(modem->at, "AT#SCFGEXT=%d,0,0,0,0,0", connid); at_command_simple(modem->at, "AT#SCFGEXT2=%d,0,0,0,0,0", connid); /* Open connection. */ cellular_command_simple_pdp(modem, "AT#SD=%d,0,%d,%s,0,0,1", connid, port, host); return 0; }
int sim800_socket_close(struct cellular *modem, int connid) { struct cellular_sim800 *priv = (struct cellular_sim800 *) modem; if(connid == SIM800_NSOCKETS) { at_command_simple(modem->at, "AT+BTDISCONN=%d", priv->spp_connid); } else if(connid < SIM800_NSOCKETS) { at_set_timeout(modem->at, SET_TIMEOUT); at_set_command_scanner(modem->at, scanner_cipclose); at_command_simple(modem->at, "AT+CIPCLOSE=%d", connid); } return 0; }
static int sim800_attach(struct cellular *modem) { at_set_callbacks(modem->at, &sim800_callbacks, (void *) modem); at_set_timeout(modem->at, 2); /* Perform autobauding. */ for (int i=0; i<SIM800_AUTOBAUD_ATTEMPTS; i++) { const char *response = at_command(modem->at, "AT"); if (response != NULL) /* Modem replied. Good. */ break; } /* Disable local echo. */ at_command(modem->at, "ATE0"); /* Disable local echo again; make sure it was disabled successfully. */ at_command_simple(modem->at, "ATE0"); /* Initialize modem. */ static const char *const init_strings[] = { // "AT+IPR=0", /* Enable autobauding if not already enabled. */ "AT+IFC=0,0", /* Disable hardware flow control. */ "AT+CMEE=2", /* Enable extended error reporting. */ "AT+CLTS=0", /* Don't sync RTC with network time, it's broken. */ "AT+CIURC=0", /* Disable "Call Ready" URC. */ "AT&W0", /* Save configuration. */ "AT+BTSPPCFG=\"TT\",1", "AT+BTPAIRCFG=0", "AT+BTSPPGET=1", "AT+BTPOWER=1", NULL }; for (const char *const *command=init_strings; *command; command++) at_command_simple(modem->at, "%s", *command); /* Configure IP application. */ // /* Switch to multiple connections mode; it's less buggy. */ // if (sim800_config(modem, "CIPMUX", "1", SIM800_CIPCFG_RETRIES) != 0) // return -1; // /* Receive data manually. */ // if (sim800_config(modem, "CIPRXGET", "1", SIM800_CIPCFG_RETRIES) != 0) // return -1; // /* Enable quick send mode. */ // if (sim800_config(modem, "CIPQSEND", "1", SIM800_CIPCFG_RETRIES) != 0) // return -1; return 0; }
static ssize_t telit2_socket_send(struct cellular *modem, int connid, const void *buffer, size_t amount, int flags) { (void) flags; /* Request transmission. */ at_set_timeout(modem->at, 150); at_expect_dataprompt(modem->at); at_command_simple(modem->at, "AT#SSENDEXT=%d,%zu", connid, amount); /* Send raw data. */ at_command_raw_simple(modem->at, buffer, amount); return amount; }
static int telit2_op_iccid(struct cellular *modem, char *buf, size_t len) { char fmt[24]; if (snprintf(fmt, sizeof(fmt), "#CCID: %%[0-9]%ds", (int) len) >= (int) sizeof(fmt)) { errno = ENOSPC; return -1; } at_set_timeout(modem->at, 5); const char *response = at_command(modem->at, "AT#CCID"); at_simple_scanf(response, fmt, buf); buf[len-1] = '\0'; return 0; }
static ssize_t telit2_socket_recv(struct cellular *modem, int connid, void *buffer, size_t length, int flags) { (void) flags; int cnt = 0; while (cnt < (int) length) { int chunk = (int) length - cnt; /* Limit read size to avoid overflowing AT response buffer. */ if (chunk > 128) chunk = 128; /* Perform the read. */ at_set_timeout(modem->at, 150); at_set_command_scanner(modem->at, scanner_srecv); const char *response = at_command(modem->at, "AT#SRECV=%d,%d", connid, chunk); if (response == NULL) return -1; /* Find the header line. */ int bytes; at_simple_scanf(response, "#SRECV: %*d,%d", &bytes); /* Bail out if we're out of data. Message is misleading. */ /* FIXME: We should maybe block until we receive something? */ if (!strcmp(response, "+CME ERROR: activation failed")) break; /* Locate the payload. */ const char *data = strchr(response, '\n'); if (data == NULL) { errno = EPROTO; return -1; } data += 1; /* Copy payload to result buffer. */ memcpy((char *)buffer + cnt, data, bytes); cnt += bytes; } return cnt; }
static int sim800_ftp_getdata(struct cellular *modem, char *buffer, size_t length) { struct cellular_sim800 *priv = (struct cellular_sim800 *) modem; int retries = 0; retry: at_set_timeout(modem->at, SET_TIMEOUT); at_set_command_scanner(modem->at, scanner_ftpget2); const char *response = at_command(modem->at, "AT+FTPGET=2,%zu", length); if (response == NULL) return -1; int cnflength; if (sscanf(response, "+FTPGET: 2,%d", &cnflength) == 1) { /* Zero means no data is available. Wait for it. */ if (cnflength == 0) { /* Bail out on timeout. */ if (++retries >= SIM800_FTP_TIMEOUT) { return -1; } vTaskDelay(pdMS_TO_TICKS(1000)); goto retry; } /* Locate the payload. */ const char *data = strchr(response, '\n'); if (data == NULL) { return -1; } data += 1; /* Copy payload to result buffer. */ memcpy((char *)buffer, data, cnflength); return cnflength; } else if (priv->ftpget1_status == 0) { /* Transfer finished. */ return 0; } else { return -1; } }
static int at_init(uart_dev_t *u, const char *recv_delimiter, const char *send_delimiter, int timeout) { if (!u || !recv_delimiter || !send_delimiter || (timeout < 0)) { LOGE(MODULE_NAME, "%s: invalid argument", __func__); return -1; } if (at_init_uart(u) != 0) return -1; at_set_timeout(timeout); at_set_recv_delimiter(recv_delimiter); at_set_send_delimiter(send_delimiter); if (at._mode == ASYN) { at_init_mutex(); slist_init(&at.task_l); aos_task_new("at_worker", at_worker, NULL, 4096); } return 0; }
static int telit2_attach(struct cellular *modem) { at_set_callbacks(modem->at, &telit2_callbacks, (void *) modem); at_set_timeout(modem->at, 1); at_command(modem->at, "AT"); /* Aid autobauding. Always a good idea. */ at_command(modem->at, "ATE0"); /* Disable local echo. */ /* Initialize modem. */ static const char *const init_strings[] = { "AT&K0", /* Disable hardware flow control. */ "AT#SELINT=2", /* Set Telit module compatibility level. */ "AT+CMEE=2", /* Enable extended error reporting. */ NULL }; for (const char *const *command=init_strings; *command; command++) at_command_simple(modem->at, "%s", *command); return 0; }
/** * Retrieve AT+CIPSTATUS state. * * @returns Zero if context is open, -1 and sets errno otherwise. */ static int sim800_ipstatus(struct cellular *modem) { at_set_timeout(modem->at, 10); at_set_command_scanner(modem->at, scanner_cipstatus); const char *response = at_command(modem->at, "AT+CIPSTATUS"); if (response == NULL) return -1; const char *state = strstr(response, "STATE: "); if (!state) { return -1; } state += strlen("STATE: "); if (!strncmp(state, "IP STATUS", strlen("IP STATUS"))) return 0; if (!strncmp(state, "IP PROCESSING", strlen("IP PROCESSING"))) return 0; return -1; }
static int sim800_socket_waitack(struct cellular *modem, int connid) { const char *response; if(connid == SIM800_NSOCKETS) { return 0; } else if(connid < SIM800_NSOCKETS) { at_set_timeout(modem->at, 5); for (int i=0; i<SIM800_WAITACK_TIMEOUT; i++) { /* Read number of bytes waiting. */ int nacklen; response = at_command(modem->at, "AT+CIPACK=%d", connid); at_simple_scanf(response, "+CIPACK: %*d,%*d,%d", &nacklen); /* Return if all bytes were acknowledged. */ if (nacklen == 0) return 0; vTaskDelay(pdMS_TO_TICKS(1000)); } } return -1; }
int main(int argc, char *argv[]) { assert(argc-1 == 1); const char *devpath = argv[1]; printf("allocating channel...\n"); struct at *at = at_alloc_unix(devpath, B115200); printf("opening port...\n"); assert(at_open(at) == 0); printf("attaching callbacks\n"); at_set_callbacks(at, &generic_modem_callbacks, NULL); const char *commands[] = { "AT", "ATE0", "AT+CGMR", "AT+CGSN", "AT+CCID", "AT+CMEE=0", "AT+BLAH", "AT+CMEE=2", "AT+BLAH", NULL }; printf("sending commands...\n"); at_set_timeout(at, 10); for (const char **command=commands; *command; command++) { const char *result = at_command(at, *command); printf("%s => %s\n", *command, result ? result : strerror(errno)); } printf("freeing resources...\n"); at_free(at); return 0; }
static int telit2_op_clock_gettime(struct cellular *modem, struct timespec *ts) { struct tm tm; int offset; at_set_timeout(modem->at, 1); const char *response = at_command(modem->at, "AT+CCLK?"); memset(&tm, 0, sizeof(struct tm)); at_simple_scanf(response, "+CCLK: \"%d/%d/%d,%d:%d:%d%d\"", &tm.tm_year, &tm.tm_mon, &tm.tm_mday, &tm.tm_hour, &tm.tm_min, &tm.tm_sec, &offset); /* Most modems report some starting date way in the past when they have * no date/time estimation. */ if (tm.tm_year < 14) { errno = EINVAL; return 1; } /* Adjust values and perform conversion. */ tm.tm_year += 2000 - 1900; tm.tm_mon -= 1; time_t unix_time = timegm(&tm); if (unix_time == -1) { errno = EINVAL; return -1; } /* Telit modems return local date/time instead of UTC (as defined in 3GPP * 27.007). Remove the timezone shift. */ unix_time -= 15*60*offset; /* All good. Return the result. */ ts->tv_sec = unix_time; ts->tv_nsec = 0; return 0; }
static void at_worker(void *arg) { char buf[RECV_BUFFER_SIZE] = {0}; int offset = 0; int ret = 0; int at_task_empty = 0; char c; at_task_t *tsk; LOGD(MODULE_NAME, "at_work started."); at_set_timeout(500); while (true) { // read from uart and store buf ret = at_getc(&c); if (ret != 0) { continue; } if (offset + 1 >= RECV_BUFFER_SIZE) { LOGE(MODULE_NAME, "Fatal error, no one is handling AT uart"); assert(0); } buf[offset++] = c; buf[offset] = 0; // check oob first for (int k = 0; k < at._oobs_num; k++) { oob_t *oob = &(at._oobs[k]); if (offset == oob->len && memcmp(oob->prefix, buf, oob->len) == 0) { LOGD(MODULE_NAME, "AT! %s\r\n", oob->prefix); // oob.cb is to consume uart data if necessary oob->cb(oob->arg); // start a new round after oob cb memset(buf, 0, offset); offset = 0; continue; } } at_task_empty = slist_empty(&at.task_l); // if no task, continue recv if (at_task_empty) { LOGD(MODULE_NAME, "No task in queue"); goto check_buffer; } // otherwise, get the first task in list tsk = slist_first_entry(&at.task_l, at_task_t, next); // check if a rsp end matched if (strcmp(buf + offset - strlen(RECV_STATUS_OK), RECV_STATUS_OK) == 0 || strcmp(buf + offset - strlen(RECV_STATUS_ERROR), RECV_STATUS_ERROR) == 0) { LOGD(MODULE_NAME, "AT cammand rsp matched"); LOGD(MODULE_NAME, "at task is going to be waked up: %d, smpr: %d", (uint32_t)tsk, (uint32_t)&tsk->smpr); memcpy(tsk->rsp + tsk->rsp_offset, buf, offset); tsk->rsp_offset += offset; if (aos_sem_is_valid(&tsk->smpr)) { LOGD(MODULE_NAME, "at task is going to be waked up: %d, smpr: %d", (uint32_t)tsk, (uint32_t)&tsk->smpr); aos_sem_signal(&tsk->smpr); // wakeup send task } // start a new round after a match hit goto check_buffer; } if ((offset >= (RECV_BUFFER_SIZE - 2)) || (strcmp(&buf[offset - at._recv_delim_size], at._recv_delimiter) == 0)) { if (tsk->rsp_offset + offset < tsk->rsp_len){ memcpy(tsk->rsp + tsk->rsp_offset, buf, offset); tsk->rsp_offset += offset; }else{ LOGE(MODULE_NAME, "invalid input for task reponse totlen is %d,tsk->rsp_offset is %d ,offset is %d\n", tsk->rsp_len, tsk->rsp_offset, offset); memset(tsk->rsp, 0, tsk->rsp_len); strcpy(tsk->rsp, RECV_STATUS_ERROR); if (aos_sem_is_valid(&tsk->smpr)) { LOGD(MODULE_NAME, "at task is going to be waked up: %d, smpr: %d", (uint32_t)tsk, (uint32_t)&tsk->smpr); aos_sem_signal(&tsk->smpr); // wakeup send task } } LOGD(MODULE_NAME, "Save buffer to task rsp, offset: %d tsk->rsp_offset = %d task->rsp_len is %d\n", offset, tsk->rsp_offset, tsk->rsp_len); } check_buffer: // in case buffer is full if ((offset >= (RECV_BUFFER_SIZE - 2)) || (strcmp(&buf[offset - at._recv_delim_size], at._recv_delimiter) == 0)) { LOGD(MODULE_NAME, "buffer full or new line hit, offset: %d, buf: %s", offset, buf); memset(buf, 0, offset); offset = 0; } } // never reach here return; }
static ssize_t sim800_socket_recv(struct cellular *modem, int connid, void *buffer, size_t length, int flags) { struct cellular_sim800 *priv = (struct cellular_sim800 *) modem; (void) flags; int cnt = 0; // TODO its dumb and exceptions should be handled in other right way // FIXME: It has to be changed. Leave for now if(connid == SIM800_NSOCKETS) { if(priv->spp_status != SIM800_SOCKET_STATUS_CONNECTED) { return -1; } /* Copy payload to result buffer. */ cnt = strlen(spp_recv_buf); if(cnt) { memcpy(buffer, spp_recv_buf, cnt); *(((char*)buffer) + cnt) = '\0'; spp_recv_buf[0] = '\0'; } } else if(connid < SIM800_NSOCKETS) { if(priv->socket_status[connid] != SIM800_SOCKET_STATUS_CONNECTED) { return -1; } char tries = 4; while ( (cnt < (int) length) && tries-- ){ int chunk = (int) length - cnt; /* Limit read size to avoid overflowing AT response buffer. */ chunk = chunk > 480 ? 480 : chunk; /* Perform the read. */ at_set_timeout(modem->at, SET_TIMEOUT); at_set_command_scanner(modem->at, scanner_ciprxget); const char *response = at_command(modem->at, "AT+CIPRXGET=2,%d,%d", connid, chunk); if (response == NULL) return -1; /* Find the header line. */ int requested, confirmed; // TODO: // 1. connid is not checked // 2. there is possible a bug here. if not all data are ready (confirmed < requested) // then wierd things can happen. see memcpy // requested should be equal to chunk // confirmed is that what can be read at_simple_scanf(response, "+CIPRXGET: 2,%*d,%d,%d", &requested, &confirmed); /* Bail out if we're out of data. */ /* FIXME: We should maybe block until we receive something? */ if (confirmed == 0) break; /* Locate the payload. */ /* TODO: what if no \n is in input stream? * should use strnchr at least */ const char *data = strchr(response, '\n'); if (data++ == NULL) { return -1; } /* Copy payload to result buffer. */ memcpy((char *)buffer + cnt, data, confirmed); cnt += confirmed; } } return cnt; }
static int at_init(const char *recv_prefix, const char *recv_success_postfix, const char *recv_fail_postfix, const char *send_delimiter, int timeout) { if (!recv_prefix || !recv_success_postfix || !recv_fail_postfix || !send_delimiter || (timeout < 0)) { LOGE(MODULE_NAME, "%s: invalid argument", __func__); return -1; } if (inited == 1) { LOGI(MODULE_NAME, "have already inited ,it will init again\r\n"); inited = 0; } if (at_init_uart() != 0) { LOGE(MODULE_NAME, "at uart init fail \r\n"); return -1; } memset(at._oobs, 0, sizeof(oob_t) * OOB_MAX); at_set_timeout(timeout); at_set_recv_delimiter(recv_prefix, recv_success_postfix, recv_fail_postfix); at_set_send_delimiter(send_delimiter); LOGD(MODULE_NAME, "at worker rcv prefix is %s success postfix is %s fail postfix is %s " "\r\n", recv_prefix, recv_success_postfix, recv_fail_postfix); if (at_init_at_mutex() != 0) { LOGE(MODULE_NAME, "at uart mutex init fail \r\n"); return -1; } if (at_init_task_mutex() != 0) { at_uinit_at_mutex(); LOGE(MODULE_NAME, "at mutex init fail \r\n"); return -1; } slist_init(&at.task_l); if (at_worker_uart_send_mutex_init() != 0) { at_uinit_at_mutex(); at_uinit_task_mutex(); LOGE(MODULE_NAME, "fail to creat at worker sem\r\n"); } if (aos_task_new("at_worker", at_worker, NULL, at_worker_stacksize)) { at_uinit_at_mutex(); at_uinit_task_mutex(); at_worker_uart_send_mutex_uinit(); LOGE(MODULE_NAME, "fail to creat at task\r\n"); return -1; } inited = 1; return 0; }
static int telit2_ftp_getdata(struct cellular *modem, char *buffer, size_t length) { /* FIXME: This function's flow is really ugly. */ int retries = 0; retry: at_set_timeout(modem->at, 150); at_set_command_scanner(modem->at, scanner_ftprecv); const char *response = at_command(modem->at, "AT#FTPRECV=%zu", length); if (response == NULL) return -1; int bytes; if (sscanf(response, "#FTPRECV: %d", &bytes) == 1) { /* Zero means no data is available. Wait for it. */ if (bytes == 0) { /* Bail out on timeout. */ if (++retries >= TELIT2_FTP_TIMEOUT) { errno = ETIMEDOUT; return -1; } sleep(1); goto retry; } /* Locate the payload. */ const char *data = strchr(response, '\n'); if (data == NULL) { errno = EPROTO; return -1; } data += 1; /* Copy payload to result buffer. */ memcpy(buffer, data, bytes); return bytes; } /* Error or EOF? */ int eof; response = at_command(modem->at, "AT#FTPGETPKT?"); /* Expected response: #FTPGETPKT: <remotefile>,<viewMode>,<eof> */ #if 0 /* The %[] specifier is not supported on some embedded systems. */ at_simple_scanf(response, "#FTPGETPKT: %*[^,],%*d,%d", &eof); #else /* Parse manually. */ if (response == NULL) return -1; errno = EPROTO; /* Check the initial part of the response. */ if (strncmp(response, "#FTPGETPKT: ", 12)) return -1; /* Skip the filename. */ response = strchr(response, ','); if (response == NULL) return -1; response++; at_simple_scanf(response, "%*d,%d", &eof); #endif if (eof == 1) return 0; return -1; }