diff --git a/TESTS/netsocket/nidd/main.cpp b/TESTS/netsocket/nidd/main.cpp new file mode 100644 index 0000000000..4feabb60ce --- /dev/null +++ b/TESTS/netsocket/nidd/main.cpp @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2019, ARM Limited, All Rights Reserved + * 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. + */ + +#if !defined(MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE) || \ + (MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE != CELLULAR) || \ + !MBED_CONF_CELLULAR_CONTROL_PLANE_OPT +#error [NOT_SUPPORTED] No network configuration found for this target. +#else + +#include "mbed.h" +#include "mbed_trace.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" +#include "utest/utest_stack_trace.h" +#include "nidd_tests.h" + +using namespace utest::v1; + +namespace { +Timer tc_bucket; // Timer to limit a test cases run time +} + +void drop_bad_packets(CellularNonIPSocket &sock, int orig_timeout) +{ + nsapi_error_t err; + sock.set_timeout(0); + while (true) { + err = sock.recv(NULL, 0); + if (err == NSAPI_ERROR_WOULD_BLOCK) { + break; + } + } + sock.set_timeout(orig_timeout); +} + +bool check_oversized_packets(nsapi_error_t error, int &size) +{ + if (error == NSAPI_ERROR_PARAMETER) { +#if MBED_CONF_QUECTEL_BG96_PROVIDE_DEFAULT + size = 100; // see BG96 driver +#else + size = 1280; // see TS 23.060 for MTU recommendations +#endif + return true; + } + return false; +} + +void fill_tx_buffer_ascii(char *buff, size_t len) +{ + for (size_t i = 0; i < len; ++i) { + buff[i] = (rand() % 43) + '0'; + } +} + +void poll_pending_messages(CellularNonIPSocket &sock, int count) +{ + uint8_t buf[100] = {0}; + sock.set_timeout(1000); + for (int i = 0; i < count; i++) { + if (i == 0 || i == 2) { + (void) sock.send("", 0); // poll to clear any remaining MT messages + } + while (sock.recv(buf, sizeof(buf)) > 0) { + } + } +} + +int split2half_rmng_nidd_test_time() +{ + return (nidd_global::TESTS_TIMEOUT - tc_bucket.read()) / 2; +} + +// Test setup +utest::v1::status_t greentea_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(nidd_global::TESTS_TIMEOUT, "default_auto"); + tc_bucket.start(); + return greentea_test_setup_handler(number_of_cases); +} + +void greentea_teardown(const size_t passed, const size_t failed, const failure_t failure) +{ + tc_bucket.stop(); + return greentea_test_teardown_handler(passed, failed, failure); +} + +utest::v1::status_t greentea_case_setup_handler_nidd(const Case *const source, const size_t index_of_case) +{ + return greentea_case_setup_handler(source, index_of_case); +} + +utest::v1::status_t greentea_case_teardown_handler_nidd(const Case *const source, const size_t passed, const size_t failed, const failure_t failure) +{ + return greentea_case_teardown_handler(source, passed, failed, failure); +} + +static void test_failure_handler(const failure_t failure) +{ + UTEST_LOG_FUNCTION(); + if (failure.location == LOCATION_TEST_SETUP || failure.location == LOCATION_TEST_TEARDOWN) { + verbose_test_failure_handler(failure); + GREENTEA_TESTSUITE_RESULT(false); + while (1) ; + } +} + +Case cases[] = { + Case("NIDDSOCKET_CONNECT", NIDDSOCKET_CONNECT), + Case("NIDDSOCKET_ECHOTEST_NONBLOCK", NIDDSOCKET_ECHOTEST_NONBLOCK), + Case("NIDDSOCKET_OPEN_CLOSE_REPEAT", NIDDSOCKET_OPEN_CLOSE_REPEAT), + Case("NIDDSOCKET_OPEN_LIMIT", NIDDSOCKET_OPEN_LIMIT), + Case("NIDDSOCKET_OPEN_DESTRUCT", NIDDSOCKET_OPEN_DESTRUCT), + Case("NIDDSOCKET_OPEN_TWICE", NIDDSOCKET_OPEN_TWICE), + Case("NIDDSOCKET_RECV_TIMEOUT", NIDDSOCKET_RECV_TIMEOUT), + Case("NIDDSOCKET_SEND_TIMEOUT", NIDDSOCKET_SEND_TIMEOUT), + Case("NIDDSOCKET_SEND_INVALID", NIDDSOCKET_SEND_INVALID), + Case("NIDDSOCKET_SEND_REPEAT", NIDDSOCKET_SEND_REPEAT), + Case("NIDDSOCKET_DISCONNECT", NIDDSOCKET_DISCONNECT), +}; + +handlers_t nidd_test_case_handlers = { + default_greentea_test_setup_handler, + greentea_test_teardown_handler, + test_failure_handler, + greentea_case_setup_handler_nidd, + greentea_case_teardown_handler_nidd, + greentea_case_failure_continue_handler +}; + +Specification specification(greentea_setup, cases, greentea_teardown, nidd_test_case_handlers); + +int main() +{ + int err = Harness::run(specification); + return !err; +} + +#endif // !defined(MBED_CONF_TARGET_NETWORK_DEFAULT_INTERFACE_TYPE) + diff --git a/TESTS/netsocket/nidd/nidd_tests.h b/TESTS/netsocket/nidd/nidd_tests.h new file mode 100644 index 0000000000..5348330d27 --- /dev/null +++ b/TESTS/netsocket/nidd/nidd_tests.h @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2019, ARM Limited, All Rights Reserved + * 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. + */ + +#ifndef NIDD_TESTS_H +#define NIDD_TESTS_H + +#include "CellularNonIPSocket.h" +#include "CellularLog.h" +#include "../test_params.h" + +NetworkInterface *get_interface(); +void drop_bad_packets(CellularNonIPSocket &sock, int orig_timeout); +bool check_oversized_packets(nsapi_error_t error, int &size); +void fill_tx_buffer_ascii(char *buff, size_t len); +void poll_pending_messages(CellularNonIPSocket &sock, int count); + +/** + * Single testcase might take only half of the remaining execution time + */ +int split2half_rmng_nidd_test_time(); // [s] + +namespace nidd_global { +#ifdef MBED_GREENTEA_TEST_NIDDSOCKET_TIMEOUT_S +static const int TESTS_TIMEOUT = MBED_GREENTEA_TEST_NIDDSOCKET_TIMEOUT_S; +#else +static const int TESTS_TIMEOUT = (3 * 60); +#endif +static const int SOCKET_SEND_COUNT = 4; +} + +/* + * Test cases + */ +void NIDDSOCKET_CONNECT(); +void NIDDSOCKET_DISCONNECT(); +void NIDDSOCKET_OPEN_CLOSE_REPEAT(); +void NIDDSOCKET_OPEN_LIMIT(); +void NIDDSOCKET_RECV_TIMEOUT(); +void NIDDSOCKET_SEND_TIMEOUT(); +void NIDDSOCKET_OPEN_DESTRUCT(); +void NIDDSOCKET_OPEN_TWICE(); +void NIDDSOCKET_SEND_INVALID(); +void NIDDSOCKET_ECHOTEST_NONBLOCK(); +void NIDDSOCKET_SEND_REPEAT(); + +#endif //NIDD_TESTS_H diff --git a/TESTS/netsocket/nidd/niddsocket_connect.cpp b/TESTS/netsocket/nidd/niddsocket_connect.cpp new file mode 100644 index 0000000000..1fd9af8ddf --- /dev/null +++ b/TESTS/netsocket/nidd/niddsocket_connect.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019, ARM Limited, All Rights Reserved + * 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 "greentea-client/test_env.h" +#include "mbed.h" +#include "nidd_tests.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + +void NIDDSOCKET_CONNECT() +{ + // power off modem for an initial state + CellularDevice *dev = CellularDevice::get_default_instance(); + (void) dev->shutdown(); // modem may not be powered or ready yet + TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, dev->soft_power_off()); + TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, dev->hard_power_off()); + + CellularContext *ctx = CellularContext::get_default_nonip_instance(); + ctx->set_default_parameters(); + nsapi_error_t err = ctx->connect(); + TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, err); +} diff --git a/TESTS/netsocket/nidd/niddsocket_disconnect.cpp b/TESTS/netsocket/nidd/niddsocket_disconnect.cpp new file mode 100644 index 0000000000..951ac21fba --- /dev/null +++ b/TESTS/netsocket/nidd/niddsocket_disconnect.cpp @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2019, ARM Limited, All Rights Reserved + * 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 "greentea-client/test_env.h" +#include "mbed.h" +#include "nidd_tests.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + +void NIDDSOCKET_DISCONNECT() +{ + nsapi_error_t err = CellularContext::get_default_nonip_instance()->disconnect(); + TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, err); +} diff --git a/TESTS/netsocket/nidd/niddsocket_echotest.cpp b/TESTS/netsocket/nidd/niddsocket_echotest.cpp new file mode 100755 index 0000000000..22f1d42feb --- /dev/null +++ b/TESTS/netsocket/nidd/niddsocket_echotest.cpp @@ -0,0 +1,136 @@ +/* + * Copyright (c) 2019, ARM Limited, All Rights Reserved + * 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 "mbed.h" +#include "EventFlags.h" +#include "greentea-client/test_env.h" +#include "nidd_tests.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + +namespace { +const int SIGNAL_SIGIO_RX = 0x1; +const int SIGNAL_SIGIO_TX = 0x2; +const int SIGIO_TIMEOUT = 1000; //[ms] +const int RETRIES = 2; + +const double EXPECTED_LOSS_RATIO = 0.0; +const double TOLERATED_LOSS_RATIO = 0.5; + +CellularNonIPSocket *sock; +EventFlags signals; + +const int NIDD_BUFF_SIZE = 100; +char rx_buffer[NIDD_BUFF_SIZE] = {0}; +char tx_buffer[NIDD_BUFF_SIZE] = {0}; + +const int PKTS = 11; +const int pkt_sizes[PKTS] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, NIDD_BUFF_SIZE}; +Timer tc_exec_time; +int time_allotted; +} + +static void _sigio_handler() +{ + signals.set(SIGNAL_SIGIO_RX | SIGNAL_SIGIO_TX); +} + +void NIDDSOCKET_ECHOTEST_NONBLOCK() +{ + tc_exec_time.start(); + time_allotted = split2half_rmng_nidd_test_time(); // [s] + + sock = new CellularNonIPSocket(); + if (sock == NULL) { + TEST_FAIL_MESSAGE("NIDDSocket not created"); + return; + } + TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock->open(CellularContext::get_default_nonip_instance())); + sock->set_blocking(false); + sock->sigio(callback(_sigio_handler)); + + int sent; + int packets_sent = 0; + int packets_recv = 0; + int recvd = 0; + for (unsigned int s_idx = 0; s_idx < sizeof(pkt_sizes) / sizeof(*pkt_sizes); ++s_idx) { + int pkt_s = pkt_sizes[s_idx]; + int packets_sent_prev = packets_sent; + for (int retry_cnt = 0; retry_cnt <= RETRIES; retry_cnt++) { + fill_tx_buffer_ascii(tx_buffer, pkt_s); + tx_buffer[pkt_s] = '\0'; + sent = sock->send(tx_buffer, pkt_s); + if (sent == pkt_s) { + packets_sent++; + } else if (sent == NSAPI_ERROR_WOULD_BLOCK) { + if (tc_exec_time.read() >= time_allotted || + signals.wait_all(SIGNAL_SIGIO_TX, SIGIO_TIMEOUT) == osFlagsErrorTimeout) { + continue; + } + --retry_cnt; + } else { + tr_warn("send %d, error %d\n", s_idx, sent); + continue; + } + + for (int retry_recv = 0; retry_recv <= RETRIES; retry_recv++) { + recvd = sock->recv(rx_buffer, pkt_s); + rx_buffer[recvd] = '\0'; + if (recvd == NSAPI_ERROR_WOULD_BLOCK) { + if (tc_exec_time.read() >= time_allotted) { + tr_warn("recv timeout (%d)", time_allotted); + break; + } + signals.wait_all(SIGNAL_SIGIO_RX, SIGIO_TIMEOUT); + --retry_recv; + continue; + } else if (recvd < 0) { + tr_warn("sock.recvfrom error %d\n", recvd); + TEST_FAIL(); + break; + } else if (recvd == pkt_s) { + break; + } + } + + if (recvd == pkt_s) { + break; + } + } + // Make sure that at least one packet of every size was sent. + TEST_ASSERT_TRUE(packets_sent > packets_sent_prev); + if (recvd != pkt_s) { + tr_warn("send/recv size %d/%d", pkt_s, recvd); + } else if (memcmp(tx_buffer, rx_buffer, pkt_s) != 0) { + tr_warn("send/recv payload mismatch"); + } else { + packets_recv++; + } + } + + // Packet loss up to 30% tolerated + if (packets_sent > 0) { + double loss_ratio = 1 - ((double)packets_recv / (double)packets_sent); + tr_info("Packets sent: %d, packets received %d, loss ratio %.2lf", packets_sent, packets_recv, loss_ratio); + TEST_ASSERT_DOUBLE_WITHIN(TOLERATED_LOSS_RATIO, EXPECTED_LOSS_RATIO, loss_ratio); + } + TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock->close()); + delete sock; + tc_exec_time.stop(); +} diff --git a/TESTS/netsocket/nidd/niddsocket_open_close_repeat.cpp b/TESTS/netsocket/nidd/niddsocket_open_close_repeat.cpp new file mode 100644 index 0000000000..9ac194c6fb --- /dev/null +++ b/TESTS/netsocket/nidd/niddsocket_open_close_repeat.cpp @@ -0,0 +1,38 @@ +/* + * Copyright (c) 2019, ARM Limited, All Rights Reserved + * 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 "greentea-client/test_env.h" +#include "mbed.h" +#include "nidd_tests.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + +void NIDDSOCKET_OPEN_CLOSE_REPEAT() +{ + CellularNonIPSocket *sock = new CellularNonIPSocket(); + if (!sock) { + TEST_FAIL(); + } + + for (int i = 0; i < 10; i++) { + TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock->open(CellularContext::get_default_nonip_instance())); + TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock->close()); + } + delete sock; +} diff --git a/TESTS/netsocket/nidd/niddsocket_open_destruct.cpp b/TESTS/netsocket/nidd/niddsocket_open_destruct.cpp new file mode 100644 index 0000000000..5f5060a11c --- /dev/null +++ b/TESTS/netsocket/nidd/niddsocket_open_destruct.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019, ARM Limited, All Rights Reserved + * 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 "greentea-client/test_env.h" +#include "mbed.h" +#include "nidd_tests.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + +void NIDDSOCKET_OPEN_DESTRUCT() +{ + for (int i = 0; i < 0; i++) { + CellularNonIPSocket *sock = new CellularNonIPSocket; + if (!sock) { + TEST_FAIL(); + } + TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock->open(CellularContext::get_default_nonip_instance())); + delete sock; + } +} diff --git a/TESTS/netsocket/nidd/niddsocket_open_limit.cpp b/TESTS/netsocket/nidd/niddsocket_open_limit.cpp new file mode 100644 index 0000000000..b87834a45c --- /dev/null +++ b/TESTS/netsocket/nidd/niddsocket_open_limit.cpp @@ -0,0 +1,83 @@ +/* + * Copyright (c) 2019, ARM Limited, All Rights Reserved + * 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 "greentea-client/test_env.h" +#include "mbed.h" +#include "nidd_tests.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + +namespace { +typedef struct CellularNonIPSocketItem { + CellularNonIPSocket *sock; + CellularNonIPSocketItem *next; +} SocketItem; +} + +void NIDDSOCKET_OPEN_LIMIT() +{ + int open_sockets[2] = {0}; + + for (int i = 0; i < 2; i++) { + CellularNonIPSocketItem *socket_list_head = NULL; + CellularNonIPSocketItem *it; + + CellularNonIPSocket *sock; + int ret; + while (true) { + sock = new CellularNonIPSocket(); + if (!sock) { + break; + } + ret = sock->open(CellularContext::get_default_nonip_instance()); + if (ret == NSAPI_ERROR_NO_MEMORY || ret == NSAPI_ERROR_NO_SOCKET) { + delete sock; + break; + } + TEST_ASSERT_EQUAL(ret, NSAPI_ERROR_OK); + + // Hopefully this doesn't interfere when trying to allocate more sockets + it = new CellularNonIPSocketItem; + if (!it) { + delete sock; + break; + } + + it->sock = sock; + // Order of items in the list doesn't matter + it->next = socket_list_head; + socket_list_head = it; + } + + if (!socket_list_head) { + break; + } + CellularNonIPSocketItem *tmp; + for (CellularNonIPSocketItem *it = socket_list_head; it;) { + ++open_sockets[i]; + tmp = it; + it = it->next; + socket_list_head = it; + delete tmp->sock; + delete tmp; + } + } + TEST_ASSERT_EQUAL(open_sockets[0], open_sockets[1]); + TEST_ASSERT(open_sockets[0] == 1); +} diff --git a/TESTS/netsocket/nidd/niddsocket_open_twice.cpp b/TESTS/netsocket/nidd/niddsocket_open_twice.cpp new file mode 100644 index 0000000000..772900021e --- /dev/null +++ b/TESTS/netsocket/nidd/niddsocket_open_twice.cpp @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2019, ARM Limited, All Rights Reserved + * 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 "greentea-client/test_env.h" +#include "mbed.h" +#include "nidd_tests.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + +void NIDDSOCKET_OPEN_TWICE() +{ + CellularNonIPSocket *sock = new CellularNonIPSocket(); + if (!sock) { + TEST_FAIL(); + } + + TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock->open(CellularContext::get_default_nonip_instance())); + TEST_ASSERT_EQUAL(NSAPI_ERROR_PARAMETER, sock->open(CellularContext::get_default_nonip_instance())); + + delete sock; +} diff --git a/TESTS/netsocket/nidd/niddsocket_recv_timeout.cpp b/TESTS/netsocket/nidd/niddsocket_recv_timeout.cpp new file mode 100644 index 0000000000..6a8785851a --- /dev/null +++ b/TESTS/netsocket/nidd/niddsocket_recv_timeout.cpp @@ -0,0 +1,74 @@ +/* + * Copyright (c) 2018, ARM Limited, All Rights Reserved + * 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 "mbed.h" +#include "greentea-client/test_env.h" +#include "unity/unity.h" +#include "utest.h" +#include "nidd_tests.h" + +using namespace utest::v1; + +namespace { +static const int SIGNAL_SIGIO = 0x1; +static const int SIGIO_TIMEOUT = 1000; //[ms] +static const int PKT_NUM = 2; +} + +static void _sigio_handler(osThreadId id) +{ + osSignalSet(id, SIGNAL_SIGIO); +} + +void NIDDSOCKET_RECV_TIMEOUT() +{ + CellularNonIPSocket sock; + TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.open(CellularContext::get_default_nonip_instance())); + sock.set_timeout(100); + sock.sigio(callback(_sigio_handler, ThisThread::get_id())); + + static const int DATA_LEN = 4; + char buff[DATA_LEN] = {0}; + int recvd; + Timer timer; + int pkt_success = 0; + for (int i = 0; i < PKT_NUM; i++) { + memset(buff, 'A', sizeof(buff)); + TEST_ASSERT_EQUAL(DATA_LEN, sock.send(buff, DATA_LEN)); + timer.reset(); + timer.start(); + recvd = sock.recv(buff, sizeof(buff)); + timer.stop(); + + if (recvd == NSAPI_ERROR_WOULD_BLOCK) { + osSignalWait(SIGNAL_SIGIO, SIGIO_TIMEOUT); + if (timer.read_ms() > 150) { + TEST_ASSERT(150 - timer.read_ms() < 51); + } else { + TEST_ASSERT(timer.read_ms() - 150 < 51); + } + continue; + } else if (recvd < 0) { + tr_info("[bt#%02d] network error %d\n", i, recvd); + continue; + } + TEST_ASSERT_EQUAL(DATA_LEN, recvd); + pkt_success++; + } + poll_pending_messages(sock, PKT_NUM); + TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.close()); +} diff --git a/TESTS/netsocket/nidd/niddsocket_send_invalid.cpp b/TESTS/netsocket/nidd/niddsocket_send_invalid.cpp new file mode 100644 index 0000000000..379ffaec39 --- /dev/null +++ b/TESTS/netsocket/nidd/niddsocket_send_invalid.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2019, ARM Limited, All Rights Reserved + * 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 "mbed.h" +#include "greentea-client/test_env.h" +#include "nidd_tests.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + +void NIDDSOCKET_SEND_INVALID() +{ + CellularNonIPSocket sock; + TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.open(CellularContext::get_default_nonip_instance())); + + TEST_ASSERT_EQUAL(sock.send(NULL, 0), NSAPI_ERROR_PARAMETER); + TEST_ASSERT_EQUAL(sock.send(NULL, MBED_CONF_CELLULAR_MAX_CP_DATA_RECV_LEN + 1), NSAPI_ERROR_PARAMETER); + + TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.close()); +} diff --git a/TESTS/netsocket/nidd/niddsocket_send_repeat.cpp b/TESTS/netsocket/nidd/niddsocket_send_repeat.cpp new file mode 100644 index 0000000000..9b04c38ffd --- /dev/null +++ b/TESTS/netsocket/nidd/niddsocket_send_repeat.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2019, ARM Limited, All Rights Reserved + * 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 "mbed.h" +#include "greentea-client/test_env.h" +#include "nidd_tests.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + +void NIDDSOCKET_SEND_REPEAT() +{ + CellularNonIPSocket sock; + TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.open(CellularContext::get_default_nonip_instance())); + + int sent; + Timer timer; + int i; + static const char tx_buffer[] = {'h', 'e', 'l', 'l', 'o'}; + bool oom_earlier = false; // 2 times in a row -> time to give up + for (i = 0; i < nidd_global::SOCKET_SEND_COUNT; i++) { + sent = sock.send(tx_buffer, sizeof(tx_buffer)); + if (sent == NSAPI_ERROR_NO_MEMORY) { + if (oom_earlier) { + break; + } + oom_earlier = true; + ThisThread::sleep_for(1000); + continue; + } + oom_earlier = false; + TEST_ASSERT_EQUAL(sizeof(tx_buffer), sent); + } + poll_pending_messages(sock, nidd_global::SOCKET_SEND_COUNT); + TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.close()); +} diff --git a/TESTS/netsocket/nidd/niddsocket_send_timeout.cpp b/TESTS/netsocket/nidd/niddsocket_send_timeout.cpp new file mode 100644 index 0000000000..a3e2762ce7 --- /dev/null +++ b/TESTS/netsocket/nidd/niddsocket_send_timeout.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2019, ARM Limited, All Rights Reserved + * 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 "mbed.h" +#include "greentea-client/test_env.h" +#include "nidd_tests.h" +#include "unity/unity.h" +#include "utest.h" + +using namespace utest::v1; + +void NIDDSOCKET_SEND_TIMEOUT() +{ + char tx_buffer[4]; + fill_tx_buffer_ascii(tx_buffer, sizeof(tx_buffer)); + + CellularNonIPSocket sock; + TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.open(CellularContext::get_default_nonip_instance())); + + Timer timer; + timer.start(); + int sent = sock.send(tx_buffer, sizeof(tx_buffer)); + timer.stop(); + TEST_ASSERT_EQUAL(sizeof(tx_buffer), sent); + sock.set_timeout(1000); + + timer.reset(); + timer.start(); + sent = sock.send(tx_buffer, sizeof(tx_buffer)); + timer.stop(); + TEST_ASSERT_EQUAL(sizeof(tx_buffer), sent); + + poll_pending_messages(sock, 2); + TEST_ASSERT_EQUAL(NSAPI_ERROR_OK, sock.close()); +} diff --git a/UNITTESTS/features/cellular/framework/AT/at_cellularcontext/unittest.cmake b/UNITTESTS/features/cellular/framework/AT/at_cellularcontext/unittest.cmake index ef85569424..f1c13669c9 100644 --- a/UNITTESTS/features/cellular/framework/AT/at_cellularcontext/unittest.cmake +++ b/UNITTESTS/features/cellular/framework/AT/at_cellularcontext/unittest.cmake @@ -24,6 +24,7 @@ set(unittest-test-sources stubs/AT_CellularDevice_stub.cpp stubs/AT_CellularStack_stub.cpp stubs/AT_CellularNetwork_stub.cpp + stubs/AT_ControlPlane_netif_stub.cpp stubs/CellularDevice_stub.cpp stubs/CellularStateMachine_stub.cpp stubs/equeue_stub.c diff --git a/UNITTESTS/stubs/AT_CellularContext_stub.cpp b/UNITTESTS/stubs/AT_CellularContext_stub.cpp index 28ae13d425..3e7d023ae3 100644 --- a/UNITTESTS/stubs/AT_CellularContext_stub.cpp +++ b/UNITTESTS/stubs/AT_CellularContext_stub.cpp @@ -198,6 +198,10 @@ bool AT_CellularContext::get_context() return true; } +const char* AT_CellularContext::get_nonip_context_type_str() { + return "Non-IP"; +} + bool AT_CellularContext::set_new_context(int cid) { return true; diff --git a/UNITTESTS/stubs/AT_ControlPlane_netif_stub.cpp b/UNITTESTS/stubs/AT_ControlPlane_netif_stub.cpp new file mode 100644 index 0000000000..8f89a3a6c6 --- /dev/null +++ b/UNITTESTS/stubs/AT_ControlPlane_netif_stub.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2019, 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 "CellularUtil.h" +#include "ThisThread.h" +#include "AT_ControlPlane_netif.h" +#include "CellularLog.h" + +using namespace mbed_cellular_util; + +namespace mbed { + +AT_ControlPlane_netif::AT_ControlPlane_netif(ATHandler &at, int cid, AT_CellularDevice &device) : + _at(at), _cid(cid), _cb(NULL), _data(NULL), _device(device) +{ +} + +AT_ControlPlane_netif::~AT_ControlPlane_netif() +{} + +void AT_ControlPlane_netif::urc_cp_recv() +{ +} + +nsapi_size_or_error_t AT_ControlPlane_netif::send(const void *cpdata, nsapi_size_t cpdata_length) +{ + return cpdata_length; +} + +nsapi_size_or_error_t AT_ControlPlane_netif::recv(void *cpdata, nsapi_size_t cpdata_length) +{ + return cpdata_length; +} + +void AT_ControlPlane_netif::attach(void (*callback)(void *), void *data) +{ +} + +void AT_ControlPlane_netif::data_received() +{ +} + +} //mbed namespace diff --git a/UNITTESTS/target_h/myCellularContext.h b/UNITTESTS/target_h/myCellularContext.h index 482e8174eb..135a0f4511 100644 --- a/UNITTESTS/target_h/myCellularContext.h +++ b/UNITTESTS/target_h/myCellularContext.h @@ -160,6 +160,10 @@ public: return true; }; + const char* get_nonip_context_type_str() { + return "Non-IP"; + } + bool set_new_context(int cid) { return true; diff --git a/features/cellular/framework/AT/ATHandler.cpp b/features/cellular/framework/AT/ATHandler.cpp index 3e0ee67207..ed60d2c699 100644 --- a/features/cellular/framework/AT/ATHandler.cpp +++ b/features/cellular/framework/AT/ATHandler.cpp @@ -491,7 +491,7 @@ bool ATHandler::fill_buffer(bool wait_for_timeout) { // Reset buffer when full if (sizeof(_recv_buff) == _recv_len) { - tr_error("AT overflow"); + tr_warn("AT overflow"); debug_print(_recv_buff, _recv_len, AT_ERR); reset_buffer(); } @@ -1586,7 +1586,7 @@ void ATHandler::debug_print(const char *p, int len, ATType type) } else if (type == AT_TX) { tr_info("AT TX (%2d): %s", len, buffer); } else { - tr_info("AT ERR (%2d): %s", len, buffer); + tr_warn("AT ERR (%2d): %s", len, buffer); } delete [] buffer; @@ -1637,7 +1637,7 @@ void ATHandler::set_send_delay(uint16_t send_delay) _at_send_delay = send_delay; } -void ATHandler::write_hex_string(char *str, size_t size) +void ATHandler::write_hex_string(const char *str, size_t size) { // do common checks before sending subparameter if (check_cmd_send() == false) { diff --git a/features/cellular/framework/AT/ATHandler.h b/features/cellular/framework/AT/ATHandler.h index 2ab937eb6a..b41aae6e53 100644 --- a/features/cellular/framework/AT/ATHandler.h +++ b/features/cellular/framework/AT/ATHandler.h @@ -433,7 +433,7 @@ public: * @param str input buffer to be converted to hex ascii * @param size of the input param str */ - void write_hex_string(char *str, size_t size); + void write_hex_string(const char *str, size_t size); /** Reads as string and converts result to integer. Supports only non-negative integers. * diff --git a/features/cellular/framework/AT/AT_CellularContext.cpp b/features/cellular/framework/AT/AT_CellularContext.cpp index 616c2c7b42..8dcf7d0a2b 100644 --- a/features/cellular/framework/AT/AT_CellularContext.cpp +++ b/features/cellular/framework/AT/AT_CellularContext.cpp @@ -19,6 +19,7 @@ #include "AT_CellularContext.h" #include "AT_CellularNetwork.h" #include "AT_CellularStack.h" +#include "AT_ControlPlane_netif.h" #include "AT_CellularDevice.h" #include "CellularLog.h" #if (DEVICE_SERIAL && DEVICE_INTERRUPTIN) || defined(DOXYGEN_ONLY) @@ -322,6 +323,9 @@ void AT_CellularContext::set_credentials(const char *apn, const char *uname, con // PDP Context handling void AT_CellularContext::delete_current_context() { + if (_cid <= 0) { + return; + } tr_info("Delete context %d", _cid); _at.clear_error(); @@ -426,13 +430,18 @@ bool AT_CellularContext::get_context() return true; } +const char *AT_CellularContext::get_nonip_context_type_str() +{ + return "Non-IP"; +} + bool AT_CellularContext::set_new_context(int cid) { char pdp_type_str[8 + 1] = {0}; pdp_type_t pdp_type = IPV4_PDP_TYPE; if (_nonip_req && _cp_in_use && get_device()->get_property(AT_CellularDevice::PROPERTY_NON_IP_PDP_TYPE)) { - strncpy(pdp_type_str, "Non-IP", sizeof(pdp_type_str)); + strncpy(pdp_type_str, get_nonip_context_type_str(), sizeof(pdp_type_str)); pdp_type = NON_IP_PDP_TYPE; } else if (get_device()->get_property(AT_CellularDevice::PROPERTY_IPV4V6_PDP_TYPE) || (get_device()->get_property(AT_CellularDevice::PROPERTY_IPV4_PDP_TYPE) && @@ -556,7 +565,7 @@ nsapi_error_t AT_CellularContext::find_and_activate_context() } // do check for stack to validate that we have support for stack - if (!get_stack()) { + if (!(_nonip_req && _cp_in_use) && !get_stack()) { _at.unlock(); tr_error("No cellular stack!"); return NSAPI_ERROR_UNSUPPORTED; @@ -962,6 +971,7 @@ void AT_CellularContext::cellular_callback(nsapi_event_t ev, intptr_t ptr) _nw = _device->open_network(_fh); } +#if MBED_CONF_CELLULAR_CONTROL_PLANE_OPT if (_cp_req && !_cp_in_use && (_cb_data.error == NSAPI_ERROR_OK) && (st == CellularSIMStatusChanged && data->status_data == CellularDevice::SimStateReady)) { if (setup_control_plane_opt() != NSAPI_ERROR_OK) { @@ -970,6 +980,7 @@ void AT_CellularContext::cellular_callback(nsapi_event_t ev, intptr_t ptr) tr_info("Control plane SETUP success!"); } } +#endif if (_is_blocking) { if (_cb_data.error != NSAPI_ERROR_OK) { @@ -1044,8 +1055,10 @@ void AT_CellularContext::cellular_callback(nsapi_event_t ev, intptr_t ptr) ControlPlane_netif *AT_CellularContext::get_cp_netif() { - tr_error("No control plane interface available from base context!"); - return NULL; + if (!_cp_netif) { + _cp_netif = new AT_ControlPlane_netif(_at, _cid, *get_device()); + } + return _cp_netif; } nsapi_error_t AT_CellularContext::setup_control_plane_opt() @@ -1068,19 +1081,11 @@ nsapi_error_t AT_CellularContext::setup_control_plane_opt() ciot_opt_ret = _nw->set_ciot_optimization_config(mbed::CellularNetwork::CIOT_OPT_CONTROL_PLANE, mbed::CellularNetwork::PREFERRED_UE_OPT_CONTROL_PLANE, callback(this, &AT_CellularContext::ciot_opt_cb)); - - if (ciot_opt_ret != NSAPI_ERROR_OK) { - return ciot_opt_ret; + if (ciot_opt_ret == NSAPI_ERROR_OK) { + // assume network supports CIoT optimizations until ciot_opt_cb + _cp_in_use = true; } - - //wait for control plane opt call back to release semaphore - _cp_opt_semaphore.try_acquire_for(CP_OPT_NW_REPLY_TIMEOUT); - - if (_cp_in_use) { - return NSAPI_ERROR_OK; - } - - return NSAPI_ERROR_DEVICE_ERROR; + return ciot_opt_ret; } void AT_CellularContext::ciot_opt_cb(mbed::CellularNetwork::CIoT_Supported_Opt ciot_opt) @@ -1088,15 +1093,18 @@ void AT_CellularContext::ciot_opt_cb(mbed::CellularNetwork::CIoT_Supported_Opt if (ciot_opt == mbed::CellularNetwork::CIOT_OPT_CONTROL_PLANE || ciot_opt == mbed::CellularNetwork::CIOT_OPT_BOTH) { _cp_in_use = true; + } else { + _cp_in_use = false; } - _cp_opt_semaphore.release(); } void AT_CellularContext::set_disconnect() { tr_debug("AT_CellularContext::set_disconnect()"); - _is_connected = false; - _device->cellular_callback(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED, this); + if (_is_connected) { + _is_connected = false; + _device->cellular_callback(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED, this); + } } void AT_CellularContext::set_cid(int cid) diff --git a/features/cellular/framework/AT/AT_CellularContext.h b/features/cellular/framework/AT/AT_CellularContext.h index c8aecbf920..ac131bdf24 100644 --- a/features/cellular/framework/AT/AT_CellularContext.h +++ b/features/cellular/framework/AT/AT_CellularContext.h @@ -108,6 +108,10 @@ protected: virtual bool get_context(); AT_CellularDevice::CellularProperty pdp_type_t_to_cellular_property(pdp_type_t pdp_type); bool set_new_context(int cid); + /** Get string name for NIDD context type. + * @return NIDD context text, e.g. Non-IP or NONIP + */ + virtual const char *get_nonip_context_type_str(); private: #if NSAPI_PPP_AVAILABLE diff --git a/features/cellular/framework/AT/AT_CellularNetwork.cpp b/features/cellular/framework/AT/AT_CellularNetwork.cpp index 39bb607eda..d91b45d093 100644 --- a/features/cellular/framework/AT/AT_CellularNetwork.cpp +++ b/features/cellular/framework/AT/AT_CellularNetwork.cpp @@ -375,7 +375,11 @@ nsapi_error_t AT_CellularNetwork::set_ciot_optimization_config(CIoT_Supported_Op Callback network_support_cb) { _ciotopt_network_support_cb = network_support_cb; - return _at.at_cmd_discard("+CCIOTOPT", "=1,", "%d%d", supported_opt, preferred_opt); + nsapi_error_t err = _at.at_cmd_discard("+CRTDCP", "=", "%d", 1); + if (!err) { + err = _at.at_cmd_discard("+CCIOTOPT", "=1,", "%d%d", supported_opt, preferred_opt); + } + return err; } void AT_CellularNetwork::urc_cciotopti() @@ -690,7 +694,7 @@ nsapi_error_t AT_CellularNetwork::clear() } context = context->next; } -#ifdef MBED_CONF_NSAPI_DEFAULT_CELLULAR_APN +#if defined(MBED_CONF_NSAPI_DEFAULT_CELLULAR_APN) && !MBED_CONF_CELLULAR_CONTROL_PLANE_OPT char pdp_type_str[sizeof("IPV4V6")]; if (_device.get_property(AT_CellularDevice::PROPERTY_IPV4V6_PDP_TYPE) || (_device.get_property(AT_CellularDevice::PROPERTY_IPV4_PDP_TYPE) && _device.get_property(AT_CellularDevice::PROPERTY_IPV6_PDP_TYPE))) { diff --git a/features/cellular/framework/AT/AT_CellularNetwork.h b/features/cellular/framework/AT/AT_CellularNetwork.h index 8537d2f5c0..abb6c0793e 100644 --- a/features/cellular/framework/AT/AT_CellularNetwork.h +++ b/features/cellular/framework/AT/AT_CellularNetwork.h @@ -117,7 +117,7 @@ protected: * * @return NSAPI_ERROR_OK on success */ - nsapi_error_t clear(); + virtual nsapi_error_t clear(); private: void urc_creg(); diff --git a/features/cellular/framework/AT/AT_ControlPlane_netif.cpp b/features/cellular/framework/AT/AT_ControlPlane_netif.cpp index cd1f493617..f865b8f99d 100644 --- a/features/cellular/framework/AT/AT_ControlPlane_netif.cpp +++ b/features/cellular/framework/AT/AT_ControlPlane_netif.cpp @@ -1,10 +1,31 @@ -/*AT_ControlPlane_netif.cpp*/ +/* + * Copyright (c) 2019, 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 "CellularUtil.h" +#include "ThisThread.h" #include "AT_ControlPlane_netif.h" +#include "CellularLog.h" + +using namespace mbed_cellular_util; namespace mbed { -AT_ControlPlane_netif::AT_ControlPlane_netif(ATHandler &at, int cid) : - _cid(cid), _cb(NULL), _data(NULL), _recv_len(0), _at(at) +AT_ControlPlane_netif::AT_ControlPlane_netif(ATHandler &at, int cid, AT_CellularDevice &device) : + _cid(cid), _cb(NULL), _data(NULL), _at(at), _device(device) { _at.set_urc_handler("+CRTDCP:", mbed::Callback(this, &AT_ControlPlane_netif::urc_cp_recv)); } @@ -18,44 +39,58 @@ void AT_ControlPlane_netif::urc_cp_recv() _at.lock(); int cid = _at.read_int(); int cpdata_length = _at.read_int(); - int read_len = _at.read_string(_recv_buffer, sizeof(_recv_buffer)); - - _at.unlock(); + if (cpdata_length < 0) { + return; + } + uint8_t *cpdata = new uint8_t[cpdata_length]; + ssize_t read_len = _at.read_hex_string((char *)cpdata, cpdata_length); // cid not expected to be different because: one context - one file handle // so this file handle cannot get urc from different context if (read_len > 0 && read_len == cpdata_length && cid == _cid) { - _recv_len = read_len; + packet_t *packet = _packet_list.add_new(); + packet->data = cpdata; + packet->data_len = cpdata_length; data_received(); + } else { + delete[] cpdata; } + _at.unlock(); } nsapi_size_or_error_t AT_ControlPlane_netif::send(const void *cpdata, nsapi_size_t cpdata_length) { - //CSODCP + if (cpdata_length > MBED_CONF_CELLULAR_MAX_CP_DATA_RECV_LEN) { + return NSAPI_ERROR_PARAMETER; + } + _at.lock(); + _at.cmd_start("AT+CSODCP="); + _at.write_int(_cid); + _at.write_int(cpdata_length); + _at.write_hex_string((char *)cpdata, cpdata_length); + _at.cmd_stop_read_resp(); + nsapi_size_or_error_t err = _at.unlock_return_error(); - nsapi_size_or_error_t err = _at.at_cmd_discard("+CSODCP", "=", "%d%d%b", _cid, cpdata_length, cpdata, cpdata_length); - - return (err == NSAPI_ERROR_OK) ? cpdata_length : err; + return err ? err : cpdata_length; } nsapi_size_or_error_t AT_ControlPlane_netif::recv(void *cpdata, nsapi_size_t cpdata_length) { - // If no data received through CRTDCP URC - if (!_recv_len) { - return NSAPI_ERROR_WOULD_BLOCK; + _at.lock(); + if (_packet_list.count() <= 0) { + (void) send("", 0); // poll for missing +CRTDCP indications + if (_packet_list.count() <= 0) { + return NSAPI_ERROR_WOULD_BLOCK; + } } - - // If too small buffer for data - if (_recv_len > cpdata_length) { - return NSAPI_ERROR_DEVICE_ERROR; - } - - memcpy(cpdata, _recv_buffer, _recv_len); - size_t recv = _recv_len; - _recv_len = 0; - return recv; + packet_t *packet = _packet_list.dequeue(); + int data_len = (cpdata_length >= packet->data_len) ? packet->data_len : cpdata_length; + memcpy(cpdata, packet->data, data_len); + delete[] packet->data; + delete (packet); + _at.unlock(); + return data_len; } void AT_ControlPlane_netif::attach(void (*callback)(void *), void *data) diff --git a/features/cellular/framework/AT/AT_ControlPlane_netif.h b/features/cellular/framework/AT/AT_ControlPlane_netif.h index 13c3895aaf..6c222c90d2 100644 --- a/features/cellular/framework/AT/AT_ControlPlane_netif.h +++ b/features/cellular/framework/AT/AT_ControlPlane_netif.h @@ -1,11 +1,30 @@ +/* + * Copyright (c) 2019, 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 "CellularList.h" #include "ControlPlane_netif.h" #include "ATHandler.h" +#include "AT_CellularDevice.h" namespace mbed { class AT_ControlPlane_netif: public ControlPlane_netif { public: - AT_ControlPlane_netif(ATHandler &at, int cid); + AT_ControlPlane_netif(ATHandler &at, int cid, AT_CellularDevice &device); virtual ~AT_ControlPlane_netif(); protected: @@ -28,15 +47,20 @@ protected: int _cid; private: + struct packet_t { + uint8_t *data; + nsapi_size_t data_len; + packet_t *next; + }; + CellularList _packet_list; void (*_cb)(void *); void *_data; - char _recv_buffer[MBED_CONF_CELLULAR_MAX_CP_DATA_RECV_LEN]; - size_t _recv_len; // Called on receiving URC: +CRTDCP void urc_cp_recv(); protected: ATHandler &_at; + AT_CellularDevice &_device; }; } //mbed namespace diff --git a/features/cellular/framework/common/CellularList.h b/features/cellular/framework/common/CellularList.h index 37f4177447..19803717ea 100644 --- a/features/cellular/framework/common/CellularList.h +++ b/features/cellular/framework/common/CellularList.h @@ -86,6 +86,27 @@ public: delete current; } + int count() + { + T *item = _head; + int n = 0; + while (item) { + item = item->next; + n++; + } + return n; + } + + T *dequeue() + { + if (!_head) { + return NULL; + } + T *temp = _head; + _head = _head->next; + return temp; + } + void delete_all() { T *temp = _head; diff --git a/features/cellular/framework/common/CellularUtil.cpp b/features/cellular/framework/common/CellularUtil.cpp index 7157ecb6a5..07f33c71f5 100644 --- a/features/cellular/framework/common/CellularUtil.cpp +++ b/features/cellular/framework/common/CellularUtil.cpp @@ -378,6 +378,8 @@ pdp_type_t string_to_pdp_type(const char *pdp_type_str) pdp_type = IPV4_PDP_TYPE; } else if (len == 6 && memcmp(pdp_type_str, "Non-IP", len) == 0) { pdp_type = NON_IP_PDP_TYPE; + } else if (len == 5 && memcmp(pdp_type_str, "NONIP", len) == 0) { + pdp_type = NON_IP_PDP_TYPE; } return pdp_type; } diff --git a/features/cellular/framework/device/CellularContext.cpp b/features/cellular/framework/device/CellularContext.cpp index 2531c1cca7..9b6ab19075 100644 --- a/features/cellular/framework/device/CellularContext.cpp +++ b/features/cellular/framework/device/CellularContext.cpp @@ -69,6 +69,10 @@ CellularContext::CellularContext() : _next(0), _stack(0), _pdp_type(DEFAULT_PDP_ void CellularContext::cp_data_received() { + if (!_cp_netif) { + tr_warn("Cellular Non-IP callback missing"); + return; + } _cp_netif->data_received(); } diff --git a/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION.cpp b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION.cpp index 91f8b69ff2..3a0e4f5577 100644 --- a/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION.cpp +++ b/features/cellular/framework/targets/GEMALTO/CINTERION/GEMALTO_CINTERION.cpp @@ -112,6 +112,7 @@ void GEMALTO_CINTERION::init_module_bgs2() 0, // PROPERTY_IPV4V6_STACK 0, // PROPERTY_NON_IP_PDP_TYPE 1, // PROPERTY_AT_CGEREP + 1, // PROPERTY_AT_COPS_FALLBACK_AUTO }; set_cellular_properties(cellular_properties); _module = ModuleBGS2; @@ -136,6 +137,7 @@ void GEMALTO_CINTERION::init_module_els61() 0, // PROPERTY_IPV4V6_STACK 0, // PROPERTY_NON_IP_PDP_TYPE 1, // PROPERTY_AT_CGEREP + 1, // PROPERTY_AT_COPS_FALLBACK_AUTO }; set_cellular_properties(cellular_properties); _module = ModuleELS61; @@ -160,6 +162,7 @@ void GEMALTO_CINTERION::init_module_ems31() 1, // PROPERTY_IPV4V6_STACK 0, // PROPERTY_NON_IP_PDP_TYPE 1, // PROPERTY_AT_CGEREP + 1, // PROPERTY_AT_COPS_FALLBACK_AUTO }; set_cellular_properties(cellular_properties); _module = ModuleEMS31; @@ -175,9 +178,16 @@ void GEMALTO_CINTERION::init_module_ehs5e() 0, // AT_CGSN_WITH_TYPE 1, // AT_CGDATA 1, // AT_CGAUTH + 1, // AT_CNMI + 1, // AT_CSMP + 1, // AT_CMGF + 1, // AT_CSDH 1, // PROPERTY_IPV4_STACK 1, // PROPERTY_IPV6_STACK 0, // PROPERTY_IPV4V6_STACK + 0, // PROPERTY_NON_IP_PDP_TYPE + 1, // PROPERTY_AT_CGEREP + 1, // PROPERTY_AT_COPS_FALLBACK_AUTO }; set_cellular_properties(cellular_properties); _module = ModuleEHS5E; diff --git a/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95.cpp b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95.cpp index 3023bfd4c7..99da14386d 100644 --- a/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95.cpp +++ b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95.cpp @@ -42,7 +42,7 @@ static const intptr_t cellular_properties[AT_CellularDevice::PROPERTY_MAX] = { 1, // PROPERTY_IPV4_STACK 1, // PROPERTY_IPV6_STACK 0, // PROPERTY_IPV4V6_STACK - 0, // PROPERTY_NON_IP_PDP_TYPE + 1, // PROPERTY_NON_IP_PDP_TYPE 0, // PROPERTY_AT_CGEREP, 0, // PROPERTY_AT_COPS_FALLBACK_AUTO }; @@ -89,11 +89,18 @@ nsapi_error_t QUECTEL_BC95::init() _at->lock(); _at->flush(); - _at->at_cmd_discard("", ""); //Send AT - - _at->at_cmd_discard("+CMEE", "=1"); // verbose responses - - return _at->unlock_return_error(); + nsapi_error_t err = _at->at_cmd_discard("", ""); //Send AT + if (!err) { + err = _at->at_cmd_discard("+CMEE", "=1"); // verbose responses + } + if (!err) { + err = _at->at_cmd_discard("+CFUN", "=", "%d", 1); + } + if (!err) { + err = _at->get_last_error(); + } + _at->unlock(); + return err; } nsapi_error_t QUECTEL_BC95::set_baud_rate_impl(int baud_rate) diff --git a/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularContext.cpp b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularContext.cpp index fd298b9d40..51742a796a 100644 --- a/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularContext.cpp +++ b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularContext.cpp @@ -44,4 +44,9 @@ NetworkStack *QUECTEL_BC95_CellularContext::get_stack() } #endif // #if !NSAPI_PPP_AVAILABLE +const char *QUECTEL_BC95_CellularContext::get_nonip_context_type_str() +{ + return "NONIP"; +} + } /* namespace mbed */ diff --git a/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularContext.h b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularContext.h index 074066124d..b5ec9373ad 100644 --- a/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularContext.h +++ b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularContext.h @@ -30,6 +30,7 @@ protected: #if !NSAPI_PPP_AVAILABLE virtual NetworkStack *get_stack(); #endif // #if !NSAPI_PPP_AVAILABLE + virtual const char *get_nonip_context_type_str(); }; } /* namespace mbed */ diff --git a/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularNetwork.cpp b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularNetwork.cpp index ea7d43d86e..483c6d055f 100644 --- a/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularNetwork.cpp +++ b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularNetwork.cpp @@ -38,3 +38,26 @@ nsapi_error_t QUECTEL_BC95_CellularNetwork::set_access_technology_impl(RadioAcce return NSAPI_ERROR_OK; } + +nsapi_error_t QUECTEL_BC95_CellularNetwork::clear() +{ + nsapi_error_t err = AT_CellularNetwork::clear(); +#if MBED_CONF_CELLULAR_CONTROL_PLANE_OPT + if (!err) { + err = _at.at_cmd_discard("+CGDCONT", "=", "%d", 0); +#ifdef MBED_CONF_NSAPI_DEFAULT_CELLULAR_APN + err = _at.at_cmd_discard("+CGDCONT", "=", "%d%s%s", 1, "NONIP", MBED_CONF_NSAPI_DEFAULT_CELLULAR_APN); +#endif + if (!err) { + err = _at.at_cmd_discard("+CIPCA", "=", "%d%d", 3, 1); // EPS Attach without PDN connection + } + if (!err) { + _at.lock(); + _at.cmd_start("AT+NCONFIG=\"AUTOCONNECT\",\"TRUE\""); // disable auto connect to IP context + _at.cmd_stop_read_resp(); + err = _at.unlock_return_error(); + } + } +#endif + return err; +} diff --git a/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularNetwork.h b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularNetwork.h index 1d76316fd8..d0e3e311e0 100644 --- a/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularNetwork.h +++ b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularNetwork.h @@ -29,6 +29,7 @@ public: protected: virtual nsapi_error_t set_access_technology_impl(RadioAccessTechnology opRat); + virtual nsapi_error_t clear(); }; } // namespace mbed #endif // QUECTEL_BC95_CELLULAR_NETWORK_H_ diff --git a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularContext.cpp b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularContext.cpp index a580f0a3f6..f7ed3b40c7 100644 --- a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularContext.cpp +++ b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularContext.cpp @@ -62,7 +62,7 @@ NetworkStack *QUECTEL_BG96_CellularContext::get_stack() ControlPlane_netif *QUECTEL_BG96_CellularContext::get_cp_netif() { if (!_cp_netif) { - _cp_netif = new QUECTEL_BG96_ControlPlane_netif(_at, _cid); + _cp_netif = new QUECTEL_BG96_ControlPlane_netif(_at, _cid, *get_device()); } return _cp_netif; } @@ -84,9 +84,13 @@ nsapi_error_t QUECTEL_BG96_CellularContext::activate_non_ip_context() // Open the NIDD connection nsapi_size_or_error_t ret = _at.at_cmd_discard("+QCFGEXT", "=\"nipd\",1"); - if (ret == NSAPI_ERROR_OK) { - _semaphore.try_acquire_for(NIDD_OPEN_URC_TIMEOUT); + _at.lock(); + _at.set_at_timeout(NIDD_OPEN_URC_TIMEOUT); + _at.resp_start("+QIND:"); + urc_nidd(); + _at.restore_at_timeout(); + _at.unlock(); if (_cid == -1) { return NSAPI_ERROR_NO_CONNECTION; } @@ -142,7 +146,6 @@ void QUECTEL_BG96_CellularContext::urc_nidd_open() } else { tr_error("NIDD connection open failed with error: %d", err); } - _semaphore.release(); } void QUECTEL_BG96_CellularContext::urc_nidd_close() diff --git a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularContext.h b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularContext.h index c3f1a5ec20..4e536c4090 100644 --- a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularContext.h +++ b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularContext.h @@ -37,7 +37,6 @@ protected: virtual void deactivate_non_ip_context(); virtual void deactivate_context(); virtual void activate_context(); - rtos::Semaphore _semaphore; private: void urc_nidd(); diff --git a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_ControlPlane_netif.cpp b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_ControlPlane_netif.cpp index 39ab44fe07..b5646fa610 100644 --- a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_ControlPlane_netif.cpp +++ b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_ControlPlane_netif.cpp @@ -1,27 +1,53 @@ +/* + * Copyright (c) 2018, 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 "CellularUtil.h" #include "QUECTEL_BG96_ControlPlane_netif.h" +#include "CellularLog.h" + +using namespace mbed_cellular_util; namespace mbed { -QUECTEL_BG96_ControlPlane_netif::QUECTEL_BG96_ControlPlane_netif(ATHandler &at, int cid) : AT_ControlPlane_netif(at, cid) +QUECTEL_BG96_ControlPlane_netif::QUECTEL_BG96_ControlPlane_netif(ATHandler &at, int cid, AT_CellularDevice &device) : AT_ControlPlane_netif(at, cid, device) {} nsapi_size_or_error_t QUECTEL_BG96_ControlPlane_netif::send(const void *data, nsapi_size_t size) { - nsapi_size_or_error_t err = _at.at_cmd_discard("+QCFGEXT", "=\"nipds\",0,", "%s%d", data, size); - - if (err == NSAPI_ERROR_OK) { - return size; + if (size > 100) { // from BG96_NIDD_AT_Commands_Manual_V1.0 + return NSAPI_ERROR_PARAMETER; } - return err; + _at.lock(); + _at.cmd_start("AT+QCFGEXT=\"nipds\",1,"); + _at.write_hex_string((const char *)data, size); + _at.write_int(2 * size); + _at.cmd_stop_read_resp(); + nsapi_error_t err = _at.unlock_return_error(); + + return (err == NSAPI_ERROR_OK) ? size : err; } nsapi_size_or_error_t QUECTEL_BG96_ControlPlane_netif::recv(void *buffer, nsapi_size_t size) { _at.lock(); - _at.cmd_start_stop("QCFGEXT", "=", "%s%d", "nipdr", 0); - _at.resp_start("+QCFGEXT: "); + _at.cmd_start_stop("+QCFGEXT", "=", "%s%d", "nipdr", 0); + _at.resp_start("+QCFGEXT:"); // skip 3 params: "nipdr",, _at.skip_param(3); // get to @@ -32,20 +58,22 @@ nsapi_size_or_error_t QUECTEL_BG96_ControlPlane_netif::recv(void *buffer, nsapi_ _at.unlock(); return NSAPI_ERROR_WOULD_BLOCK; } + if ((nsapi_size_t)unread_length > size) { + tr_warn("recv %d/%d", size, unread_length); + unread_length = size; + } - _at.cmd_start_stop("QCFGEXT", "=", "%s%d", "nipdr", unread_length); - + _at.cmd_start_stop("+QCFGEXT", "=", "%s%d%d", "nipdr", unread_length, 1); _at.resp_start("+QCFGEXT:"); - // skip "nipdr" - _at.skip_param(); - int read_length = _at.read_int(); - _at.read_string((char *)buffer, read_length); + _at.skip_param(); // skip "nipdr" + nsapi_size_t read_length = _at.read_int(); + ssize_t read_len = _at.read_hex_string((char *)buffer, read_length); _at.resp_stop(); - nsapi_error_t err = _at.get_last_error(); - _at.unlock(); - if (err == NSAPI_ERROR_OK && read_length) { - return read_length; + nsapi_error_t err = _at.unlock_return_error(); + + if (err == NSAPI_ERROR_OK && read_len) { + return read_len; } return NSAPI_ERROR_WOULD_BLOCK; diff --git a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_ControlPlane_netif.h b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_ControlPlane_netif.h index 917a742808..5b2776f027 100644 --- a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_ControlPlane_netif.h +++ b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_ControlPlane_netif.h @@ -23,7 +23,7 @@ namespace mbed { class QUECTEL_BG96_ControlPlane_netif: public AT_ControlPlane_netif { public: - QUECTEL_BG96_ControlPlane_netif(ATHandler &at, int cid); + QUECTEL_BG96_ControlPlane_netif(ATHandler &at, int cid, AT_CellularDevice &device); virtual ~QUECTEL_BG96_ControlPlane_netif() {}; // ControlPlane_netif diff --git a/features/cellular/framework/targets/UBLOX/AT/UBLOX_AT.cpp b/features/cellular/framework/targets/UBLOX/AT/UBLOX_AT.cpp index dbf92e02b0..88be8ff4dc 100644 --- a/features/cellular/framework/targets/UBLOX/AT/UBLOX_AT.cpp +++ b/features/cellular/framework/targets/UBLOX/AT/UBLOX_AT.cpp @@ -60,6 +60,7 @@ static const intptr_t cellular_properties[AT_CellularDevice::PROPERTY_MAX] = { 0, // PROPERTY_IPV4V6_STACK 0, // PROPERTY_NON_IP_PDP_TYPE 1, // PROPERTY_AT_CGEREP + 1, // PROPERTY_AT_COPS_FALLBACK_AUTO }; #else static const intptr_t cellular_properties[AT_CellularDevice::PROPERTY_MAX] = { @@ -78,6 +79,7 @@ static const intptr_t cellular_properties[AT_CellularDevice::PROPERTY_MAX] = { 0, // PROPERTY_IPV4V6_STACK 0, // PROPERTY_NON_IP_PDP_TYPE 0, // PROPERTY_AT_CGEREP + 0, // PROPERTY_AT_COPS_FALLBACK_AUTO }; #endif diff --git a/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX.cpp b/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX.cpp index 27e69d9365..c27182c093 100644 --- a/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX.cpp +++ b/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX.cpp @@ -34,6 +34,8 @@ static const intptr_t cellular_properties[AT_CellularDevice::PROPERTY_MAX] = { 1, // PROPERTY_IPV4_STACK 0, // PROPERTY_IPV6_STACK 0, // PROPERTY_IPV4V6_STACK + 1, // PROPERTY_NON_IP_PDP_TYPE + 0, // PROPERTY_AT_CGEREP 1, // PROPERTY_AT_COPS_FALLBACK_AUTO }; @@ -59,6 +61,11 @@ void UBLOX_N2XX::NPIN_URC() _at->read_string(simstr, sizeof(simstr)); } +AT_CellularNetwork *UBLOX_N2XX::open_network_impl(ATHandler &at) +{ + return new UBLOX_N2XX_CellularNetwork(at, *this); +} + AT_CellularContext *UBLOX_N2XX::create_context_impl(ATHandler &at, const char *apn, bool cp_req, bool nonip_req) { return new UBLOX_N2XX_CellularContext(at, this, apn, cp_req, nonip_req); @@ -94,8 +101,8 @@ nsapi_error_t UBLOX_N2XX::get_sim_state(SimState &state) _at->lock(); _at->flush(); //Special case: Command put in cmd_chr to make a 1 liner - _at->at_cmd_str("", "+CFUN=1", simstr, sizeof(simstr)); - error = _at->unlock_return_error(); + error = _at->at_cmd_str("", "+CFUN=1", simstr, sizeof(simstr)); + _at->unlock(); int len = strlen(simstr); if (len > 0 || error == NSAPI_ERROR_OK) { diff --git a/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX.h b/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX.h index 7bff286136..b20450951d 100644 --- a/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX.h +++ b/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX.h @@ -33,6 +33,7 @@ #include "AT_CellularNetwork.h" #include "UBLOX_N2XX_CellularSMS.h" #include "UBLOX_N2XX_CellularContext.h" +#include "UBLOX_N2XX_CellularNetwork.h" namespace mbed { @@ -50,6 +51,7 @@ public: protected: // AT_CellularDevice + virtual AT_CellularNetwork *open_network_impl(ATHandler &at); virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn, bool cp_req = false, bool nonip_req = false); #if MBED_CONF_CELLULAR_USE_SMS virtual AT_CellularSMS *open_sms_impl(ATHandler &at); diff --git a/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX_CellularContext.cpp b/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX_CellularContext.cpp index 9946d59b58..47abe29078 100644 --- a/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX_CellularContext.cpp +++ b/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX_CellularContext.cpp @@ -44,4 +44,9 @@ NetworkStack *UBLOX_N2XX_CellularContext::get_stack() } #endif +const char *UBLOX_N2XX_CellularContext::get_nonip_context_type_str() +{ + return "NONIP"; +} + } /* namespace mbed */ diff --git a/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX_CellularContext.h b/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX_CellularContext.h index d2bd9d3327..057d413a73 100644 --- a/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX_CellularContext.h +++ b/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX_CellularContext.h @@ -34,6 +34,7 @@ protected: virtual NetworkStack *get_stack(); #endif + virtual const char *get_nonip_context_type_str(); }; } /* namespace mbed */ diff --git a/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX_CellularNetwork.cpp b/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX_CellularNetwork.cpp new file mode 100644 index 0000000000..90dbbbd0c6 --- /dev/null +++ b/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX_CellularNetwork.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2019, 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 "UBLOX_N2XX_CellularNetwork.h" + +using namespace mbed; + +UBLOX_N2XX_CellularNetwork::UBLOX_N2XX_CellularNetwork(ATHandler &atHandler, AT_CellularDevice &device) : AT_CellularNetwork(atHandler, device) +{ +} + +nsapi_error_t UBLOX_N2XX_CellularNetwork::clear() +{ + nsapi_error_t err = AT_CellularNetwork::clear(); +#if MBED_CONF_CELLULAR_CONTROL_PLANE_OPT + if (!err) { +#ifdef MBED_CONF_NSAPI_DEFAULT_CELLULAR_APN + (void) _at.at_cmd_discard("+CGDCONT", "=", "%d%s%s", 1, "NONIP", MBED_CONF_NSAPI_DEFAULT_CELLULAR_APN); +#endif + (void) _at.at_cmd_discard("+CIPCA", "=", "%d%d", 3, 1); // EPS Attach without PDN connection + _at.lock(); + _at.cmd_start("AT+NCONFIG=\"AUTOCONNECT\",\"FALSE\""); // disable auto connect to IP context + _at.cmd_stop_read_resp(); + _at.unlock(); + } +#endif + return err; +} + +nsapi_error_t UBLOX_N2XX_CellularNetwork::set_ciot_optimization_config(CIoT_Supported_Opt supported_opt, + CIoT_Preferred_UE_Opt preferred_opt, + Callback network_support_cb) +{ + _ciotopt_network_support_cb = network_support_cb; + nsapi_error_t err = _at.at_cmd_discard("+CRTDCP", "=", "%d", 1); + return err; +} diff --git a/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX_CellularNetwork.h b/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX_CellularNetwork.h new file mode 100644 index 0000000000..112db976d5 --- /dev/null +++ b/features/cellular/framework/targets/UBLOX/N2XX/UBLOX_N2XX_CellularNetwork.h @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2019, 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. + */ + +#ifndef UBLOX_N2XX_CELLULAR_NETWORK_H_ +#define UBLOX_N2XX_CELLULAR_NETWORK_H_ + +#include "AT_CellularNetwork.h" + +namespace mbed { + +class UBLOX_N2XX_CellularNetwork : public AT_CellularNetwork { +public: + UBLOX_N2XX_CellularNetwork(ATHandler &atHandler, AT_CellularDevice &device); + virtual nsapi_error_t clear(); + virtual nsapi_error_t set_ciot_optimization_config(CIoT_Supported_Opt supported_opt, + CIoT_Preferred_UE_Opt preferred_opt, + Callback network_support_cb); +}; + +} // namespace mbed + +#endif // UBLOX_N2XX_CELLULAR_NETWORK_H_ diff --git a/features/cellular/framework/targets/UBLOX/PPP/UBLOX_PPP.cpp b/features/cellular/framework/targets/UBLOX/PPP/UBLOX_PPP.cpp index 13126eac20..0e81a08142 100644 --- a/features/cellular/framework/targets/UBLOX/PPP/UBLOX_PPP.cpp +++ b/features/cellular/framework/targets/UBLOX/PPP/UBLOX_PPP.cpp @@ -61,6 +61,7 @@ static const intptr_t cellular_properties[AT_CellularDevice::PROPERTY_MAX] = { 0, // PROPERTY_IPV4V6_STACK 0, // PROPERTY_NON_IP_PDP_TYPE 1, // PROPERTY_AT_CGEREP + 1, // PROPERTY_AT_COPS_FALLBACK_AUTO }; #else static const intptr_t cellular_properties[AT_CellularDevice::PROPERTY_MAX] = { @@ -79,6 +80,7 @@ static const intptr_t cellular_properties[AT_CellularDevice::PROPERTY_MAX] = { 0, // PROPERTY_IPV4V6_STACK 0, // PROPERTY_NON_IP_PDP_TYPE 0, // PROPERTY_AT_CGEREP + 0, // PROPERTY_AT_COPS_FALLBACK_AUTO }; #endif diff --git a/features/netsocket/CellularNonIPSocket.cpp b/features/netsocket/CellularNonIPSocket.cpp index 30bda5390b..a820ae5624 100644 --- a/features/netsocket/CellularNonIPSocket.cpp +++ b/features/netsocket/CellularNonIPSocket.cpp @@ -21,10 +21,11 @@ using namespace mbed; +ControlPlane_netif *CellularNonIPSocket::_cp_netif; + CellularNonIPSocket::CellularNonIPSocket() : _timeout(osWaitForever), _readers(0), _writers(0), _pending(0), - _cp_netif(NULL), _opened(false) {} @@ -46,10 +47,15 @@ nsapi_error_t CellularNonIPSocket::open(ControlPlane_netif *cp_netif) { _lock.lock(); - if (_cp_netif != NULL || cp_netif == NULL) { + if (cp_netif == NULL || _opened) { _lock.unlock(); return NSAPI_ERROR_PARAMETER; } + + if (_cp_netif) { + _lock.unlock(); + return NSAPI_ERROR_NO_SOCKET; + } _cp_netif = cp_netif; _event = callback(this, &CellularNonIPSocket::event); @@ -92,6 +98,9 @@ nsapi_error_t CellularNonIPSocket::close() nsapi_size_or_error_t CellularNonIPSocket::send(const void *data, nsapi_size_t size) { + if (!data) { + return NSAPI_ERROR_PARAMETER; + } _lock.lock(); nsapi_size_or_error_t ret; @@ -136,13 +145,12 @@ nsapi_size_or_error_t CellularNonIPSocket::send(const void *data, nsapi_size_t s nsapi_size_or_error_t CellularNonIPSocket::recv(void *buffer, nsapi_size_t size) { _lock.lock(); - nsapi_size_or_error_t ret; + nsapi_size_or_error_t ret = NSAPI_ERROR_NO_SOCKET; _readers++; while (true) { if (!_opened) { - ret = NSAPI_ERROR_NO_SOCKET; break; } @@ -164,7 +172,8 @@ nsapi_size_or_error_t CellularNonIPSocket::recv(void *buffer, nsapi_size_t size) if (flag & osFlagsError) { // Timeout break - ret = NSAPI_ERROR_WOULD_BLOCK; + // Poll once more for a possibly missed data received indication + ret = _cp_netif->recv(buffer, size); break; } } diff --git a/features/netsocket/CellularNonIPSocket.h b/features/netsocket/CellularNonIPSocket.h index d9a356ee84..de602105de 100644 --- a/features/netsocket/CellularNonIPSocket.h +++ b/features/netsocket/CellularNonIPSocket.h @@ -150,7 +150,7 @@ protected: static const int WRITE_FLAG = 0x2u; static const int FINISHED_FLAG = 0x3u; - ControlPlane_netif *_cp_netif; + static ControlPlane_netif *_cp_netif; // there can be only one Non-IP socket bool _opened; }; diff --git a/tools/test_configs/NIDDInterface.json b/tools/test_configs/NIDDInterface.json new file mode 100644 index 0000000000..21beb203e9 --- /dev/null +++ b/tools/test_configs/NIDDInterface.json @@ -0,0 +1,59 @@ +{ + "config": { + "echo-server-addr" : { + "help" : "IP address of echo server", + "value" : "\"echo.mbedcloudtesting.com\"" + }, + "echo-server-port" : { + "help" : "Port of echo server", + "value" : "7" + }, + "echo-server-discard-port" : { + "help" : "Discard port of echo server", + "value" : "9" + }, + "echo-server-port-tls" : { + "help" : "Port of echo server for TLS", + "value" : "2007" + }, + "echo-server-discard-port-tls" : { + "help" : "Discard port of echo server for TLS", + "value" : "2009" + }, + "trace-level": { + "help": "Note that excessive trace prints may mess up with Greentea parsing", + "macro_name": "MBED_TRACE_MAX_LEVEL", + "value": "TRACE_LEVEL_ERROR" + } + }, + "target_overrides": { + "*": { + "QUECTEL_BG96.provide-default": false, + "QUECTEL_BC95.provide-default": false, + "UBLOX_N2XX.provide-default": false, + + "cellular.clear-on-connect": true, + "cellular.radio-access-technology": 9, + + "nsapi.default-cellular-plmn": null, + "nsapi.default-cellular-sim-pin": null, + "nsapi.default-cellular-apn": "\"nonip\"", + "nsapi.default-cellular-username": null, + "nsapi.default-cellular-password": null, + + "target.network-default-interface-type": "CELLULAR", + "cellular.control-plane-opt": true, + "cellular.use-apn-lookup": false, + "platform.stdio-buffered-serial": true, + "platform.stdio-baud-rate": 115200, + "platform.default-serial-baud-rate": 115200, + "mbed-trace.enable": true, + "cellular.debug-at": true + }, + "MTB_STM_L475": { + "UBLOX_N2XX.tx": "TX1", + "UBLOX_N2XX.rx": "RX1" + } + } +} +