Merge pull request #6927 from AriParkkila/cellular-debug

Cellular: AT debugging improved
pull/7011/head
Cruz Monrreal 2018-05-24 12:35:06 -05:00 committed by GitHub
commit 5ce26b1306
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 358 additions and 229 deletions

View File

@ -72,7 +72,7 @@ You can define the debug tracing level in the `mbed_app.json` configuration file
The `TESTS` folder contains Greentea tests for cellular specific classes. You need to give relevant configuration file with `--app-config` parameter, e.g.:
mbed test -n features-cellular-tests-* --app-config features\cellular\TESTS\socket\udp\template_mbed_app.json -vv
mbed test -n features-cellular-tests-* --app-config features\cellular\TESTS\socket\udp\template_mbed_app.json.txt -v
Note that Greentea tests use SIM PIN so you need to change that or your SIM card may get locked.

View File

@ -55,73 +55,141 @@ static UARTSerial cellular_serial(MDMTXD, MDMRXD, MBED_CONF_PLATFORM_DEFAULT_SER
static rtos::Semaphore network_semaphore(0);
static CellularConnectionFSM cellular;
#if MBED_CONF_MBED_TRACE_ENABLE
static rtos::Mutex trace_mutex;
void trace_wait()
{
trace_mutex.lock();
}
void trace_release()
{
trace_mutex.unlock();
}
static char time_st[sizeof("[12345678]") + 1];
static char *trace_time(size_t ss)
{
snprintf(time_st, sizeof("[12345678]"), "[%08llu]", rtos::Kernel::get_ms_count());
return time_st;
}
static void trace_open()
{
mbed_trace_init();
mbed_trace_prefix_function_set(&trace_time);
mbed_trace_mutex_wait_function_set(trace_wait);
mbed_trace_mutex_release_function_set(trace_release);
mbed_cellular_trace::mutex_wait_function_set(trace_wait);
mbed_cellular_trace::mutex_release_function_set(trace_release);
}
static void trace_close()
{
mbed_cellular_trace::mutex_wait_function_set(NULL);
mbed_cellular_trace::mutex_release_function_set(NULL);
mbed_trace_free();
}
#endif // MBED_CONF_MBED_TRACE_ENABLE
static SocketAddress echo_server_addr;
static rtos::EventFlags eventFlags;
class EchoSocket : public UDPSocket {
public:
EchoSocket(int size) : UDPSocket(), _async_flag(0), _data(0), _size(size) {
}
virtual ~EchoSocket() {
delete _data;
}
void set_async(int async) {
_async_flag = async;
EchoSocket(int size) : UDPSocket(), _data(0), _size(size), _async_flag(0), _tx_pending(false), _rx_pending(false)
{
}
virtual ~EchoSocket()
{
delete _data;
}
void set_async(int async)
{
_async_flag = async;
if (_async_flag) {
set_blocking(false);
sigio(callback(this, &EchoSocket::async_callback));
} else {
set_blocking(true);
set_timeout(SOCKET_TIMEOUT);
sigio(NULL);
}
}
}
void test_sendto(const char *const hostname = NULL) {
_data = new uint8_t[_size];
for (int i=0; i<_size; i++) {
_data[i] = (uint8_t)rand();
}
// clear pending events
TEST_ASSERT(!(EchoSocket::eventFlags.clear(_async_flag) & osFlagsError));
if (hostname) {
TEST_ASSERT(sendto(hostname, ECHO_SERVER_UDP_PORT, _data, _size) == _size);
} else {
TEST_ASSERT(sendto(echo_server_addr, _data, _size) == _size);
}
}
void test_recvfrom() {
if (_async_flag) {
TEST_ASSERT((EchoSocket::eventFlags.wait_any(_async_flag, SOCKET_TIMEOUT) & (osFlagsError | _async_flag)) == _async_flag);
}
uint8_t *buf = new uint8_t[_size];
memset(buf, 0, _size);
SocketAddress recv_address;
void test_sendto(const char *const hostname = NULL)
{
if (!_data) {
_data = new uint8_t[_size];
for (int i = 0; i < _size; i++) {
_data[i] = (uint8_t)rand();
}
}
nsapi_size_or_error_t ret;
if (hostname) {
ret = sendto(hostname, ECHO_SERVER_UDP_PORT, _data, _size);
} else {
ret = sendto(echo_server_addr, _data, _size);
}
if (ret == _size) { // send successful
_tx_pending = false;
} else {
TEST_ASSERT(_async_flag && ret == NSAPI_ERROR_WOULD_BLOCK);
_tx_pending = true;
}
}
TEST_ASSERT(recvfrom(&recv_address, buf, _size) == _size);
void test_recvfrom()
{
uint8_t *buf = new uint8_t[_size];
memset(buf, 0, _size);
SocketAddress recv_address;
nsapi_size_or_error_t ret = recvfrom(&recv_address, buf, _size);
if (ret == _size) { // recv successful
_rx_pending = false;
TEST_ASSERT(recv_address == echo_server_addr);
TEST_ASSERT(memcmp(_data, buf, _size) == 0);
delete _data;
_data = NULL;
_rx_pending = false;
} else {
TEST_ASSERT(_async_flag && ret == NSAPI_ERROR_WOULD_BLOCK);
_rx_pending = true;
}
delete buf;
}
bool async_process()
{
if (_tx_pending) {
test_sendto();
}
if (_rx_pending) {
test_recvfrom();
}
return _tx_pending | _rx_pending;
}
TEST_ASSERT(recv_address == echo_server_addr);
TEST_ASSERT(memcmp(_data, buf, _size) == 0);
delete buf;
delete _data;
_data = 0;
}
private:
void async_callback() {
EchoSocket::eventFlags.set(_async_flag);
}
uint8_t *_data;
int _size;
uint32_t _async_flag; // 0 for blocking socket, signal bit for async
static rtos::EventFlags eventFlags;
void async_callback()
{
eventFlags.set(_async_flag);
}
uint8_t *_data;
int _size;
uint32_t _async_flag; // 0 for blocking socket, signal bit for async
bool _tx_pending;
bool _rx_pending;
};
rtos::EventFlags EchoSocket::eventFlags;
static void network_callback(nsapi_event_t ev, intptr_t ptr)
{
if (ev == NSAPI_EVENT_CONNECTION_STATUS_CHANGE) {
if (ptr == NSAPI_STATUS_GLOBAL_UP) {
MBED_ASSERT(network_semaphore.release() == osOK);
MBED_ASSERT(network_semaphore.release() == osOK);
}
}
}
@ -131,65 +199,79 @@ static void udp_network_stack()
cellular.set_serial(&cellular_serial);
TEST_ASSERT(cellular.init() == NSAPI_ERROR_OK);
#if defined (MDMRTS) && defined (MDMCTS)
cellular_serial.set_flow_control(SerialBase::RTSCTS, MDMRTS, MDMCTS);
cellular_serial.set_flow_control(SerialBase::RTSCTS, MDMRTS, MDMCTS);
#endif
cellular.attach(&network_callback);
TEST_ASSERT(cellular.start_dispatch() == NSAPI_ERROR_OK);
cellular.set_sim_pin(MBED_CONF_APP_CELLULAR_SIM_PIN);
#ifdef MBED_CONF_APP_APN
CellularNetwork *network = cellular.get_network();
TEST_ASSERT(network->set_credentials(MBED_CONF_APP_APN) == NSAPI_ERROR_OK);
#endif
cellular_target_state = CellularConnectionFSM::STATE_CONNECTED;
TEST_ASSERT(cellular.continue_to_state(cellular_target_state) == NSAPI_ERROR_OK);
TEST_ASSERT(network_semaphore.wait(NETWORK_TIMEOUT) == 1);
TEST_ASSERT(network_semaphore.wait(NETWORK_TIMEOUT) == 1);
}
static void udp_gethostbyname()
{
TEST_ASSERT(cellular.get_network()->gethostbyname(ECHO_SERVER_NAME, &echo_server_addr) == 0);
tr_info("HOST: %s", echo_server_addr.get_ip_address());
echo_server_addr.set_port(7);
wait(1);
tr_info("Echo server IP: %s", echo_server_addr.get_ip_address());
echo_server_addr.set_port(7);
}
static void udp_socket_send_receive()
{
EchoSocket echo_socket(4);
TEST_ASSERT(echo_socket.open(cellular.get_network()) == NSAPI_ERROR_OK);
echo_socket.set_async(0);
echo_socket.set_blocking(true);
echo_socket.set_timeout(SOCKET_TIMEOUT);
echo_socket.test_sendto();
echo_socket.test_recvfrom();
TEST_ASSERT(echo_socket.close() == NSAPI_ERROR_OK);
wait(1);
}
static void udp_socket_send_receive_async()
{
int async_flag = 1;
TEST_ASSERT(!(eventFlags.clear(async_flag) & osFlagsError));
EchoSocket echo_socket(4);
TEST_ASSERT(echo_socket.open(cellular.get_network()) == NSAPI_ERROR_OK);
echo_socket.set_async(1);
echo_socket.set_async(async_flag);
echo_socket.test_sendto();
echo_socket.test_recvfrom();
while (true) {
TEST_ASSERT((eventFlags.wait_any(async_flag, SOCKET_TIMEOUT) & (osFlagsError)) != osFlagsError);
if (!echo_socket.async_process()) {
break;
}
}
TEST_ASSERT(echo_socket.close() == NSAPI_ERROR_OK);
wait(1);
}
using namespace utest::v1;
static utest::v1::status_t greentea_failure_handler(const Case *const source, const failure_t reason)
{
#if MBED_CONF_MBED_TRACE_ENABLE
trace_close();
#endif
greentea_case_failure_abort_handler(source, reason);
return STATUS_ABORT;
}
static Case cases[] = {
Case("UDP network stack", udp_network_stack, greentea_failure_handler),
Case("UDP gethostbyname", udp_gethostbyname, greentea_failure_handler),
Case("UDP socket send/receive", udp_socket_send_receive, greentea_failure_handler),
Case("UDP socket send/receive async", udp_socket_send_receive_async, greentea_failure_handler),
//Case("UDP socket multiple simultaneous", udp_socket_multiple_simultaneous, greentea_failure_handler),
Case("UDP network stack", udp_network_stack, greentea_failure_handler),
Case("UDP gethostbyname", udp_gethostbyname, greentea_failure_handler),
Case("UDP socket send/receive", udp_socket_send_receive, greentea_failure_handler),
Case("UDP socket send/receive async", udp_socket_send_receive_async, greentea_failure_handler),
};
static utest::v1::status_t test_setup(const size_t number_of_cases)
{
GREENTEA_SETUP(10*60, "default_auto"); // network registration may take up to 180 seconds, DNS query a couple of minutes, etc.
GREENTEA_SETUP(10 * 60, "default_auto"); // network registration may take up to 180 seconds, DNS query a couple of minutes, etc.
return verbose_test_setup_handler(number_of_cases);
}
@ -197,7 +279,12 @@ static Specification specification(test_setup, cases);
int main()
{
mbed_trace_init();
return Harness::run(specification);
#if MBED_CONF_MBED_TRACE_ENABLE
trace_open();
#endif
int ret = Harness::run(specification);
#if MBED_CONF_MBED_TRACE_ENABLE
trace_close();
#endif
return ret;
}

View File

@ -17,24 +17,27 @@
"value": 0
},
"trace-level": {
"help": "Options are TRACE_LEVEL_ERROR,TRACE_LEVEL_WARN,TRACE_LEVEL_INFO,TRACE_LEVEL_DEBUG",
"help": "Note that excessive trace prints may mess up with Greentea parsing",
"macro_name": "MBED_TRACE_MAX_LEVEL",
"value": "TRACE_LEVEL_INFO"
"value": "TRACE_LEVEL_ERROR"
}
},
"target_overrides": {
"*": {
"ppp-cell-iface.apn-lookup": false,
"cellular.use-apn-lookup": false,
"target.features_add": ["LWIP", "COMMON_PAL"],
"mbed-trace.enable": false,
"target.features_add": ["LWIP"],
"mbed-trace.enable": true,
"lwip.ipv4-enabled": true,
"lwip.ipv6-enabled": true,
"lwip.tcp-enabled": false,
"lwip.ppp-enabled": true,
"lwip.ethernet-enabled": false,
"platform.stdio-convert-newlines": true,
"platform.default-serial-baud-rate": 115200
"platform.default-serial-baud-rate": 115200,
"drivers.uart-serial-txbuf-size": 512,
"drivers.uart-serial-rxbuf-size": 1024,
"cellular.debug-at": false
}
}
}

View File

@ -35,12 +35,6 @@ using namespace mbed_cellular_util;
#include "CellularLog.h"
#if MBED_CONF_MBED_TRACE_ENABLE
#define at_debug(format, ...) do { if (_debug_on) debug(format, ## __VA_ARGS__); } while (0)
#else
#define at_debug(...)
#endif
// URCs should be handled fast, if you add debug traces within URC processing then you also need to increase this time
#define PROCESS_URC_TIME 20
@ -86,12 +80,10 @@ ATHandler::ATHandler(FileHandle *fh, EventQueue &queue, int timeout, const char
_urc_matched(false),
_error_found(false),
_max_resp_length(MAX_RESP_LENGTH),
_debug_on(false),
_debug_on(MBED_CONF_CELLULAR_DEBUG_AT),
_cmd_start(false),
_start_time(0)
{
//enable_debug(true);
clear_error();
if (output_delimiter) {
@ -119,9 +111,9 @@ ATHandler::ATHandler(FileHandle *fh, EventQueue &queue, int timeout, const char
set_filehandle_sigio();
}
void ATHandler::enable_debug(bool enable)
void ATHandler::set_debug(bool debug_on)
{
_debug_on = enable;
_debug_on = debug_on;
}
ATHandler::~ATHandler()
@ -273,14 +265,14 @@ void ATHandler::set_at_timeout(uint32_t timeout_milliseconds, bool default_timeo
void ATHandler::restore_at_timeout()
{
if (_previous_at_timeout != _at_timeout) {
_at_timeout =_previous_at_timeout;
_at_timeout = _previous_at_timeout;
}
}
void ATHandler::process_oob()
{
lock();
tr_debug("process_oob %d", (_fileHandle->readable() || (_recv_pos < _recv_len)));
tr_debug("process_oob readable=%d, pos=%u, len=%u", _fileHandle->readable(), _recv_pos, _recv_len);
if (_fileHandle->readable() || (_recv_pos < _recv_len)) {
_current_scope = NotSet;
uint32_t timeout = _at_timeout;
@ -319,14 +311,12 @@ void ATHandler::set_filehandle_sigio()
void ATHandler::reset_buffer()
{
tr_debug("%s", __func__);
_recv_pos = 0;
_recv_len = 0;
}
void ATHandler::rewind_buffer()
{
tr_debug("%s", __func__);
if (_recv_pos > 0 && _recv_len >= _recv_pos) {
_recv_len -= _recv_pos;
// move what is not read to beginning of buffer
@ -342,7 +332,7 @@ int ATHandler::poll_timeout(bool wait_for_timeout)
uint64_t now = rtos::Kernel::get_ms_count();
if (now >= _start_time + _at_timeout) {
timeout = 0;
} else if ( _start_time + _at_timeout - now > INT_MAX) {
} else if (_start_time + _at_timeout - now > INT_MAX) {
timeout = INT_MAX;
} else {
timeout = _start_time + _at_timeout - now;
@ -355,7 +345,6 @@ int ATHandler::poll_timeout(bool wait_for_timeout)
bool ATHandler::fill_buffer(bool wait_for_timeout)
{
tr_debug("%s", __func__);
// Reset buffer when full
if (sizeof(_recv_buff) == _recv_len) {
tr_error("AT overflow");
@ -369,6 +358,7 @@ bool ATHandler::fill_buffer(bool wait_for_timeout)
if (count > 0 && (fhs.revents & POLLIN)) {
ssize_t len = _fileHandle->read(_recv_buff + _recv_len, sizeof(_recv_buff) - _recv_len);
if (len > 0) {
debug_print(_recv_buff + _recv_len, len);
_recv_len += len;
return true;
}
@ -380,7 +370,6 @@ bool ATHandler::fill_buffer(bool wait_for_timeout)
int ATHandler::get_char()
{
if (_recv_pos == _recv_len) {
tr_debug("%s", __func__);
reset_buffer(); // try to read as much as possible
if (!fill_buffer()) {
tr_warn("AT timeout");
@ -389,14 +378,11 @@ int ATHandler::get_char()
}
}
tr_debug("%s: %c", __func__, _recv_buff[_recv_pos]);
return _recv_buff[_recv_pos++];
}
void ATHandler::skip_param(uint32_t count)
{
tr_debug("%s", __func__);
if (_last_err || !_stop_tag || _stop_tag->found) {
return;
}
@ -426,7 +412,6 @@ void ATHandler::skip_param(uint32_t count)
void ATHandler::skip_param(ssize_t len, uint32_t count)
{
tr_debug("%s", __func__);
if (_last_err || !_stop_tag || _stop_tag->found) {
return;
}
@ -447,7 +432,6 @@ void ATHandler::skip_param(ssize_t len, uint32_t count)
ssize_t ATHandler::read_bytes(uint8_t *buf, size_t len)
{
tr_debug("%s", __func__);
if (_last_err) {
return -1;
}
@ -466,19 +450,12 @@ ssize_t ATHandler::read_bytes(uint8_t *buf, size_t len)
ssize_t ATHandler::read(char *buf, size_t size, bool read_even_stop_tag, bool hex)
{
tr_debug("%s", __func__);
at_debug("\n----------read buff:----------\n");
for (size_t i = _recv_pos; i < _recv_len; i++) {
at_debug("%c", _recv_buff[i]);
}
at_debug("\n----------read end----------\n");
if (_last_err || !_stop_tag || (_stop_tag->found && read_even_stop_tag == false)) {
return -1;
}
size_t match_pos = 0;
size_t read_size = hex ? size*2 : size;
size_t read_size = hex ? size * 2 : size;
consume_char('\"');
@ -488,19 +465,18 @@ ssize_t ATHandler::read(char *buf, size_t size, bool read_even_stop_tag, bool he
for (; read_idx < (read_size + match_pos); read_idx++) {
int c = get_char();
buf_idx = hex ? read_idx/2 : read_idx;
buf_idx = hex ? read_idx / 2 : read_idx;
if (c == -1) {
buf[buf_idx] = '\0';
set_error(NSAPI_ERROR_DEVICE_ERROR);
return -1;
} else if (c == _delimiter) {
}
if (c == _delimiter) {
buf[buf_idx] = '\0';
break;
} else if (c == '\"') {
match_pos = 0;
if (read_idx > 0) {
read_idx--;
}
read_idx--;
continue;
} else if (_stop_tag->len && c == _stop_tag->tag[match_pos]) {
match_pos++;
@ -520,7 +496,7 @@ ssize_t ATHandler::read(char *buf, size_t size, bool read_even_stop_tag, bool he
} else {
hexbuf[read_idx % 2] = c;
if (read_idx % 2 == 1) {
hex_str_to_char_str(hexbuf, 2, buf+buf_idx);
hex_str_to_char_str(hexbuf, 2, buf + buf_idx);
}
}
}
@ -540,8 +516,6 @@ ssize_t ATHandler::read_hex_string(char *buf, size_t size)
int32_t ATHandler::read_int()
{
tr_debug("%s", __func__);
if (_last_err || !_stop_tag || _stop_tag->found) {
return -1;
}
@ -566,7 +540,7 @@ void ATHandler::set_default_delimiter()
_delimiter = DEFAULT_DELIMITER;
}
void ATHandler::set_tag(tag_t* tag_dst, const char *tag_seq)
void ATHandler::set_tag(tag_t *tag_dst, const char *tag_seq)
{
if (tag_seq) {
size_t tag_len = strlen(tag_seq);
@ -589,7 +563,6 @@ void ATHandler::set_stop_tag(const char *stop_tag_seq)
void ATHandler::set_scope(ScopeType scope_type)
{
tr_debug("%s: %d", __func__, scope_type);
if (_current_scope != scope_type) {
_current_scope = scope_type;
switch (_current_scope) {
@ -616,9 +589,8 @@ void ATHandler::set_scope(ScopeType scope_type)
}
// should match from recv_pos?
bool ATHandler::match(const char* str, size_t size)
bool ATHandler::match(const char *str, size_t size)
{
tr_debug("%s: %s", __func__, str);
rewind_buffer();
if ((_recv_len - _recv_pos) < size) {
@ -635,14 +607,12 @@ bool ATHandler::match(const char* str, size_t size)
bool ATHandler::match_urc()
{
tr_debug("%s", __func__);
rewind_buffer();
size_t prefix_len = 0;
for (struct oob_t *oob = _oobs; oob; oob = oob->next) {
prefix_len = oob->prefix_len;
if (_recv_len >= prefix_len) {
if (match(oob->prefix, prefix_len)) {
tr_debug("URC! %s\n", oob->prefix);
set_scope(InfoType);
if (oob->cb) {
oob->cb();
@ -657,8 +627,6 @@ bool ATHandler::match_urc()
bool ATHandler::match_error()
{
tr_debug("%s", __func__);
if (match(CME_ERROR, CME_ERROR_LENGTH)) {
at_error(true, DeviceErrorTypeErrorCME);
return true;
@ -717,7 +685,7 @@ void ATHandler::set_3gpp_error(int err, DeviceErrorType error_type)
// CMS errors 0-127 maps straight to 3GPP errors
_last_3gpp_error = err;
} else {
for (size_t i = 0; i<sizeof(map_3gpp_errors)/sizeof(map_3gpp_errors[0]); i++) {
for (size_t i = 0; i < sizeof(map_3gpp_errors) / sizeof(map_3gpp_errors[0]); i++) {
if (map_3gpp_errors[i][0] == err) {
_last_3gpp_error = map_3gpp_errors[i][1];
tr_debug("AT3GPP error code %d", get_3gpp_error());
@ -737,25 +705,17 @@ void ATHandler::at_error(bool error_code_expected, DeviceErrorType error_type)
set_3gpp_error(err, error_type);
_last_at_err.errCode = err;
_last_at_err.errType = error_type;
tr_debug("ATHandler ERROR: %d", err);
tr_error("AT error code %ld", err);
} else {
tr_debug("ATHandler ERROR reading failed");
tr_warn("ATHandler ERROR reading failed");
}
}
_last_err = NSAPI_ERROR_DEVICE_ERROR;
set_error(NSAPI_ERROR_DEVICE_ERROR);
}
void ATHandler::resp(const char *prefix, bool check_urc)
{
tr_debug("%s: %s", __func__, prefix);
at_debug("\n----------resp buff:----------\n");
for (size_t i = _recv_pos; i < _recv_len; i++) {
at_debug("%c", _recv_buff[i]);
}
at_debug("\n----------buff----------\n");
_prefix_matched = false;
_urc_matched = false;
_error_found = false;
@ -794,7 +754,7 @@ void ATHandler::resp(const char *prefix, bool check_urc)
} else {
// If no prefix, no CRLF and no more chance to match for OK, ERROR or URC(since max resp length is already in buffer)
// return so data could be read
if (!prefix && ((_recv_len-_recv_pos) >= _max_resp_length)) {
if (!prefix && ((_recv_len - _recv_pos) >= _max_resp_length)) {
return;
}
if (!fill_buffer()) {
@ -810,8 +770,6 @@ void ATHandler::resp(const char *prefix, bool check_urc)
void ATHandler::resp_start(const char *prefix, bool stop)
{
tr_debug("%s: %s", __func__, prefix);
if (_last_err) {
return;
}
@ -837,7 +795,6 @@ void ATHandler::resp_start(const char *prefix, bool stop)
// check urc because of error as urc
bool ATHandler::info_resp()
{
tr_debug("%s", __func__);
if (_last_err || _resp_stop.found) {
return false;
}
@ -868,7 +825,6 @@ bool ATHandler::info_resp()
bool ATHandler::info_elem(char start_tag)
{
tr_debug("%s: %c", __func__, start_tag);
if (_last_err) {
return false;
}
@ -894,7 +850,6 @@ bool ATHandler::info_elem(char start_tag)
bool ATHandler::consume_char(char ch)
{
tr_debug("%s: %c", __func__, ch);
int read_char = get_char();
if (read_char == -1) {
return false;
@ -909,7 +864,6 @@ bool ATHandler::consume_char(char ch)
bool ATHandler::consume_to_tag(const char *tag, bool consume_tag)
{
tr_debug("%s: %s", __func__, tag);
size_t match_pos = 0;
while (true) {
@ -934,17 +888,15 @@ bool ATHandler::consume_to_tag(const char *tag, bool consume_tag)
bool ATHandler::consume_to_stop_tag()
{
tr_debug("%s", __func__);
if (!_stop_tag || (_stop_tag && _stop_tag->found) || _error_found) {
return true;
}
if (consume_to_tag((const char*)_stop_tag->tag, true)) {
if (consume_to_tag((const char *)_stop_tag->tag, true)) {
return true;
}
tr_debug("consume_to_stop_tag not found");
tr_warn("AT stop tag not found");
set_error(NSAPI_ERROR_DEVICE_ERROR);
return false;
}
@ -955,8 +907,6 @@ void ATHandler::resp_stop()
{
// Do not return on error so that we can consume whatever there is in the buffer
tr_debug("%s", __func__);
if (_current_scope == ElemType) {
information_response_element_stop();
set_scope(InfoType);
@ -981,7 +931,6 @@ void ATHandler::resp_stop()
void ATHandler::information_response_stop()
{
tr_debug("%s", __func__);
if (consume_to_stop_tag()) {
set_scope(RespType);
}
@ -989,7 +938,6 @@ void ATHandler::information_response_stop()
void ATHandler::information_response_element_stop()
{
tr_debug("%s", __func__);
if (consume_to_stop_tag()) {
set_scope(InfoType);
}
@ -1006,27 +954,25 @@ void ATHandler::set_string(char *dest, const char *src, size_t src_len)
dest[src_len] = '\0';
}
const char* ATHandler::mem_str(const char* dest, size_t dest_len, const char* src, size_t src_len)
const char *ATHandler::mem_str(const char *dest, size_t dest_len, const char *src, size_t src_len)
{
if (dest_len > src_len) {
for(size_t i = 0; i < dest_len-src_len+1; ++i) {
if(memcmp(dest+i, src, src_len) == 0) {
return dest+i;
for(size_t i = 0; i < dest_len - src_len + 1; ++i) {
if(memcmp(dest + i, src, src_len) == 0) {
return dest + i;
}
}
}
return NULL;
}
void ATHandler::cmd_start(const char* cmd)
void ATHandler::cmd_start(const char *cmd)
{
if (_at_send_delay) {
rtos::Thread::wait_until(_last_response_stop + _at_send_delay);
}
at_debug("AT cmd %s (err %d)\n", cmd, _last_err);
if (_last_err != NSAPI_ERROR_OK) {
return;
}
@ -1038,7 +984,6 @@ void ATHandler::cmd_start(const char* cmd)
void ATHandler::write_int(int32_t param)
{
at_debug("AT int %d\n", param);
// do common checks before sending subparameter
if (check_cmd_send() == false) {
return;
@ -1053,9 +998,8 @@ void ATHandler::write_int(int32_t param)
}
}
void ATHandler::write_string(const char* param, bool useQuotations)
void ATHandler::write_string(const char *param, bool useQuotations)
{
at_debug("AT str %s (with quotes %d)\n", param, useQuotations);
// do common checks before sending subparameter
if (check_cmd_send() == false) {
return;
@ -1076,7 +1020,6 @@ void ATHandler::write_string(const char* param, bool useQuotations)
void ATHandler::cmd_stop()
{
at_debug("AT stop %s (err %d)\n", _output_delimiter, _last_err);
if (_last_err != NSAPI_ERROR_OK) {
return;
}
@ -1086,8 +1029,6 @@ void ATHandler::cmd_stop()
size_t ATHandler::write_bytes(const uint8_t *data, size_t len)
{
at_debug("AT write bytes %d (err %d)\n", len, _last_err);
if (_last_err != NSAPI_ERROR_OK) {
return 0;
}
@ -1101,17 +1042,18 @@ size_t ATHandler::write(const void *data, size_t len)
fhs.fh = _fileHandle;
fhs.events = POLLOUT;
size_t write_len = 0;
for (; write_len < len; ) {
for (; write_len < len;) {
int count = poll(&fhs, 1, poll_timeout());
if (count <= 0 || !(fhs.revents & POLLOUT)) {
set_error(NSAPI_ERROR_DEVICE_ERROR);
return 0;
}
ssize_t ret = _fileHandle->write((uint8_t*)data + write_len, len - write_len);
ssize_t ret = _fileHandle->write((uint8_t *)data + write_len, len - write_len);
if (ret < 0) {
set_error(NSAPI_ERROR_DEVICE_ERROR);
return 0;
}
debug_print((char *)data + write_len, ret);
write_len += (size_t)ret;
}
@ -1145,3 +1087,26 @@ void ATHandler::flush()
reset_buffer();
}
}
void ATHandler::debug_print(char *p, int len)
{
#if MBED_CONF_MBED_TRACE_ENABLE
if (_debug_on) {
mbed_cellular_trace::mutex_wait();
for (ssize_t i = 0; i < len; i++) {
char c = *p++;
if (!isprint(c)) {
if (c == '\r') {
} else if (c == '\n') {
debug("%c", c);
} else {
debug("[%d]", c);
}
} else {
debug("%c", c);
}
}
mbed_cellular_trace::mutex_release();
}
#endif
}

View File

@ -28,8 +28,7 @@
#include "Callback.h"
#include "EventQueue.h"
namespace mbed
{
namespace mbed {
class FileHandle;
@ -64,8 +63,7 @@ struct device_err_t {
*
* Class for sending AT commands and parsing AT responses.
*/
class ATHandler
{
class ATHandler {
public:
/** Constructor
@ -220,7 +218,7 @@ public:
*
* @param cmd AT command to be written to modem
*/
void cmd_start(const char* cmd);
void cmd_start(const char *cmd);
/** Writes integer type AT command subparameter. Starts with the delimiter if not the first param after cmd_start.
* In case of failure when writing, the last error is set to NSAPI_ERROR_DEVICE_ERROR.
@ -236,7 +234,7 @@ public:
* @param param string to be written to modem as AT command subparameter
* @param useQuotations flag indicating whether the string should be included in quotation marks
*/
void write_string(const char* param, bool useQuotations = true);
void write_string(const char *param, bool useQuotations = true);
/** Stops the AT command by writing command-line terminator CR to mark command as finished.
*/
@ -360,17 +358,23 @@ public:
*/
bool consume_to_stop_tag();
/** Sets _debug_on flag.
*
* @param enable value to be set for _debug_on flag
*/
void enable_debug(bool enable);
/** Return the last 3GPP error code.
* @return last 3GPP error code
*/
int get_3gpp_error();
public: // just for debugging
/**
* AT debugging, when enabled will print all data read and written,
* non-printable chars are printed as "[%d]".
*
* AT debug can be enabled at compile time using MBED_CONF_CELLULAR_DEBUG_AT flag or at runtime
* calling set_debug(). Note that MBED_CONF_MBED_TRACE_ENABLE must also be enabled.
*
* @param debug_on Enable/disable debugging
*/
void set_debug(bool debug_on);
private:
// should fit any prefix and int
@ -438,10 +442,10 @@ private:
// Returns true on successful read OR false on timeout.
bool fill_buffer(bool wait_for_timeout = true);
void set_tag(tag_t* tag_dest, const char *tag_seq);
void set_tag(tag_t *tag_dest, const char *tag_seq);
// Rewinds the receiving buffer and compares it against given str.
bool match(const char* str, size_t size);
bool match(const char *str, size_t size);
// Iterates URCs and checks if they match the receiving buffer content.
// If URC match sets the scope to information response and after urc's cb returns
// finishes the information response scope(consumes to CRLF).
@ -495,12 +499,15 @@ private:
*
* @return pointer to first occurrence of src in dest
*/
const char* mem_str(const char* dest, size_t dest_len, const char* src, size_t src_len);
const char *mem_str(const char *dest, size_t dest_len, const char *src, size_t src_len);
// check is urc is already added
bool find_urc_handler(const char *prefix, mbed::Callback<void()> callback);
ssize_t read(char *buf, size_t size, bool read_even_stop_tag, bool hex);
// print contents of a buffer to trace log
void debug_print(char *p, int len);
};
} // namespace mbed

View File

@ -45,7 +45,7 @@ AT_CellularDevice::~AT_CellularDevice()
}
// each parser is associated with one filehandle (that is UART)
ATHandler* AT_CellularDevice::get_at_handler(FileHandle *fileHandle)
ATHandler *AT_CellularDevice::get_at_handler(FileHandle *fileHandle)
{
if (!fileHandle) {
return NULL;
@ -62,7 +62,7 @@ ATHandler* AT_CellularDevice::get_at_handler(FileHandle *fileHandle)
atHandler = new ATHandler(fileHandle, _queue, _default_timeout, "\r", get_send_delay());
if (atHandler) {
if (_modem_debug_on) {
atHandler->enable_debug(_modem_debug_on);
atHandler->set_debug(_modem_debug_on);
}
atHandler->_nextATHandler = _atHandlers;
_atHandlers = atHandler;
@ -71,7 +71,7 @@ ATHandler* AT_CellularDevice::get_at_handler(FileHandle *fileHandle)
return atHandler;
}
void AT_CellularDevice::release_at_handler(ATHandler* at_handler)
void AT_CellularDevice::release_at_handler(ATHandler *at_handler)
{
if (!at_handler) {
return;
@ -92,7 +92,7 @@ void AT_CellularDevice::release_at_handler(ATHandler* at_handler)
break;
} else {
prev = atHandler;
atHandler =atHandler->_nextATHandler;
atHandler = atHandler->_nextATHandler;
}
}
}
@ -234,7 +234,7 @@ void AT_CellularDevice::modem_debug_on(bool on)
ATHandler *atHandler = _atHandlers;
while (atHandler) {
atHandler->enable_debug(_modem_debug_on);
atHandler->set_debug(_modem_debug_on);
atHandler = atHandler->_nextATHandler;
}
}

View File

@ -115,13 +115,13 @@ void AT_CellularNetwork::read_reg_params_and_compare(RegistrationType type)
#if MBED_CONF_MBED_TRACE_ENABLE
switch (reg_status) {
case NotRegistered:
tr_error("not registered");
tr_warn("not registered");
break;
case RegistrationDenied:
tr_error("registration denied");
tr_warn("registration denied");
break;
case Unknown:
tr_error("registration status unknown");
tr_warn("registration status unknown");
break;
default:
break;
@ -168,27 +168,27 @@ nsapi_error_t AT_CellularNetwork::set_credentials(const char *apn,
{
size_t len;
if (apn && (len = strlen(apn)) > 0) {
_apn = (char*)malloc(len*sizeof(char)+1);
_apn = (char *)malloc(len * sizeof(char) + 1);
if (_apn) {
memcpy(_apn, apn, len+1);
memcpy(_apn, apn, len + 1);
} else {
return NSAPI_ERROR_NO_MEMORY;
}
}
if (username && (len = strlen(username)) > 0) {
_uname = (char*)malloc(len*sizeof(char)+1);
_uname = (char *)malloc(len * sizeof(char) + 1);
if (_uname) {
memcpy(_uname, username, len+1);
memcpy(_uname, username, len + 1);
} else {
return NSAPI_ERROR_NO_MEMORY;
}
}
if (password && (len = strlen(password)) > 0) {
_pwd = (char*)malloc(len*sizeof(char)+1);
_pwd = (char *)malloc(len * sizeof(char) + 1);
if (_pwd) {
memcpy(_pwd, password, len+1);
memcpy(_pwd, password, len + 1);
} else {
return NSAPI_ERROR_NO_MEMORY;
}
@ -277,7 +277,7 @@ nsapi_error_t AT_CellularNetwork::activate_context()
_at.resp_stop();
if (!_is_context_active) {
tr_info("Activate PDP context %d",_cid);
tr_info("Activate PDP context %d", _cid);
_at.cmd_start("AT+CGACT=1,");
_at.write_int(_cid);
_at.cmd_stop();
@ -462,7 +462,7 @@ bool AT_CellularNetwork::set_new_context(int cid)
}
}
char pdp_type[8+1] = {0};
char pdp_type[8 + 1] = {0};
switch (tmp_stack) {
case IPV4_STACK:
@ -541,7 +541,7 @@ bool AT_CellularNetwork::get_context()
if (pdp_type_len > 0) {
apn_len = _at.read_string(apn, sizeof(apn) - 1);
if (apn_len >= 0) {
if (_apn && (strcmp(apn, _apn) != 0) ) {
if (_apn && (strcmp(apn, _apn) != 0)) {
continue;
}
nsapi_ip_stack_t pdp_stack = string_to_stack_type(pdp_type_from_context);
@ -571,7 +571,7 @@ bool AT_CellularNetwork::get_context()
_cid = cid;
break;
}
// If PDP is IPV4 or IPV6 they are already checked if supported
// If PDP is IPV4 or IPV6 they are already checked if supported
} else {
_ip_stack_type = pdp_stack;
_cid = cid;
@ -590,16 +590,16 @@ bool AT_CellularNetwork::get_context()
}
_at.resp_stop();
if (_cid == -1) { // no suitable context was found so create a new one
if (!set_new_context(cid_max+1)) {
if (!set_new_context(cid_max + 1)) {
return false;
}
}
// save the apn
if (apn_len > 0 && !_apn) {
_apn = (char*)malloc(apn_len*sizeof(char)+1);
_apn = (char *)malloc(apn_len * sizeof(char) + 1);
if (_apn) {
memcpy(_apn, apn, apn_len+1);
memcpy(_apn, apn, apn_len + 1);
} else {
return false;
}
@ -609,7 +609,7 @@ bool AT_CellularNetwork::get_context()
return true;
}
nsapi_ip_stack_t AT_CellularNetwork::string_to_stack_type(const char* pdp_type)
nsapi_ip_stack_t AT_CellularNetwork::string_to_stack_type(const char *pdp_type)
{
nsapi_ip_stack_t stack = DEFAULT_STACK;
int len = strlen(pdp_type);
@ -649,7 +649,7 @@ nsapi_error_t AT_CellularNetwork::set_registration_urc(RegistrationType type, bo
}
}
nsapi_error_t AT_CellularNetwork::get_network_registering_mode(NWRegisteringMode& mode)
nsapi_error_t AT_CellularNetwork::get_network_registering_mode(NWRegisteringMode &mode)
{
_at.lock();
_at.cmd_start("AT+COPS?");
@ -700,12 +700,12 @@ void AT_CellularNetwork::read_reg_params(RegistrationType type, RegistrationStat
reg_status = (RegistrationStatus)_at.read_int();
int len = _at.read_string(lac_string, LAC_LENGTH);
if (memcmp(lac_string, "ffff", LAC_LENGTH-1) && len >= 0) {
if (memcmp(lac_string, "ffff", LAC_LENGTH - 1) && len >= 0) {
lac_read = true;
}
len = _at.read_string(cell_id_string, CELL_ID_LENGTH);
if (memcmp(cell_id_string, "ffffffff", CELL_ID_LENGTH-1) && len >= 0) {
if (memcmp(cell_id_string, "ffffffff", CELL_ID_LENGTH - 1) && len >= 0) {
cell_id_read = true;
}
@ -713,12 +713,12 @@ void AT_CellularNetwork::read_reg_params(RegistrationType type, RegistrationStat
if (lac_read) {
lac = hex_str_to_int(lac_string, LAC_LENGTH);
tr_debug("lac %s %d", lac_string, lac );
tr_debug("lac %s %d", lac_string, lac);
}
if (cell_id_read) {
cell_id = hex_str_to_int(cell_id_string, CELL_ID_LENGTH);
tr_debug("cell_id %s %d", cell_id_string, cell_id );
tr_debug("cell_id %s %d", cell_id_string, cell_id);
}
}
@ -892,7 +892,7 @@ nsapi_error_t AT_CellularNetwork::set_access_technology_impl(RadioAccessTechnolo
return NSAPI_ERROR_UNSUPPORTED;
}
nsapi_error_t AT_CellularNetwork::get_access_technology(RadioAccessTechnology& rat)
nsapi_error_t AT_CellularNetwork::get_access_technology(RadioAccessTechnology &rat)
{
rat = _current_act;
return NSAPI_ERROR_OK;
@ -942,7 +942,7 @@ nsapi_error_t AT_CellularNetwork::scan_plmn(operList_t &operators, int &opsCount
// Optional - try read an int
ret = _at.read_int();
op->op_rat = (ret == error_code) ? RAT_UNKNOWN:(RadioAccessTechnology)ret;
op->op_rat = (ret == error_code) ? RAT_UNKNOWN : (RadioAccessTechnology)ret;
if ((_op_act == RAT_UNKNOWN) ||
((op->op_rat != RAT_UNKNOWN) && (op->op_rat == _op_act))) {
@ -975,8 +975,8 @@ nsapi_error_t AT_CellularNetwork::set_ciot_optimization_config(Supported_UE_Opt
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularNetwork::get_ciot_optimization_config(Supported_UE_Opt& supported_opt,
Preferred_UE_Opt& preferred_opt)
nsapi_error_t AT_CellularNetwork::get_ciot_optimization_config(Supported_UE_Opt &supported_opt,
Preferred_UE_Opt &preferred_opt)
{
_at.lock();
@ -1013,7 +1013,7 @@ nsapi_error_t AT_CellularNetwork::get_rate_control(
int next_element = _at.read_int();
if (next_element >= 0) {
reports = (RateControlExceptionReports)next_element;
tr_debug("reports %d",reports);
tr_debug("reports %d", reports);
next_element = _at.read_int();
} else {
comma_found = false;
@ -1021,7 +1021,7 @@ nsapi_error_t AT_CellularNetwork::get_rate_control(
if (comma_found && next_element >= 0) {
timeUnit = (RateControlUplinkTimeUnit)next_element;
tr_debug("time %d",timeUnit);
tr_debug("time %d", timeUnit);
next_element = _at.read_int();
} else {
comma_found = false;
@ -1029,7 +1029,7 @@ nsapi_error_t AT_CellularNetwork::get_rate_control(
if (comma_found && next_element >= 0) {
uplinkRate = next_element;
tr_debug("rate %d",uplinkRate);
tr_debug("rate %d", uplinkRate);
}
}
_at.resp_stop();
@ -1039,16 +1039,16 @@ nsapi_error_t AT_CellularNetwork::get_rate_control(
return (ret == NSAPI_ERROR_OK) ? NSAPI_ERROR_OK : NSAPI_ERROR_PARAMETER;
}
nsapi_error_t AT_CellularNetwork::get_pdpcontext_params(pdpContextList_t& params_list)
nsapi_error_t AT_CellularNetwork::get_pdpcontext_params(pdpContextList_t &params_list)
{
const int ipv6_subnet_size = 128;
const int max_ipv6_size = 64;
char* ipv6_and_subnetmask = (char*)malloc(ipv6_subnet_size);
char *ipv6_and_subnetmask = (char *)malloc(ipv6_subnet_size);
if (!ipv6_and_subnetmask) {
return NSAPI_ERROR_NO_MEMORY;
}
char* temp = (char*)malloc(max_ipv6_size);
char *temp = (char *)malloc(max_ipv6_size);
if (!temp) {
free(ipv6_and_subnetmask);
return NSAPI_ERROR_NO_MEMORY;

View File

@ -38,7 +38,7 @@ nsapi_error_t AT_CellularSIM::get_sim_state(SimState &state)
_at.cmd_start("AT+CPIN?");
_at.cmd_stop();
_at.resp_start("+CPIN:");
ssize_t len = _at.read_string(simstr, sizeof (simstr));
ssize_t len = _at.read_string(simstr, sizeof(simstr));
if (len != -1) {
if (len >= 5 && memcmp(simstr, "READY", 5) == 0) {
state = SimStateReady;
@ -61,13 +61,13 @@ nsapi_error_t AT_CellularSIM::get_sim_state(SimState &state)
#if MBED_CONF_MBED_TRACE_ENABLE
switch (state) {
case SimStatePinNeeded:
tr_error("SIM PIN required");
tr_info("SIM PIN required");
break;
case SimStatePukNeeded:
tr_error("SIM PUK required");
break;
case SimStateUnknown:
tr_error("SIM state unknown");
tr_warn("SIM state unknown");
break;
default:
tr_info("SIM is ready");
@ -134,7 +134,7 @@ nsapi_error_t AT_CellularSIM::set_pin_query(const char *sim_pin, bool query_pin)
return _at.unlock_return_error();
}
nsapi_error_t AT_CellularSIM::get_imsi(char* imsi)
nsapi_error_t AT_CellularSIM::get_imsi(char *imsi)
{
_at.lock();
_at.cmd_start("AT+CIMI");

View File

@ -0,0 +1,61 @@
/*
* Copyright (c) , Arm Limited and affiliates.
* SPDX-License-Identifier: Apache-2.0
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "CellularLog.h"
#if MBED_CONF_MBED_TRACE_ENABLE
namespace mbed_cellular_trace {
typedef struct trace_s {
void (*mutex_wait_f)(void);
void (*mutex_release_f)(void);
} trace_t;
static trace_t m_trace = {
.mutex_wait_f = 0,
.mutex_release_f = 0,
};
void mutex_wait_function_set(void (*mutex_wait_f)(void))
{
m_trace.mutex_wait_f = mutex_wait_f;
}
void mutex_release_function_set(void (*mutex_release_f)(void))
{
m_trace.mutex_release_f = mutex_release_f;
}
void mutex_wait()
{
if (m_trace.mutex_wait_f) {
m_trace.mutex_wait_f();
}
}
void mutex_release()
{
if (m_trace.mutex_release_f) {
m_trace.mutex_release_f();
}
}
} // namespace mbed_cellular_trace
#endif // MBED_CONF_MBED_TRACE_ENABLE

View File

@ -18,24 +18,26 @@
#ifndef CELLULAR_LOG_H_
#define CELLULAR_LOG_H_
#include "rtos.h"
#if defined(HAVE_DEBUG) && !defined(FEA_TRACE_SUPPORT)
#define FEA_TRACE_SUPPORT
#endif
#if defined(FEATURE_COMMON_PAL)
#include "mbed-trace/mbed_trace.h"
#ifndef TRACE_GROUP
#define TRACE_GROUP "cellular"
#define TRACE_GROUP "CELL"
#endif // TRACE_GROUP
#else
#define tr_debug(...) (void(0))
#define tr_info(...) (void(0))
#define tr_error(...) (void(0))
#define tr_warn(...) (void(0))
#endif // FEATURE_COMMON_PAL
/**
* Set mutex wait/release functions for 'tr_' macros,
* implementation here is modified from that found from mbed_trace.
*/
namespace mbed_cellular_trace {
void mutex_wait_function_set(void (*mutex_wait_f)(void));
void mutex_release_function_set(void (*mutex_release_f)(void));
void mutex_wait();
void mutex_release();
}
#endif // CELLULAR_LOG_H_

View File

@ -8,6 +8,10 @@
"random_max_start_delay": {
"help": "Maximum random delay value used in start-up sequence in milliseconds",
"value": 0
},
"debug-at": {
"help": "Enable AT debug prints",
"value": false
}
}
}