Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cellular: Add BG96 AT driver with DNS support #11082

Merged
merged 1 commit into from
Aug 2, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 6 additions & 4 deletions TESTS/netsocket/dns/asynchronous_dns_cancel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}
Expand All @@ -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());
Expand All @@ -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]);
}
}

Expand Down
4 changes: 4 additions & 0 deletions TESTS/netsocket/dns/dns_tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
20 changes: 16 additions & 4 deletions TESTS/netsocket/dns/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}
}

Expand All @@ -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",
Expand All @@ -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]);
}
}

Expand Down Expand Up @@ -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);
}
}
}
Expand Down Expand Up @@ -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),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -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()
AriParkkila marked this conversation as resolved.
Show resolved Hide resolved
{
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();
Expand Down Expand Up @@ -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)
AriParkkila marked this conversation as resolved.
Show resolved Hide resolved
{
(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)
AriParkkila marked this conversation as resolved.
Show resolved Hide resolved
{
(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);
AriParkkila marked this conversation as resolved.
Show resolved Hide resolved
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
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,13 @@ class QUECTEL_BG96_CellularStack : public AT_CellularStack {

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();
Expand All @@ -73,6 +80,15 @@ class QUECTEL_BG96_CellularStack : public AT_CellularStack {
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_ */
4 changes: 4 additions & 0 deletions features/cellular/mbed_lib.json
Original file line number Diff line number Diff line change
Expand Up @@ -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
}
}
}