static bool at_vrecv(const char *response, va_list args) { char *_buffer = at._buffer; char *_recv_delimiter = at._recv_delimiter; char c; int ret = 0; vrecv_start: while (response[0]) { int i = 0; int offset = 0; while (response[i]) { if (memcmp(&response[i + 1 - at._recv_delim_size], _recv_delimiter, at._recv_delim_size) == 0) { i++; break; } else if (response[i] == '%' && response[i + 1] != '%' && response[i + 1] != '*') { _buffer[offset++] = '%'; _buffer[offset++] = '*'; i++; } else { _buffer[offset++] = response[i++]; } } _buffer[offset++] = '%'; _buffer[offset++] = 'n'; _buffer[offset++] = 0; int j = 0; while (true) { ret = at_getc(&c); if (ret != 0) { return false; } _buffer[offset + j++] = c; _buffer[offset + j] = 0; for (int k = 0; k < at._oobs_num; k++) { oob_t *oob = &(at._oobs[k]); if (j == oob->len && memcmp(oob->prefix, at._buffer + offset, oob->len) == 0) { LOGD(MODULE_NAME, "AT! %s\r\n", oob->prefix); oob->cb(oob->arg); goto vrecv_start; } } int count = -1; sscanf(_buffer + offset, _buffer, &count); if (count == j) { LOGD(MODULE_NAME, "AT= %s\r\n", _buffer + offset); memcpy(_buffer, response, i); _buffer[i] = 0; vsscanf(_buffer + offset, _buffer, args); response += i; break; } if (j + 1 >= BUFFER_SIZE - offset || strcmp(&_buffer[offset + j - at._recv_delim_size], _recv_delimiter) == 0) { LOGD(MODULE_NAME, "AT< %s", _buffer + offset); j = 0; } } } return true; }
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 void at_worker(void *arg) { int offset = 0; int ret = 0; int at_task_empty = 0; int at_task_reponse_begin = 0; int memcpy_size = 0; int rsp_prefix_len = 0; int rsp_success_postfix_len = 0; int rsp_fail_postfix_len = 0; char c; at_task_t *tsk; char * buf = NULL; char * rsp_prefix = NULL; char * rsp_success_postfix = NULL; char * rsp_fail_postfix = NULL; oob_t * oob = NULL; LOGD(MODULE_NAME, "at_work started."); buf = aos_malloc(RECV_BUFFER_SIZE); if (NULL == buf) { LOGE(MODULE_NAME, "AT worker fail to malloc ,task exist \r\n"); aos_task_exit(0); return; } memset(buf, 0, RECV_BUFFER_SIZE); while (true) { // read from uart and store buf if (at._mode != ASYN) { aos_msleep(1); } 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"); continue; } buf[offset++] = c; buf[offset] = 0; for (int k = 0; k < at._oobs_num; k++) { oob = &(at._oobs[k]); if (oob->reallen > 0 || (offset >= strlen(oob->prefix) && memcmp(oob->prefix, buf + offset - strlen(oob->prefix), strlen(oob->prefix)) == 0)) { LOGD(MODULE_NAME, "AT! %s\r\n", oob->prefix); if (oob->postfix == NULL) { oob->cb(oob->arg, NULL, 0); memset(buf + offset - strlen(oob->prefix), 0, offset); offset -= strlen(oob->prefix); } else { if (oob->reallen == 0) { memset(oob->oobinputdata, 0, oob->maxlen); memcpy(oob->oobinputdata, oob->prefix, strlen(oob->prefix) - 1); oob->reallen += strlen(oob->prefix) - 1; } if (oob->reallen < oob->maxlen) { oob->oobinputdata[oob->reallen] = c; oob->reallen++; if ((oob->reallen >= strlen(oob->prefix) + strlen(oob->postfix)) && (strncmp(oob->oobinputdata + oob->reallen - strlen(oob->postfix), oob->postfix, strlen(oob->postfix)) == 0)) { /*recv postfix*/ oob->cb(oob->arg, oob->oobinputdata, oob->reallen); memset(oob->oobinputdata, 0, oob->reallen); oob->reallen = 0; memset(buf, 0, offset); offset = 0; } } else { LOGE(MODULE_NAME, "invalid oob %s input , for oversize %s \r\n", oob->prefix, oob->oobinputdata); memset(oob->oobinputdata, 0, oob->reallen); oob->reallen = 0; memset(buf, 0, offset); offset = 0; } /*oob data maybe more than buf size */ if (offset > (RECV_BUFFER_SIZE - 2)) { memset(buf, 0, offset); offset = 0; } } continue; } } aos_mutex_lock(&at.task_mutex, AOS_WAIT_FOREVER); at_task_empty = slist_empty(&at.task_l); if (!at_task_empty) { tsk = slist_first_entry(&at.task_l, at_task_t, next); } aos_mutex_unlock(&at.task_mutex); // if no task, continue recv if (at_task_empty) { LOGD(MODULE_NAME, "No task in queue"); goto check_buffer; } if (NULL != tsk->rsp_prefix && 0 != tsk->rsp_prefix_len) { rsp_prefix = tsk->rsp_prefix; rsp_prefix_len = tsk->rsp_prefix_len; } else { rsp_prefix = at._default_recv_prefix; rsp_prefix_len = at._recv_prefix_len; } if (NULL != tsk->rsp_success_postfix && 0 != tsk->rsp_success_postfix_len) { rsp_success_postfix = tsk->rsp_success_postfix; rsp_success_postfix_len = tsk->rsp_success_postfix_len; } else { rsp_success_postfix = at._default_recv_success_postfix; rsp_success_postfix_len = at._recv_success_postfix_len; } if (NULL != tsk->rsp_fail_postfix && 0 != tsk->rsp_fail_postfix_len) { rsp_fail_postfix = tsk->rsp_fail_postfix; rsp_fail_postfix_len = tsk->rsp_fail_postfix_len; } else { rsp_fail_postfix = at._default_recv_fail_postfix; rsp_fail_postfix_len = at._recv_fail_postfix_len; } if (offset >= rsp_prefix_len && at_task_reponse_begin == 0 && (strncmp(buf + offset - rsp_prefix_len, rsp_prefix, rsp_prefix_len) == 0)) { at_task_reponse_begin = 1; } if (at_task_reponse_begin == 1) { if (tsk->rsp_offset < tsk->rsp_len) { tsk->rsp[tsk->rsp_offset] = c; tsk->rsp_offset++; if ((tsk->rsp_offset >= rsp_success_postfix_len && strncmp( tsk->rsp + tsk->rsp_offset - rsp_success_postfix_len, rsp_success_postfix, rsp_success_postfix_len) == 0) || (tsk->rsp_offset >= rsp_fail_postfix_len && strncmp(tsk->rsp + tsk->rsp_offset - rsp_fail_postfix_len, rsp_fail_postfix, rsp_fail_postfix_len) == 0)) { aos_sem_signal(&tsk->smpr); at_task_reponse_begin = 0; memset(buf, 0, offset); offset = 0; } } else { memset(tsk->rsp, 0, tsk->rsp_len); strcpy(tsk->rsp, rsp_fail_postfix); aos_sem_signal(&tsk->smpr); at_task_reponse_begin = 0; memset(buf, 0, offset); offset = 0; } } check_buffer: // in case buffer is full if (offset > (RECV_BUFFER_SIZE - 2)) { printf("buffer full \r\n"); memcpy_size = rsp_prefix_len > rsp_success_postfix_len ? rsp_prefix_len : rsp_success_postfix_len; memcpy_size = memcpy_size > rsp_fail_postfix_len ? memcpy_size : rsp_fail_postfix_len; memcpy(buf, buf + offset - memcpy_size, memcpy_size); memset(buf + memcpy_size, 0, offset - memcpy_size); offset = memcpy_size; } } return; }