Cellular: Add BG96 AT driver with DNS support

pull/11082/head
Ari Parkkila 2019-07-21 22:50:40 -07:00
parent 417a9fe2fb
commit 71c7ed2fb4
6 changed files with 148 additions and 8 deletions

View File

@ -35,15 +35,15 @@ void ASYNCHRONOUS_DNS_CANCEL()
data[i].semaphore = &semaphore;
data[i].req_result = get_interface()->gethostbyname_async(dns_test_hosts[i],
mbed::Callback<void(nsapi_error_t, SocketAddress *)>(hostbyname_cb, (void *) &data[i]));
TEST_ASSERT(data[i].req_result >= 0 || data[i].req_result == NSAPI_ERROR_NO_MEMORY);
TEST_ASSERT(data[i].req_result >= 0 || data[i].req_result == NSAPI_ERROR_NO_MEMORY || data[i].req_result == NSAPI_ERROR_BUSY);
if (data[i].req_result >= 0) {
// Callback will be called
count++;
} else {
// No memory to initiate DNS query, callback will not be called
printf("Error: No memory to initiate DNS query for %s\n", dns_test_hosts[i]);
data[i].result = NSAPI_ERROR_NO_MEMORY;
printf("Error: No resources to initiate DNS query for %s\n", dns_test_hosts[i]);
data[i].result = data[i].req_result;
data[i].value_set = true;
}
}
@ -66,7 +66,7 @@ void ASYNCHRONOUS_DNS_CANCEL()
printf("DNS: query \"%s\" => cancel\n", dns_test_hosts[i]);
continue;
}
TEST_ASSERT(data[i].result == NSAPI_ERROR_OK || data[i].result == NSAPI_ERROR_NO_MEMORY || data[i].result == NSAPI_ERROR_DNS_FAILURE || data[i].result == NSAPI_ERROR_TIMEOUT);
TEST_ASSERT(data[i].result == NSAPI_ERROR_OK || data[i].result == NSAPI_ERROR_NO_MEMORY || data[i].result == NSAPI_ERROR_BUSY || data[i].result == NSAPI_ERROR_DNS_FAILURE || data[i].result == NSAPI_ERROR_TIMEOUT);
if (data[i].result == NSAPI_ERROR_OK) {
printf("DNS: query \"%s\" => \"%s\"\n",
dns_test_hosts[i], data[i].addr.get_ip_address());
@ -76,6 +76,8 @@ void ASYNCHRONOUS_DNS_CANCEL()
printf("DNS: query \"%s\" => timeout\n", dns_test_hosts[i]);
} else if (data[i].result == NSAPI_ERROR_NO_MEMORY) {
printf("DNS: query \"%s\" => no memory\n", dns_test_hosts[i]);
} else if (data[i].result == NSAPI_ERROR_BUSY) {
printf("DNS: query \"%s\" => busy\n", dns_test_hosts[i]);
}
}

View File

@ -19,8 +19,12 @@
#define DNS_TESTS_H
#ifndef MBED_CONF_APP_DNS_SIMULT_QUERIES
#ifdef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES
#define MBED_CONF_APP_DNS_SIMULT_QUERIES MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES
#else
#define MBED_CONF_APP_DNS_SIMULT_QUERIES 5
#endif
#endif
#ifndef MBED_CONF_NSAPI_DNS_CACHE_SIZE
#define MBED_CONF_NSAPI_DNS_CACHE_SIZE 3

View File

@ -70,13 +70,13 @@ void do_asynchronous_gethostbyname(const char hosts[][DNS_TEST_HOST_LEN], unsign
for (unsigned int i = 0; i < op_count; i++) {
data[i].semaphore = &semaphore;
nsapi_error_t err = net->gethostbyname_async(hosts[i], mbed::Callback<void(nsapi_error_t, SocketAddress *)>(hostbyname_cb, (void *) &data[i]));
TEST_ASSERT(err >= 0 || err == NSAPI_ERROR_NO_MEMORY);
TEST_ASSERT(err >= 0 || err == NSAPI_ERROR_NO_MEMORY || err == NSAPI_ERROR_BUSY);
if (err >= 0) {
// Callback will be called
count++;
} else {
// No memory to initiate DNS query, callback will not be called
data[i].result = NSAPI_ERROR_NO_MEMORY;
data[i].result = err;
}
}
@ -87,7 +87,7 @@ void do_asynchronous_gethostbyname(const char hosts[][DNS_TEST_HOST_LEN], unsign
// Print result
for (unsigned int i = 0; i < op_count; i++) {
TEST_ASSERT(data[i].result == NSAPI_ERROR_OK || data[i].result == NSAPI_ERROR_NO_MEMORY || data[i].result == NSAPI_ERROR_DNS_FAILURE || data[i].result == NSAPI_ERROR_TIMEOUT);
TEST_ASSERT(data[i].result == NSAPI_ERROR_OK || data[i].result == NSAPI_ERROR_NO_MEMORY || data[i].result == NSAPI_ERROR_BUSY || data[i].result == NSAPI_ERROR_DNS_FAILURE || data[i].result == NSAPI_ERROR_TIMEOUT);
if (data[i].result == NSAPI_ERROR_OK) {
(*exp_ok)++;
printf("DNS: query \"%s\" => \"%s\"\n",
@ -101,6 +101,9 @@ void do_asynchronous_gethostbyname(const char hosts[][DNS_TEST_HOST_LEN], unsign
} else if (data[i].result == NSAPI_ERROR_NO_MEMORY) {
(*exp_no_mem)++;
printf("DNS: query \"%s\" => no memory\n", hosts[i]);
} else if (data[i].result == NSAPI_ERROR_BUSY) {
(*exp_no_mem)++;
printf("DNS: query \"%s\" => busy\n", hosts[i]);
}
}
@ -135,9 +138,12 @@ void do_gethostbyname(const char hosts[][DNS_TEST_HOST_LEN], unsigned int op_cou
} else if (err == NSAPI_ERROR_NO_MEMORY) {
(*exp_no_mem)++;
printf("DNS: query \"%s\" => no memory\n", hosts[i]);
} else if (err == NSAPI_ERROR_BUSY) {
(*exp_no_mem)++;
printf("DNS: query \"%s\" => busy\n", hosts[i]);
} else {
printf("DNS: query \"%s\" => %d, unexpected answer\n", hosts[i], err);
TEST_ASSERT(err == NSAPI_ERROR_OK || err == NSAPI_ERROR_NO_MEMORY || err == NSAPI_ERROR_DNS_FAILURE || err == NSAPI_ERROR_TIMEOUT);
TEST_ASSERT(err == NSAPI_ERROR_OK || err == NSAPI_ERROR_NO_MEMORY || err == NSAPI_ERROR_BUSY || err == NSAPI_ERROR_DNS_FAILURE || err == NSAPI_ERROR_TIMEOUT);
}
}
}
@ -181,12 +187,18 @@ Case cases[] = {
Case("ASYNCHRONOUS_DNS", ASYNCHRONOUS_DNS),
Case("ASYNCHRONOUS_DNS_SIMULTANEOUS", ASYNCHRONOUS_DNS_SIMULTANEOUS),
Case("ASYNCHRONOUS_DNS_SIMULTANEOUS_CACHE", ASYNCHRONOUS_DNS_SIMULTANEOUS_CACHE),
#ifndef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES
Case("ASYNCHRONOUS_DNS_CACHE", ASYNCHRONOUS_DNS_CACHE),
#endif
#if !defined MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES || MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES > MBED_CONF_APP_DNS_TEST_HOSTS_NUM
Case("ASYNCHRONOUS_DNS_NON_ASYNC_AND_ASYNC", ASYNCHRONOUS_DNS_NON_ASYNC_AND_ASYNC),
#endif
Case("ASYNCHRONOUS_DNS_CANCEL", ASYNCHRONOUS_DNS_CANCEL),
#ifndef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES
Case("ASYNCHRONOUS_DNS_EXTERNAL_EVENT_QUEUE", ASYNCHRONOUS_DNS_EXTERNAL_EVENT_QUEUE),
Case("ASYNCHRONOUS_DNS_INVALID_HOST", ASYNCHRONOUS_DNS_INVALID_HOST),
Case("ASYNCHRONOUS_DNS_TIMEOUTS", ASYNCHRONOUS_DNS_TIMEOUTS),
#endif
Case("ASYNCHRONOUS_DNS_SIMULTANEOUS_REPEAT", ASYNCHRONOUS_DNS_SIMULTANEOUS_REPEAT),
Case("SYNCHRONOUS_DNS", SYNCHRONOUS_DNS),
Case("SYNCHRONOUS_DNS_MULTIPLE", SYNCHRONOUS_DNS_MULTIPLE),

View File

@ -21,9 +21,15 @@
using namespace mbed;
QUECTEL_BG96_CellularStack::QUECTEL_BG96_CellularStack(ATHandler &atHandler, int cid, nsapi_ip_stack_t stack_type) : AT_CellularStack(atHandler, cid, stack_type)
#ifdef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES
, _dns_callback(NULL), _dns_version(NSAPI_UNSPEC)
#endif
{
_at.set_urc_handler("+QIURC: \"recv", mbed::Callback<void()>(this, &QUECTEL_BG96_CellularStack::urc_qiurc_recv));
_at.set_urc_handler("+QIURC: \"close", mbed::Callback<void()>(this, &QUECTEL_BG96_CellularStack::urc_qiurc_closed));
#ifdef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES
_at.set_urc_handler("+QIURC: \"dnsgip\",", mbed::Callback<void()>(this, &QUECTEL_BG96_CellularStack::urc_qiurc_dnsgip));
#endif
}
QUECTEL_BG96_CellularStack::~QUECTEL_BG96_CellularStack()
@ -102,6 +108,41 @@ void QUECTEL_BG96_CellularStack::urc_qiurc_closed()
urc_qiurc(URC_CLOSED);
}
#ifdef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES
bool QUECTEL_BG96_CellularStack::read_dnsgip(SocketAddress &address, nsapi_version_t _dns_version)
{
if (_at.read_int() == 0) {
int count = _at.read_int();
_at.skip_param();
for (; count > 0; count--) {
_at.resp_start("+QIURC: \"dnsgip\",");
char ipAddress[NSAPI_IP_SIZE];
_at.read_string(ipAddress, sizeof(ipAddress));
if (address.set_ip_address(ipAddress)) {
if (_dns_version == NSAPI_UNSPEC || _dns_version == address.get_ip_version()) {
return true;
}
}
}
}
return false;
}
void QUECTEL_BG96_CellularStack::urc_qiurc_dnsgip()
{
if (!_dns_callback) {
return;
}
SocketAddress address;
if (read_dnsgip(address, _dns_version)) {
_dns_callback(NSAPI_ERROR_OK, &address);
} else {
_dns_callback(NSAPI_ERROR_DNS_FAILURE, NULL);
}
_dns_callback = NULL;
}
#endif
void QUECTEL_BG96_CellularStack::urc_qiurc(urc_type_t urc_type)
{
_at.lock();
@ -299,3 +340,64 @@ nsapi_size_or_error_t QUECTEL_BG96_CellularStack::socket_recvfrom_impl(CellularS
return recv_len;
}
#ifdef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES
nsapi_error_t QUECTEL_BG96_CellularStack::gethostbyname(const char *host, SocketAddress *address,
nsapi_version_t version, const char *interface_name)
{
(void) interface_name;
MBED_ASSERT(host);
MBED_ASSERT(address);
_at.lock();
if (_dns_callback) {
_at.unlock();
return NSAPI_ERROR_BUSY;
}
if (!address->set_ip_address(host)) {
_at.set_at_timeout(60 * 1000); // from BG96_TCP/IP_AT_Commands_Manual_V1.0
_at.at_cmd_discard("+QIDNSGIP", "=", "%d%s", _cid, host);
_at.resp_start("+QIURC: \"dnsgip\",");
_at.restore_at_timeout();
if (!read_dnsgip(*address, version)) {
_at.unlock();
return NSAPI_ERROR_DNS_FAILURE;
}
}
return _at.unlock_return_error();
}
nsapi_value_or_error_t QUECTEL_BG96_CellularStack::gethostbyname_async(const char *host, hostbyname_cb_t callback,
nsapi_version_t version, const char *interface_name)
{
(void) interface_name;
MBED_ASSERT(host);
MBED_ASSERT(callback);
_at.lock();
if (_dns_callback) {
_at.unlock();
return NSAPI_ERROR_BUSY;
}
_at.at_cmd_discard("+QIDNSGIP", "=", "%d%s", _cid, host);
if (!_at.get_last_error()) {
_dns_callback = callback;
_dns_version = version;
}
return _at.unlock_return_error() ? NSAPI_ERROR_DNS_FAILURE : NSAPI_ERROR_OK;
}
nsapi_error_t QUECTEL_BG96_CellularStack::gethostbyname_async_cancel(int id)
{
_at.lock();
_dns_callback = NULL;
_at.unlock();
return NSAPI_ERROR_OK;
}
#endif

View File

@ -48,6 +48,13 @@ protected: // NetworkStack
virtual nsapi_error_t socket_connect(nsapi_socket_t handle, const SocketAddress &address);
#ifdef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES
virtual nsapi_error_t gethostbyname(const char *host, SocketAddress *address, nsapi_version_t version, const char *interface_name);
virtual nsapi_value_or_error_t gethostbyname_async(const char *host, hostbyname_cb_t callback, nsapi_version_t version = NSAPI_UNSPEC,
const char *interface_name = NULL);
virtual nsapi_error_t gethostbyname_async_cancel(int id);
#endif
protected: // AT_CellularStack
virtual int get_max_socket_count();
@ -73,6 +80,15 @@ private:
void urc_qiurc_closed();
void handle_open_socket_response(int &modem_connect_id, int &err);
#ifdef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES
// URC handler for DNS query
void urc_qiurc_dnsgip();
// read DNS query result
bool read_dnsgip(SocketAddress &address, nsapi_version_t _dns_version);
hostbyname_cb_t _dns_callback;
nsapi_version_t _dns_version;
#endif
};
} // namespace mbed
#endif /* QUECTEL_BG96_CELLULARSTACK_H_ */

View File

@ -20,6 +20,10 @@
"control-plane-opt": {
"help": "Enables control plane CIoT EPS optimization",
"value": false
},
"offload-dns-queries" : {
"help": "Use modem IP stack for DNS queries, null or numeric simultaneous queries",
"value": null
}
}
}