diff --git a/.travis.yml b/.travis.yml index 7d2ba7009e..9de3678080 100644 --- a/.travis.yml +++ b/.travis.yml @@ -111,7 +111,7 @@ matrix: - python tools/make.py -t GCC_ARM -m K64F --source=. --build=BUILD/K64F/GCC_ARM -j0 # Check that example compiles without rtos - sed -n '/``` cpp/,/```/{/```$/Q;/```/d;p;}' $EVENTS/README.md > main.cpp - - rm -r rtos features/netsocket features/frameworks BUILD + - rm -r rtos features/cellular features/netsocket features/frameworks BUILD - python tools/make.py -t GCC_ARM -m DISCO_F401VC --source=. --build=BUILD/DISCO_F401VC/GCC_ARM -j0 # Run local equeue tests - make -C $EVENTS/equeue test diff --git a/features/cellular/.gitignore b/features/cellular/.gitignore new file mode 100644 index 0000000000..70c84433ae --- /dev/null +++ b/features/cellular/.gitignore @@ -0,0 +1,12 @@ +lcov/ +results/ +coverages/ +gcov/ +*.exe +*.o +*.d +*.a +*.gcda +*.gcno +cpputest_*.xml +*_unit_tests* diff --git a/features/cellular/.mbedignore b/features/cellular/.mbedignore new file mode 100644 index 0000000000..e28badb677 --- /dev/null +++ b/features/cellular/.mbedignore @@ -0,0 +1 @@ +UNITTESTS/* diff --git a/features/cellular/Makefile.test b/features/cellular/Makefile.test new file mode 100644 index 0000000000..18f0a75bdd --- /dev/null +++ b/features/cellular/Makefile.test @@ -0,0 +1,56 @@ +# +# Makefile.test for CIot library unit tests +# + + +# List of subdirectories to build +TEST_FOLDER_NAME := UNITTESTS +TEST_FOLDER := ./UNITTESTS/ +# List of unit test directories for libraries +UNITTESTS := $(sort $(dir $(wildcard $(TEST_FOLDER)*))) +TESTDIRS := $(UNITTESTS:%=build-%) +CLEANTESTDIRS := $(UNITTESTS:%=clean-%) +COVERAGEFILE := ./lcov/coverage.info + +.PHONY: test +test: $(TESTDIRS) + @rm -rf ./lcov + @rm -rf ./coverage + @mkdir -p lcov + @mkdir -p lcov/results + @mkdir coverage + @find $(TEST_FOLDER) -name '*.xml' | xargs cp -t ./lcov/results/ + @rm -f lcov/index.xml + @./xsl_script.sh + @cp junit_xsl.xslt lcov/. + @xsltproc -o lcov/testresults.html lcov/junit_xsl.xslt lcov/index.xml + @rm -f lcov/junit_xsl.xslt + @rm -f lcov/index.xml + @find ./ -name '*.gcno' | xargs cp --backup=numbered -t ./coverage/ + @find ./ -name '*.gcda' | xargs cp --backup=numbered -t ./coverage/ + @gcovr --object-directory ./coverage --exclude-unreachable-branches -e '.*/builds/.*' -e '.*/$(TEST_FOLDER_NAME)/.*' -e '.*/yotta_modules/.*' -e '.*/stubs/.*' -e '.*/mbed-coap/.*' -x -o ./lcov/gcovr.xml + @lcov -d $(TEST_FOLDER_NAME)/. -c -o $(COVERAGEFILE) + @lcov -q -r $(COVERAGEFILE) "/usr*" -o $(COVERAGEFILE) + @lcov -q -r $(COVERAGEFILE) "/$(TEST_FOLDER_NAME)*" -o $(COVERAGEFILE) + @lcov -q -r $(COVERAGEFILE) "/mbed-client-libservice*" -o $(COVERAGEFILE) + @lcov -q -r $(COVERAGEFILE) "/mbed-client*" -o $(COVERAGEFILE) + @lcov -q -r $(COVERAGEFILE) "/mbed-os/events*" -o $(COVERAGEFILE) + @lcov -q -r $(COVERAGEFILE) "/mbed-os/features/netsocket*" -o $(COVERAGEFILE) + @lcov -q -r $(COVERAGEFILE) "/mbed-os/platform*" -o $(COVERAGEFILE) + @genhtml -q $(COVERAGEFILE) --output-directory lcov/html + @echo mbed-ciot module unit tests built + +$(TESTDIRS): + @make -C $(@:build-%=%) + +$(CLEANDIRS): + @make -C $(@:clean-%=%) clean + +$(CLEANTESTDIRS): + @make -C $(@:clean-%=%) clean + +# Extend default clean rule +clean: clean-extra + +clean-extra: $(CLEANDIRS) \ + $(CLEANTESTDIRS) diff --git a/features/cellular/README.md b/features/cellular/README.md new file mode 100644 index 0000000000..5c02c0e390 --- /dev/null +++ b/features/cellular/README.md @@ -0,0 +1,73 @@ +# Mbed cellular connectivity + +This is the Github repo for Mbed cellular connectivity: + + easy_cellular/ + EasyCellularConnection Simplified cellular usage based on `CellularBase.h` + CellularConnectionUtil A utility class for cellular connection + + framework/ + API Application Programming Interface for cellular connectivity + AT AT implementation based on 3GPP TS 27.007 specification + common Common and utility sources + targets Vendor specific cellular module adaptations + +## Known limitations + +**Please note that this is a first release of Cellular framework and is subject to further development in future.** + +Only UDP is supported when using AT commands to control sockets in an IP stack built into the cellular modem. If TCP is required, use the PPP/LWIP stack. + +## Supported modules + +You can find currently supported cellular modules in the `framework/targets/` folder, where we also add support for new cellular modules. + +## Cellular configuration + +You can change cellular defaults in the `mbed_app.json` configuration file: + + "config": { + "cellular_plmn": { + "help": "PLMN selection, 0=auto", + "value": 0 + }, + "apn": { + "help": "Access point name, e.g. internet", + "value": "\"internet\"" + }, + "cellular_sim_pin": { + "help": "PIN code", + "value": "\"1234\"" + } + } + +## Debug traces + +You can define the debug tracing level in the `mbed_app.json` configuration file: + + "target_overrides": { + "*": { + "target.features_add": ["COMMON_PAL"], + "mbed-trace.enable": true, + "platform.stdio-convert-newlines": true, + "platform.stdio-baud-rate": 115200, + "platform.default-serial-baud-rate": 115200 + } + }, + "config": { + "trace-level": { + "help": "Options are TRACE_LEVEL_ERROR,TRACE_LEVEL_WARN,TRACE_LEVEL_INFO,TRACE_LEVEL_DEBUG", + "macro_name": "MBED_TRACE_MAX_LEVEL", + "value": "TRACE_LEVEL_INFO" + } + } + +## Unit tests + +The `UNITTESTS` folder contains unit tests for cellular specific classes. Unit tests are based on the stubbing method. + +You can run those tests locally by running `./run_tests` script under the `UNITTESTS/` folder. + +You need the following applications: `cpputest`, `gcov` and `lcov` (genhtml) for running the tests. + +After you have run the `run_tests` script, you can find test results under `UNITTESTS/results` folder and line and function coverages under the `UNITTESTS/coverages` folder. diff --git a/features/cellular/TESTS/cellular/cellular_all/CellularTests.h b/features/cellular/TESTS/cellular/cellular_all/CellularTests.h new file mode 100644 index 0000000000..37f30b5c90 --- /dev/null +++ b/features/cellular/TESTS/cellular/cellular_all/CellularTests.h @@ -0,0 +1,82 @@ +/* + * Copyright (c) 2017, 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 CELLULAR_TESTS_H +#define CELLULAR_TESTS_H + +#include "CellularUtil.h" // for CELLULAR_ helper macros +#include "CellularTargets.h" + +#ifdef CELLULAR_DEVICE + +#include "mbed_events.h" + +#include "greentea-client/test_env.h" +#include "unity.h" +#include "utest.h" + +#include "CellularLog.h" + +#include CELLULAR_STRINGIFY(CELLULAR_DEVICE.h) +extern EventQueue queue; +extern CELLULAR_DEVICE cellularDevice; + +extern UARTSerial serial; +extern CellularNetwork *network; + +extern CellularSMS *sms; +extern CellularPower *pwr; +extern CellularSIM *sim; + + +/** + * TEST CASES DEFINED HERE AND in main.cpp + */ + +// power +void test_create_power(void); + +// SIM +void test_get_sim_state(void); +void test_set_pin(void); +void test_change_pin(void); + +// sms +void test_sms_init(void); + +// network +void test_attach(void); +void test_connect(void); +void test_get_ip_address(void); +void test_disconnect(void); + +// stack +void test_socket_open(void); +void test_socket_bind(void); +/* +void test_socket_set_blocking(); +void test_socket_send_receive_blocking(); +*/ +void test_socket_set_non_blocking(); +void test_socket_send_receive_non_blocking(); +void test_socket_close(void); + +// Test closing all interface via device +void test_close_interfaces(void); + +#endif // CELLULAR_DEVICE + +#endif // CELLULAR_TESTS_H diff --git a/features/cellular/TESTS/cellular/cellular_all/main.cpp b/features/cellular/TESTS/cellular/cellular_all/main.cpp new file mode 100644 index 0000000000..1309b8e81f --- /dev/null +++ b/features/cellular/TESTS/cellular/cellular_all/main.cpp @@ -0,0 +1,107 @@ +/* + * Copyright (c) 2017, 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 "CellularTests.h" + +#if !defined(MBED_CONF_NSAPI_PRESENT) +#error [NOT_SUPPORTED] A json configuration file is needed. Skipping this build. +#endif + +#ifndef CELLULAR_DEVICE +#error [NOT_SUPPORTED] CELLULAR_DEVICE must be defined for this test +#endif + +EventQueue queue(32 * EVENTS_EVENT_SIZE); +Thread t; +CELLULAR_DEVICE cellularDevice(queue); + +UARTSerial serial(MDMTXD, MDMRXD, MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE); +CellularNetwork *network = NULL; +CellularPower *pwr = NULL; +CellularSIM *sim = NULL; +CellularSMS *sms = NULL; + +using namespace utest::v1; + +// using namespace mbed; +utest::v1::status_t greentea_failure_handler(const Case *const source, const failure_t reason) +{ + greentea_case_failure_abort_handler(source, reason); + return STATUS_CONTINUE; +} + +Case cases[] = { + // power test + Case("Create power", test_create_power, greentea_failure_handler), +#ifdef MBED_CONF_APP_CELLULAR_SIM_PIN + // sim test + Case("test get SIM state", test_get_sim_state, greentea_failure_handler), + Case("SIM set pin", test_set_pin, greentea_failure_handler), + Case("SIM change pin", test_change_pin, greentea_failure_handler), +#endif + // network tests + Case("attach", test_attach, greentea_failure_handler), + // SMS tests + Case("SMS init", test_sms_init, greentea_failure_handler), + // network tests + Case("connect", test_connect, greentea_failure_handler), + Case("get_ip_address", test_get_ip_address, greentea_failure_handler), + // stack tests + Case("open", test_socket_open, greentea_failure_handler), + Case("bind", test_socket_bind, greentea_failure_handler), +// Case("set socket blocking", test_socket_set_blocking, greentea_failure_handler), +// Case("socket send receive in blocking mode", test_socket_send_receive_blocking, greentea_failure_handler), + Case("set socket non blocking", test_socket_set_non_blocking, greentea_failure_handler), + Case("socket send receive in non blocking mode", test_socket_send_receive_non_blocking, greentea_failure_handler), + Case("close", test_socket_close, greentea_failure_handler), + // network tests + Case("disconnect", test_disconnect, greentea_failure_handler), + + // test closing of all interface, must be the last test case + Case("Close all Interfaces", test_close_interfaces, greentea_failure_handler) +}; + +utest::v1::status_t test_setup(const size_t number_of_cases) +{ + GREENTEA_SETUP(300, "default_auto"); + + return verbose_test_setup_handler(number_of_cases); +} + +Specification specification(test_setup, cases); + +void test_close_interfaces() +{ + // SMS is already closed in it's test + cellularDevice.close_network(); + cellularDevice.close_sim(); + cellularDevice.close_power(); +} + +int main() +{ +#if defined (MDMRTS) && defined (MDMCTS) + serial.set_flow_control(SerialBase::RTSCTS, MDMRTS, MDMCTS); +#endif + pwr = cellularDevice.open_power(&serial); + sim = cellularDevice.open_sim(&serial); + sms = cellularDevice.open_sms(&serial); + network = cellularDevice.open_network(&serial); + + t.start(callback(&queue, &EventQueue::dispatch_forever)); + return Harness::run(specification); +} diff --git a/features/cellular/TESTS/cellular/cellular_all/network.cpp b/features/cellular/TESTS/cellular/cellular_all/network.cpp new file mode 100644 index 0000000000..2229dba1bd --- /dev/null +++ b/features/cellular/TESTS/cellular/cellular_all/network.cpp @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2017, 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 "CellularTests.h" +#ifdef CELLULAR_DEVICE + +using namespace mbed; + +static bool wait_register() +{ + tr_info("Try registering to network..."); + if (network->set_registration() != NSAPI_ERROR_OK) { + tr_error("Network registration request failed."); + return false; + } + + CellularNetwork::RegistrationStatus status; + for (int i=0; i<180; i++) { + tr_info("Register to network %d...", i); + for (int type = 0; type < CellularNetwork::C_MAX; type++) { + if (network->get_registration_status((CellularNetwork::RegistrationType)type, status) == NSAPI_ERROR_OK) { + tr_info("status %d...", status); + switch (status) { + case CellularNetwork::RegisteredRoaming: + // fall-through + case CellularNetwork::RegisteredHomeNetwork: + tr_info("Registered to network."); + return true; + case CellularNetwork::RegisteredSMSOnlyRoaming: + // fall-through + case CellularNetwork::RegisteredSMSOnlyHome: + tr_warn("SMS only network registration!"); + return true; + case CellularNetwork::RegisteredCSFBNotPreferredRoaming: + // fall-through + case CellularNetwork::RegisteredCSFBNotPreferredHome: + tr_warn("Not preferred network registration!"); + return true; + case CellularNetwork::AttachedEmergencyOnly: + tr_warn("Emergency only network registration!"); + return true; + case CellularNetwork::RegistrationDenied: + tr_warn("Network registration denied!"); + wait(i); + break; + case CellularNetwork::NotRegistered: + case CellularNetwork::Unknown: + case CellularNetwork::SearchingNetwork: + default: + break; + } + } + } + wait(1); + } + return false; +} + +void test_attach() +{ + tr_info("Register to network."); + TEST_ASSERT(wait_register()); + tr_info("Attach to network."); + nsapi_error_t err = network->set_attach(); + TEST_ASSERT(!err); + CellularNetwork::AttachStatus status; + err = network->get_attach(status); + TEST_ASSERT(!err); +} + +void test_connect() +{ + nsapi_error_t err = network->connect(); + TEST_ASSERT(!err); +} + +void test_get_ip_address() +{ + const char *ip = network->get_ip_address(); + TEST_ASSERT(ip && ip[0]); + tr_info("IP: %s\r\n", ip); +} + +void test_disconnect() +{ + nsapi_error_t err = network->disconnect(); + TEST_ASSERT(!err); +} + +#endif // CELLULAR_DEVICE diff --git a/features/cellular/TESTS/cellular/cellular_all/power.cpp b/features/cellular/TESTS/cellular/cellular_all/power.cpp new file mode 100644 index 0000000000..b6d4a434b6 --- /dev/null +++ b/features/cellular/TESTS/cellular/cellular_all/power.cpp @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017, 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 "CellularTests.h" + +#ifdef CELLULAR_DEVICE + +using namespace mbed; + +static bool start_cellular_at(CellularPower *pwr) +{ + nsapi_error_t err = pwr->off(); + if (err != NSAPI_ERROR_OK && err != NSAPI_ERROR_UNSUPPORTED) { + return false; + } + err = pwr->on(); + if (err != NSAPI_ERROR_OK && err != NSAPI_ERROR_UNSUPPORTED) { + return false; + } + tr_info("Wait for cellular device 180 seconds..."); + for (int i = 0; i < 180; i++) { + if (pwr->set_at_mode() == NSAPI_ERROR_OK) { + return true; + } + wait(1); + } + return false; +} + +void test_create_power() +{ + TEST_ASSERT(start_cellular_at(pwr)); + + tr_info("Cellular device is ready!"); +} + +// TODO: tests still missing for off, sleep, opt_power_save_mode, opt_receive_period + +#endif // CELLULAR_DEVICE diff --git a/features/cellular/TESTS/cellular/cellular_all/sim.cpp b/features/cellular/TESTS/cellular/cellular_all/sim.cpp new file mode 100644 index 0000000000..d95069baaf --- /dev/null +++ b/features/cellular/TESTS/cellular/cellular_all/sim.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2017, 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 "CellularTests.h" + +#ifdef CELLULAR_DEVICE + +#ifdef MBED_CONF_APP_CELLULAR_SIM_PIN + +using namespace mbed; + +void test_get_sim_state() +{ + wait(1); + CellularSIM::SimState state = CellularSIM::SimStateUnknown; + tr_info("Wait SIM for 180 seconds..."); + for (int i = 0; i < 180; i++) { + CellularSIM::SimState tmp_state; + if ((sim->get_sim_state(tmp_state) == NSAPI_ERROR_OK) && tmp_state != CellularSIM::SimStateUnknown) { + state = tmp_state; + break; + } + } + TEST_ASSERT_MESSAGE(state == CellularSIM::SimStateReady || state == CellularSIM::SimStatePinNeeded || + state == CellularSIM::SimStatePukNeeded, "Invalid SIM state"); +} + +// creates PIN which is different than one defined in MBED_CONF_APP_CELLULAR_SIM_PIN +static void create_random_pin(char* random_pin) +{ + + char s[11]; + do { + sprintf(s,"%d", rand()); + + } while (strncmp(s, MBED_CONF_APP_CELLULAR_SIM_PIN, 4) == 0); + + strncpy(random_pin, s, 4); + random_pin[4] = '\0'; +} + +void test_set_pin() +{ + // run test only if sim is not in ready state as then sim interface will return NSAPI_ERROR_OK + nsapi_error_t err; + CellularSIM::SimState state = CellularSIM::SimStateUnknown; + if ((sim->get_sim_state(state) == NSAPI_ERROR_OK) && (state != CellularSIM::SimStateReady)) { + char random_pin[5]; + create_random_pin(random_pin); + err = sim->set_pin(random_pin); + TEST_ASSERT_MESSAGE(err != 0, "Setting random pin should fail"); + } + + err = sim->set_pin(MBED_CONF_APP_CELLULAR_SIM_PIN); + char err_msg[60]; + sprintf(err_msg, "Setting correct pin: %s failed with: %d", MBED_CONF_APP_CELLULAR_SIM_PIN, err); + TEST_ASSERT_MESSAGE(err == 0, err_msg); +} + +void test_change_pin() +{ + char random_pin[5]; + create_random_pin(random_pin); + nsapi_error_t err = sim->change_pin(MBED_CONF_APP_CELLULAR_SIM_PIN, random_pin); + + char err_msg[60]; + sprintf(err_msg, "Change from original pin failed with: %d", err); + TEST_ASSERT_MESSAGE(err == NSAPI_ERROR_OK, err_msg); + + err = sim->change_pin(random_pin, MBED_CONF_APP_CELLULAR_SIM_PIN); + sprintf(err_msg, "Change back original pin failed with: %d", err); + TEST_ASSERT_MESSAGE(err == NSAPI_ERROR_OK, err_msg); +} + +#endif + +#endif // CELLULAR_DEVICE diff --git a/features/cellular/TESTS/cellular/cellular_all/sms.cpp b/features/cellular/TESTS/cellular/cellular_all/sms.cpp new file mode 100644 index 0000000000..d4741e3c98 --- /dev/null +++ b/features/cellular/TESTS/cellular/cellular_all/sms.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017, 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 "CellularTests.h" + +#ifdef CELLULAR_DEVICE + +using namespace mbed; + +void test_sms_init() +{ + // for some weird reason if we don't wait for few seconds we get SIM Busy error in initialize even is SIM is ready... + wait(3); + + // check SIM state as we have tested sim and it might not be ready + for (int i = 0; i < MAX_SIM_READY_WAITING_TIME; i++) { + CellularSIM::SimState state; + if (sim->get_sim_state(state) == NSAPI_ERROR_OK && state == CellularSIM::SimStateReady) { + break; + } + wait(1); + } + + nsapi_error_t err = sms->initialize(CellularSMS::CellularSMSMmodeText); + char err_msg[60]; + sprintf(err_msg, "SMS initialize failed with: %d", err); + + cellularDevice.close_sms(); + sms = NULL; + TEST_ASSERT_MESSAGE(!err, err_msg); +} + +#endif // CELLULAR_DEVICE diff --git a/features/cellular/TESTS/cellular/cellular_all/stack.cpp b/features/cellular/TESTS/cellular/cellular_all/stack.cpp new file mode 100644 index 0000000000..d4f58c2ede --- /dev/null +++ b/features/cellular/TESTS/cellular/cellular_all/stack.cpp @@ -0,0 +1,120 @@ +/* + * Copyright (c) 2017, 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 "CellularTests.h" + +#ifdef CELLULAR_DEVICE + +using namespace mbed; + +static UDPSocket socket; +#define SERVER_IP_ADDR "52.215.34.155" +#define SERVER_UDP_PORT 7 +static rtos::Semaphore sock_event; + +void test_socket_open() +{ + nsapi_error_t err = socket.open(network); + TEST_ASSERT(err == NSAPI_ERROR_OK); +} + +void test_socket_bind() +{ + nsapi_error_t err = socket.bind(3030); + TEST_ASSERT(!err); +} + +/* +void test_socket_set_blocking() +{ + //socket.set_blocking(true); + socket.set_timeout(5000); +} + +void test_socket_send_receive_blocking() +{ + char receive_buffer[CELLULAR_MTU] = {0}; + char send_buffer[] = { 'H', 'e', 'l', 'l', 'u', 'l', 'a', 'r', '!' }; + int send_count = 0; + int send_tries = 1; + int max_send_tries = 3; + + // Send to echo server + while (send_tries <= max_send_tries) { + tr_info("ONE!!!"); + send_count = socket.sendto(SERVER_IP_ADDR, SERVER_UDP_PORT, send_buffer, sizeof(send_buffer)); + TEST_ASSERT_MESSAGE(send_count == sizeof(send_buffer), "Sent count doesnt match sent buffer!"); + send_tries++; + + // Read response + SocketAddress address; + int receive_count = 0; + // 2 tries. First recv attempt should be blocked and wait for a max 5 seconds for socket read flag + int recv_tries = 2; + while (recv_tries >= 0) { + tr_info("RECV!!!"); + receive_count = socket.recvfrom(&address, receive_buffer, sizeof(receive_buffer)); + if (receive_count > 0) { + break; + } + recv_tries--; + wait(1); + } + TEST_ASSERT_MESSAGE(receive_count == send_count, "Receive and Sent count dont match!"); + TEST_ASSERT_MESSAGE(strncmp(send_buffer, receive_buffer, send_count) == 0, "Sent data doesn't match received data while in ECHO"); + } +} +*/ + +static void socket_sigio_cb() +{ + sock_event.release(); +} + +void test_socket_set_non_blocking() +{ + socket.set_blocking(false); + socket.sigio(socket_sigio_cb); +} + +void test_socket_send_receive_non_blocking() +{ + char receive_buffer[1500] = {0}; + char send_buffer[] = { 'H', 'e', 'l', 'l', 'u', 'l', 'a', 'r', '!' }; + + // Send to echo server + int send_count = socket.sendto(SERVER_IP_ADDR, SERVER_UDP_PORT, send_buffer, sizeof(send_buffer)); + TEST_ASSERT(send_count == sizeof(send_buffer)); + + int32_t event; + event = sock_event.wait(10000); + TEST_ASSERT_MESSAGE( event>=1, "No Socket event within 10 seconds"); + + // Read response + SocketAddress address; + int receive_count = socket.recvfrom(&address, receive_buffer, sizeof(receive_buffer)); + TEST_ASSERT_MESSAGE(receive_count == send_count, "Receive and Sent count dont match!"); + TEST_ASSERT_MESSAGE(strncmp(send_buffer, receive_buffer, send_count) == 0, "Sent data doesn't match received data while in ECHO"); +} + + +void test_socket_close() +{ + nsapi_error_t err = socket.close(); + TEST_ASSERT(!err); +} + +#endif // CELLULAR_DEVICE diff --git a/features/cellular/TESTS/cellular/cellular_all/template_mbed_app.json.txt b/features/cellular/TESTS/cellular/cellular_all/template_mbed_app.json.txt new file mode 100644 index 0000000000..c52e649aab --- /dev/null +++ b/features/cellular/TESTS/cellular/cellular_all/template_mbed_app.json.txt @@ -0,0 +1,31 @@ +{ + "config": { + "sock-type": "UDP", + "network-interface":{ + "help": "Options are ETHERNET,CELLULAR", + "value": "CELLULAR" + }, + "cellular_sim_pin": { + "help": "PIN code", + "value": "\"1234\"" + }, + "trace-level": { + "help": "Options are TRACE_LEVEL_ERROR,TRACE_LEVEL_WARN,TRACE_LEVEL_INFO,TRACE_LEVEL_DEBUG", + "macro_name": "MBED_TRACE_MAX_LEVEL", + "value": "TRACE_LEVEL_INFO" + } + }, + "target_overrides": { + "*": { + "target.features_add": ["LWIP", "COMMON_PAL"], + "mbed-trace.enable": true, + "lwip.ipv4-enabled": true, + "lwip.ethernet-enabled": false, + "lwip.ppp-enabled": true, + "lwip.tcp-enabled": true, + "platform.stdio-convert-newlines": true, + "platform.stdio-baud-rate": 115200, + "platform.default-serial-baud-rate": 115200 + } + } +} diff --git a/features/cellular/UNITTESTS/Makefile b/features/cellular/UNITTESTS/Makefile new file mode 100755 index 0000000000..1327cf4601 --- /dev/null +++ b/features/cellular/UNITTESTS/Makefile @@ -0,0 +1,19 @@ +#scan for folders having "Makefile" in them and remove 'this' to prevent loop +DIRS := $(filter-out ./, $(sort $(dir $(shell find . -name 'Makefile')))) + +all: + for dir in $(DIRS); do \ + cd $$dir; make gcov; cd ..; cd ..;\ + done + +clean: + for dir in $(DIRS); do \ + cd $$dir; make clean; cd ..; cd ..;\ + done + rm -rf ../source/*gcov ../source/*gcda ../source/*o + rm -rf stubs/*gcov stubs/*gcda stubs/*o + rm -rf results/* + rm -rf coverages/* + rm -rf results + rm -rf coverages + diff --git a/features/cellular/UNITTESTS/MakefileWorker.mk b/features/cellular/UNITTESTS/MakefileWorker.mk new file mode 100755 index 0000000000..2096ced036 --- /dev/null +++ b/features/cellular/UNITTESTS/MakefileWorker.mk @@ -0,0 +1,562 @@ +#--------- +# +# MakefileWorker.mk +# +# Include this helper file in your makefile +# It makes +# A static library +# A test executable +# +# See this example for parameter settings +# examples/Makefile +# +#---------- +# Inputs - these variables describe what to build +# +# INCLUDE_DIRS - Directories used to search for include files. +# This generates a -I for each directory +# SRC_DIRS - Directories containing source file to built into the library +# SRC_FILES - Specific source files to build into library. Helpful when not all code +# in a directory can be built for test (hopefully a temporary situation) +# TEST_SRC_DIRS - Directories containing unit test code build into the unit test runner +# These do not go in a library. They are explicitly included in the test runner +# TEST_SRC_FILES - Specific source files to build into the unit test runner +# These do not go in a library. They are explicitly included in the test runner +# MOCKS_SRC_DIRS - Directories containing mock source files to build into the test runner +# These do not go in a library. They are explicitly included in the test runner +#---------- +# You can adjust these variables to influence how to build the test target +# and where to put and name outputs +# See below to determine defaults +# COMPONENT_NAME - the name of the thing being built +# TEST_TARGET - name the test executable. By default it is +# $(COMPONENT_NAME)_tests +# Helpful if you want 1 > make files in the same directory with different +# executables as output. +# CPPUTEST_HOME - where CppUTest home dir found +# TARGET_PLATFORM - Influences how the outputs are generated by modifying the +# CPPUTEST_OBJS_DIR and CPPUTEST_LIB_DIR to use a sub-directory under the +# normal objs and lib directories. Also modifies where to search for the +# CPPUTEST_LIB to link against. +# CPPUTEST_OBJS_DIR - a directory where o and d files go +# CPPUTEST_LIB_DIR - a directory where libs go +# CPPUTEST_ENABLE_DEBUG - build for debug +# CPPUTEST_USE_MEM_LEAK_DETECTION - Links with overridden new and delete +# CPPUTEST_USE_STD_CPP_LIB - Set to N to keep the standard C++ library out +# of the test harness +# CPPUTEST_USE_GCOV - Turn on coverage analysis +# Clean then build with this flag set to Y, then 'make gcov' +# CPPUTEST_MAPFILE - generate a map file +# CPPUTEST_WARNINGFLAGS - overly picky by default +# OTHER_MAKEFILE_TO_INCLUDE - a hook to use this makefile to make +# other targets. Like CSlim, which is part of fitnesse +# CPPUTEST_USE_VPATH - Use Make's VPATH functionality to support user +# specification of source files and directories that aren't below +# the user's Makefile in the directory tree, like: +# SRC_DIRS += ../../lib/foo +# It defaults to N, and shouldn't be necessary except in the above case. +#---------- +# +# Other flags users can initialize to sneak in their settings +# CPPUTEST_CXXFLAGS - flags for the C++ compiler +# CPPUTEST_CPPFLAGS - flags for the C++ AND C preprocessor +# CPPUTEST_CFLAGS - flags for the C complier +# CPPUTEST_LDFLAGS - Linker flags +#---------- + +# Some behavior is weird on some platforms. Need to discover the platform. + +# Platforms +UNAME_OUTPUT = "$(shell uname -a)" +MACOSX_STR = Darwin +MINGW_STR = MINGW +CYGWIN_STR = CYGWIN +LINUX_STR = Linux +SUNOS_STR = SunOS +UNKNWOWN_OS_STR = Unknown + +# Compilers +CC_VERSION_OUTPUT ="$(shell $(CXX) -v 2>&1)" +CLANG_STR = clang +SUNSTUDIO_CXX_STR = SunStudio + +UNAME_OS = $(UNKNWOWN_OS_STR) + +ifeq ($(findstring $(MINGW_STR),$(UNAME_OUTPUT)),$(MINGW_STR)) + UNAME_OS = $(MINGW_STR) +endif + +ifeq ($(findstring $(CYGWIN_STR),$(UNAME_OUTPUT)),$(CYGWIN_STR)) + UNAME_OS = $(CYGWIN_STR) +endif + +ifeq ($(findstring $(LINUX_STR),$(UNAME_OUTPUT)),$(LINUX_STR)) + UNAME_OS = $(LINUX_STR) +endif + +ifeq ($(findstring $(MACOSX_STR),$(UNAME_OUTPUT)),$(MACOSX_STR)) + UNAME_OS = $(MACOSX_STR) +#lion has a problem with the 'v' part of -a + UNAME_OUTPUT = "$(shell uname -pmnrs)" +endif + +ifeq ($(findstring $(SUNOS_STR),$(UNAME_OUTPUT)),$(SUNOS_STR)) + UNAME_OS = $(SUNOS_STR) + + SUNSTUDIO_CXX_ERR_STR = CC -flags +ifeq ($(findstring $(SUNSTUDIO_CXX_ERR_STR),$(CC_VERSION_OUTPUT)),$(SUNSTUDIO_CXX_ERR_STR)) + CC_VERSION_OUTPUT ="$(shell $(CXX) -V 2>&1)" + COMPILER_NAME = $(SUNSTUDIO_CXX_STR) +endif +endif + +ifeq ($(findstring $(CLANG_STR),$(CC_VERSION_OUTPUT)),$(CLANG_STR)) + COMPILER_NAME = $(CLANG_STR) +endif + +#Kludge for mingw, it does not have cc.exe, but gcc.exe will do +ifeq ($(UNAME_OS),$(MINGW_STR)) + CC := gcc +endif + +#And another kludge. Exception handling in gcc 4.6.2 is broken when linking the +# Standard C++ library as a shared library. Unbelievable. +ifeq ($(UNAME_OS),$(MINGW_STR)) + CPPUTEST_LDFLAGS += -static +endif +ifeq ($(UNAME_OS),$(CYGWIN_STR)) + CPPUTEST_LDFLAGS += -static +endif + + +#Kludge for MacOsX gcc compiler on Darwin9 who can't handle pendantic +ifeq ($(UNAME_OS),$(MACOSX_STR)) +ifeq ($(findstring Version 9,$(UNAME_OUTPUT)),Version 9) + CPPUTEST_PEDANTIC_ERRORS = N +endif +endif + +ifndef COMPONENT_NAME + COMPONENT_NAME = name_this_in_the_makefile +endif + +# Debug on by default +ifndef CPPUTEST_ENABLE_DEBUG + CPPUTEST_ENABLE_DEBUG = Y +endif + +# new and delete for memory leak detection on by default +ifndef CPPUTEST_USE_MEM_LEAK_DETECTION + CPPUTEST_USE_MEM_LEAK_DETECTION = Y +endif + +# Use the standard C library +ifndef CPPUTEST_USE_STD_C_LIB + CPPUTEST_USE_STD_C_LIB = Y +endif + +# Use the standard C++ library +ifndef CPPUTEST_USE_STD_CPP_LIB + CPPUTEST_USE_STD_CPP_LIB = Y +endif + +# Use gcov, off by default +ifndef CPPUTEST_USE_GCOV + CPPUTEST_USE_GCOV = N +endif + +ifndef CPPUTEST_PEDANTIC_ERRORS + CPPUTEST_PEDANTIC_ERRORS = Y +endif + +# Default warnings +ifndef CPPUTEST_WARNINGFLAGS + CPPUTEST_WARNINGFLAGS = -Wall -Wextra -Wshadow -Wswitch-default -Wswitch-enum -Wconversion +ifeq ($(CPPUTEST_PEDANTIC_ERRORS), Y) +# CPPUTEST_WARNINGFLAGS += -pedantic-errors + CPPUTEST_WARNINGFLAGS += -pedantic +endif +ifeq ($(UNAME_OS),$(LINUX_STR)) + CPPUTEST_WARNINGFLAGS += -Wsign-conversion +endif + CPPUTEST_CXX_WARNINGFLAGS = -Woverloaded-virtual + CPPUTEST_C_WARNINGFLAGS = -Wstrict-prototypes +endif + +#Wonderful extra compiler warnings with clang +ifeq ($(COMPILER_NAME),$(CLANG_STR)) +# -Wno-disabled-macro-expansion -> Have to disable the macro expansion warning as the operator new overload warns on that. +# -Wno-padded -> I sort-of like this warning but if there is a bool at the end of the class, it seems impossible to remove it! (except by making padding explicit) +# -Wno-global-constructors Wno-exit-time-destructors -> Great warnings, but in CppUTest it is impossible to avoid as the automatic test registration depends on the global ctor and dtor +# -Wno-weak-vtables -> The TEST_GROUP macro declares a class and will automatically inline its methods. Thats ok as they are only in one translation unit. Unfortunately, the warning can't detect that, so it must be disabled. + CPPUTEST_CXX_WARNINGFLAGS += -Weverything -Wno-disabled-macro-expansion -Wno-padded -Wno-global-constructors -Wno-exit-time-destructors -Wno-weak-vtables + CPPUTEST_C_WARNINGFLAGS += -Weverything -Wno-padded +endif + +# Uhm. Maybe put some warning flags for SunStudio here? +ifeq ($(COMPILER_NAME),$(SUNSTUDIO_CXX_STR)) + CPPUTEST_CXX_WARNINGFLAGS = + CPPUTEST_C_WARNINGFLAGS = +endif + +# Default dir for temporary files (d, o) +ifndef CPPUTEST_OBJS_DIR +ifndef TARGET_PLATFORM + CPPUTEST_OBJS_DIR = objs +else + CPPUTEST_OBJS_DIR = objs/$(TARGET_PLATFORM) +endif +endif + +# Default dir for the outout library +ifndef CPPUTEST_LIB_DIR +ifndef TARGET_PLATFORM + CPPUTEST_LIB_DIR = lib +else + CPPUTEST_LIB_DIR = lib/$(TARGET_PLATFORM) +endif +endif + +# No map by default +ifndef CPPUTEST_MAP_FILE + CPPUTEST_MAP_FILE = N +endif + +# No extentions is default +ifndef CPPUTEST_USE_EXTENSIONS + CPPUTEST_USE_EXTENSIONS = N +endif + +# No VPATH is default +ifndef CPPUTEST_USE_VPATH + CPPUTEST_USE_VPATH := N +endif +# Make empty, instead of 'N', for usage in $(if ) conditionals +ifneq ($(CPPUTEST_USE_VPATH), Y) + CPPUTEST_USE_VPATH := +endif + +ifndef TARGET_PLATFORM +#CPPUTEST_LIB_LINK_DIR = $(CPPUTEST_HOME)/lib +CPPUTEST_LIB_LINK_DIR = /usr/lib/x86_64-linux-gnu +else +CPPUTEST_LIB_LINK_DIR = $(CPPUTEST_HOME)/lib/$(TARGET_PLATFORM) +endif + +# -------------------------------------- +# derived flags in the following area +# -------------------------------------- + +# Without the C library, we'll need to disable the C++ library and ... +ifeq ($(CPPUTEST_USE_STD_C_LIB), N) + CPPUTEST_USE_STD_CPP_LIB = N + CPPUTEST_USE_MEM_LEAK_DETECTION = N + CPPUTEST_CPPFLAGS += -DCPPUTEST_STD_C_LIB_DISABLED + CPPUTEST_CPPFLAGS += -nostdinc +endif + +CPPUTEST_CPPFLAGS += -DCPPUTEST_COMPILATION + +ifeq ($(CPPUTEST_USE_MEM_LEAK_DETECTION), N) + CPPUTEST_CPPFLAGS += -DCPPUTEST_MEM_LEAK_DETECTION_DISABLED +else + ifndef CPPUTEST_MEMLEAK_DETECTOR_NEW_MACRO_FILE + CPPUTEST_MEMLEAK_DETECTOR_NEW_MACRO_FILE = -include $(CPPUTEST_HOME)/include/CppUTest/MemoryLeakDetectorNewMacros.h + endif + ifndef CPPUTEST_MEMLEAK_DETECTOR_MALLOC_MACRO_FILE + CPPUTEST_MEMLEAK_DETECTOR_MALLOC_MACRO_FILE = -include $(CPPUTEST_HOME)/include/CppUTest/MemoryLeakDetectorMallocMacros.h + endif +endif + +ifeq ($(CPPUTEST_ENABLE_DEBUG), Y) + CPPUTEST_CXXFLAGS += -g + CPPUTEST_CFLAGS += -g + CPPUTEST_LDFLAGS += -g +endif + +ifeq ($(CPPUTEST_USE_STD_CPP_LIB), N) + CPPUTEST_CPPFLAGS += -DCPPUTEST_STD_CPP_LIB_DISABLED +ifeq ($(CPPUTEST_USE_STD_C_LIB), Y) + CPPUTEST_CXXFLAGS += -nostdinc++ +endif +endif + +ifdef $(GMOCK_HOME) + GTEST_HOME = $(GMOCK_HOME)/gtest + CPPUTEST_CPPFLAGS += -I$(GMOCK_HOME)/include + GMOCK_LIBRARY = $(GMOCK_HOME)/lib/.libs/libgmock.a + LD_LIBRARIES += $(GMOCK_LIBRARY) + CPPUTEST_CPPFLAGS += -DINCLUDE_GTEST_TESTS + CPPUTEST_WARNINGFLAGS = + CPPUTEST_CPPFLAGS += -I$(GTEST_HOME)/include -I$(GTEST_HOME) + GTEST_LIBRARY = $(GTEST_HOME)/lib/.libs/libgtest.a + LD_LIBRARIES += $(GTEST_LIBRARY) +endif + + +ifeq ($(CPPUTEST_USE_GCOV), Y) + CPPUTEST_CXXFLAGS += -fprofile-arcs -ftest-coverage + CPPUTEST_CFLAGS += -fprofile-arcs -ftest-coverage +endif + +CPPUTEST_CXXFLAGS += $(CPPUTEST_WARNINGFLAGS) $(CPPUTEST_CXX_WARNINGFLAGS) +CPPUTEST_CPPFLAGS += $(CPPUTEST_WARNINGFLAGS) +CPPUTEST_CXXFLAGS += $(CPPUTEST_MEMLEAK_DETECTOR_NEW_MACRO_FILE) +CPPUTEST_CPPFLAGS += $(CPPUTEST_MEMLEAK_DETECTOR_MALLOC_MACRO_FILE) +CPPUTEST_CFLAGS += $(CPPUTEST_C_WARNINGFLAGS) + +TARGET_MAP = $(COMPONENT_NAME).map.txt +ifeq ($(CPPUTEST_MAP_FILE), Y) + CPPUTEST_LDFLAGS += -Wl,-map,$(TARGET_MAP) +endif + +# Link with CppUTest lib +CPPUTEST_LIB = $(CPPUTEST_LIB_LINK_DIR)/libCppUTest.a + +ifeq ($(CPPUTEST_USE_EXTENSIONS), Y) +CPPUTEST_LIB += $(CPPUTEST_LIB_LINK_DIR)/libCppUTestExt.a +endif + +ifdef CPPUTEST_STATIC_REALTIME + LD_LIBRARIES += -lrt +endif + +TARGET_LIB = \ + $(CPPUTEST_LIB_DIR)/lib$(COMPONENT_NAME).a + +ifndef TEST_TARGET + ifndef TARGET_PLATFORM + TEST_TARGET = $(COMPONENT_NAME)_tests + else + TEST_TARGET = $(COMPONENT_NAME)_$(TARGET_PLATFORM)_tests + endif +endif + +#Helper Functions +get_src_from_dir = $(wildcard $1/*.cpp) $(wildcard $1/*.cc) $(wildcard $1/*.c) +get_dirs_from_dirspec = $(wildcard $1) +get_src_from_dir_list = $(foreach dir, $1, $(call get_src_from_dir,$(dir))) +__src_to = $(subst .c,$1, $(subst .cc,$1, $(subst .cpp,$1,$(if $(CPPUTEST_USE_VPATH),$(notdir $2),$2)))) +src_to = $(addprefix $(CPPUTEST_OBJS_DIR)/,$(call __src_to,$1,$2)) +src_to_o = $(call src_to,.o,$1) +src_to_d = $(call src_to,.d,$1) +src_to_gcda = $(call src_to,.gcda,$1) +src_to_gcno = $(call src_to,.gcno,$1) +time = $(shell date +%s) +delta_t = $(eval minus, $1, $2) +debug_print_list = $(foreach word,$1,echo " $(word)";) echo; + +#Derived +STUFF_TO_CLEAN += $(TEST_TARGET) $(TEST_TARGET).exe $(TARGET_LIB) $(TARGET_MAP) + +SRC += $(call get_src_from_dir_list, $(SRC_DIRS)) $(SRC_FILES) +OBJ = $(call src_to_o,$(SRC)) + +STUFF_TO_CLEAN += $(OBJ) + +TEST_SRC += $(call get_src_from_dir_list, $(TEST_SRC_DIRS)) $(TEST_SRC_FILES) +TEST_OBJS = $(call src_to_o,$(TEST_SRC)) +STUFF_TO_CLEAN += $(TEST_OBJS) + + +MOCKS_SRC += $(call get_src_from_dir_list, $(MOCKS_SRC_DIRS)) +MOCKS_OBJS = $(call src_to_o,$(MOCKS_SRC)) +STUFF_TO_CLEAN += $(MOCKS_OBJS) + +ALL_SRC = $(SRC) $(TEST_SRC) $(MOCKS_SRC) + +# If we're using VPATH +ifeq ($(CPPUTEST_USE_VPATH), Y) +# gather all the source directories and add them + VPATH += $(sort $(dir $(ALL_SRC))) +# Add the component name to the objs dir path, to differentiate between same-name objects + CPPUTEST_OBJS_DIR := $(addsuffix /$(COMPONENT_NAME),$(CPPUTEST_OBJS_DIR)) +endif + +#Test coverage with gcov +GCOV_OUTPUT = gcov_output.txt +GCOV_REPORT = gcov_report.txt +GCOV_ERROR = gcov_error.txt +GCOV_GCDA_FILES = $(call src_to_gcda, $(ALL_SRC)) +GCOV_GCNO_FILES = $(call src_to_gcno, $(ALL_SRC)) +TEST_OUTPUT = $(TEST_TARGET).txt +STUFF_TO_CLEAN += \ + $(GCOV_OUTPUT)\ + $(GCOV_REPORT)\ + $(GCOV_REPORT).html\ + $(GCOV_ERROR)\ + $(GCOV_GCDA_FILES)\ + $(GCOV_GCNO_FILES)\ + $(TEST_OUTPUT) + +#The gcda files for gcov need to be deleted before each run +#To avoid annoying messages. +GCOV_CLEAN = $(SILENCE)rm -f $(GCOV_GCDA_FILES) $(GCOV_OUTPUT) $(GCOV_REPORT) $(GCOV_ERROR) +RUN_TEST_TARGET = $(SILENCE) $(GCOV_CLEAN) ; echo "Running $(TEST_TARGET)"; ./$(TEST_TARGET) $(CPPUTEST_EXE_FLAGS) -ojunit + +ifeq ($(CPPUTEST_USE_GCOV), Y) + + ifeq ($(COMPILER_NAME),$(CLANG_STR)) + LD_LIBRARIES += --coverage + else + LD_LIBRARIES += -lgcov + endif +endif + + +INCLUDES_DIRS_EXPANDED = $(call get_dirs_from_dirspec, $(INCLUDE_DIRS)) +INCLUDES += $(foreach dir, $(INCLUDES_DIRS_EXPANDED), -I$(dir)) +MOCK_DIRS_EXPANDED = $(call get_dirs_from_dirspec, $(MOCKS_SRC_DIRS)) +INCLUDES += $(foreach dir, $(MOCK_DIRS_EXPANDED), -I$(dir)) + +CPPUTEST_CPPFLAGS += $(INCLUDES) $(CPPUTESTFLAGS) + +DEP_FILES = $(call src_to_d, $(ALL_SRC)) +STUFF_TO_CLEAN += $(DEP_FILES) $(PRODUCTION_CODE_START) $(PRODUCTION_CODE_END) +STUFF_TO_CLEAN += $(STDLIB_CODE_START) $(MAP_FILE) cpputest_*.xml junit_run_output + +# We'll use the CPPUTEST_CFLAGS etc so that you can override AND add to the CppUTest flags +CFLAGS = $(CPPUTEST_CFLAGS) $(CPPUTEST_ADDITIONAL_CFLAGS) +CPPFLAGS = $(CPPUTEST_CPPFLAGS) $(CPPUTEST_ADDITIONAL_CPPFLAGS) +CXXFLAGS = $(CPPUTEST_CXXFLAGS) $(CPPUTEST_ADDITIONAL_CXXFLAGS) +LDFLAGS = $(CPPUTEST_LDFLAGS) $(CPPUTEST_ADDITIONAL_LDFLAGS) + +# Don't consider creating the archive a warning condition that does STDERR output +ARFLAGS := $(ARFLAGS)c + +DEP_FLAGS=-MMD -MP + +# Some macros for programs to be overridden. For some reason, these are not in Make defaults +RANLIB = ranlib + +# Targets + +.PHONY: all +all: start $(TEST_TARGET) + $(RUN_TEST_TARGET) + +.PHONY: start +start: $(TEST_TARGET) + $(SILENCE)START_TIME=$(call time) + +.PHONY: all_no_tests +all_no_tests: $(TEST_TARGET) + +.PHONY: flags +flags: + @echo + @echo "OS ${UNAME_OS}" + @echo "Compile C and C++ source with CPPFLAGS:" + @$(call debug_print_list,$(CPPFLAGS)) + @echo "Compile C++ source with CXXFLAGS:" + @$(call debug_print_list,$(CXXFLAGS)) + @echo "Compile C source with CFLAGS:" + @$(call debug_print_list,$(CFLAGS)) + @echo "Link with LDFLAGS:" + @$(call debug_print_list,$(LDFLAGS)) + @echo "Link with LD_LIBRARIES:" + @$(call debug_print_list,$(LD_LIBRARIES)) + @echo "Create libraries with ARFLAGS:" + @$(call debug_print_list,$(ARFLAGS)) + +TEST_DEPS = $(TEST_OBJS) $(MOCKS_OBJS) $(PRODUCTION_CODE_START) $(TARGET_LIB) $(USER_LIBS) $(PRODUCTION_CODE_END) $(CPPUTEST_LIB) $(STDLIB_CODE_START) +test-deps: $(TEST_DEPS) + +$(TEST_TARGET): $(TEST_DEPS) + @echo Linking $@ + $(SILENCE)$(CXX) -o $@ $^ $(LD_LIBRARIES) $(LDFLAGS) + +$(TARGET_LIB): $(OBJ) + @echo Building archive $@ + $(SILENCE)mkdir -p $(dir $@) + $(SILENCE)$(AR) $(ARFLAGS) $@ $^ + $(SILENCE)$(RANLIB) $@ + +test: $(TEST_TARGET) + $(RUN_TEST_TARGET) | tee $(TEST_OUTPUT) + +vtest: $(TEST_TARGET) + $(RUN_TEST_TARGET) -v | tee $(TEST_OUTPUT) + +$(CPPUTEST_OBJS_DIR)/%.o: %.cc + @echo compiling $(notdir $<) + $(SILENCE)mkdir -p $(dir $@) + $(SILENCE)$(COMPILE.cpp) $(DEP_FLAGS) $(OUTPUT_OPTION) $< + +$(CPPUTEST_OBJS_DIR)/%.o: %.cpp + @echo compiling $(notdir $<) + $(SILENCE)mkdir -p $(dir $@) + $(SILENCE)$(COMPILE.cpp) $(DEP_FLAGS) $(OUTPUT_OPTION) $< + +$(CPPUTEST_OBJS_DIR)/%.o: %.c + @echo compiling $(notdir $<) + $(SILENCE)mkdir -p $(dir $@) + $(SILENCE)$(COMPILE.c) $(DEP_FLAGS) $(OUTPUT_OPTION) $< + +ifneq "$(MAKECMDGOALS)" "clean" +-include $(DEP_FILES) +endif + +.PHONY: clean +clean: + @echo Making clean + $(SILENCE)$(RM) $(STUFF_TO_CLEAN) + $(SILENCE)rm -rf gcov objs #$(CPPUTEST_OBJS_DIR) + $(SILENCE)rm -rf $(CPPUTEST_LIB_DIR) + $(SILENCE)find . -name "*.gcno" | xargs rm -f + $(SILENCE)find . -name "*.gcda" | xargs rm -f + +#realclean gets rid of all gcov, o and d files in the directory tree +#not just the ones made by this makefile +.PHONY: realclean +realclean: clean + $(SILENCE)rm -rf gcov + $(SILENCE)find . -name "*.gdcno" | xargs rm -f + $(SILENCE)find . -name "*.[do]" | xargs rm -f + +gcov: test +ifeq ($(CPPUTEST_USE_VPATH), Y) + $(SILENCE)gcov --object-directory $(CPPUTEST_OBJS_DIR) $(SRC) >> $(GCOV_OUTPUT) 2>> $(GCOV_ERROR) +else + $(SILENCE)for d in $(SRC_DIRS) ; do \ + gcov --object-directory $(CPPUTEST_OBJS_DIR)/$$d $$d/*.c $$d/*.cpp >> $(GCOV_OUTPUT) 2>>$(GCOV_ERROR) ; \ + done + $(SILENCE)for f in $(SRC_FILES) ; do \ + gcov --object-directory $(CPPUTEST_OBJS_DIR)/$$f $$f >> $(GCOV_OUTPUT) 2>>$(GCOV_ERROR) ; \ + done +endif +# $(CPPUTEST_HOME)/scripts/filterGcov.sh $(GCOV_OUTPUT) $(GCOV_ERROR) $(GCOV_REPORT) $(TEST_OUTPUT) + /usr/share/cpputest/scripts/filterGcov.sh $(GCOV_OUTPUT) $(GCOV_ERROR) $(GCOV_REPORT) $(TEST_OUTPUT) + $(SILENCE)cat $(GCOV_REPORT) + $(SILENCE)mkdir -p gcov + $(SILENCE)mv *.gcov gcov + $(SILENCE)mv gcov_* gcov + @echo "See gcov directory for details" + +.PHONEY: format +format: + $(CPPUTEST_HOME)/scripts/reformat.sh $(PROJECT_HOME_DIR) + +.PHONEY: debug +debug: + @echo + @echo "Target Source files:" + @$(call debug_print_list,$(SRC)) + @echo "Target Object files:" + @$(call debug_print_list,$(OBJ)) + @echo "Test Source files:" + @$(call debug_print_list,$(TEST_SRC)) + @echo "Test Object files:" + @$(call debug_print_list,$(TEST_OBJS)) + @echo "Mock Source files:" + @$(call debug_print_list,$(MOCKS_SRC)) + @echo "Mock Object files:" + @$(call debug_print_list,$(MOCKS_OBJS)) + @echo "All Input Dependency files:" + @$(call debug_print_list,$(DEP_FILES)) + @echo Stuff to clean: + @$(call debug_print_list,$(STUFF_TO_CLEAN)) + @echo Includes: + @$(call debug_print_list,$(INCLUDES)) + +-include $(OTHER_MAKEFILE_TO_INCLUDE) diff --git a/features/cellular/UNITTESTS/at/at_cellularbase/Makefile b/features/cellular/UNITTESTS/at/at_cellularbase/Makefile new file mode 100644 index 0000000000..119b84aae9 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularbase/Makefile @@ -0,0 +1,21 @@ +include ../../makefile_defines.txt + +COMPONENT_NAME = AT_CellularBase_unit + +#This must be changed manually +SRC_FILES = \ + ../../../framework/AT/AT_CellularBase.cpp + +TEST_SRC_FILES = \ + main.cpp \ + at_cellularbasetest.cpp \ + test_at_cellularbase.cpp \ + ../../stubs/ATHandler_stub.cpp \ + ../../stubs/EventQueue_stub.cpp \ + ../../stubs/FileHandle_stub.cpp \ + ../../stubs/mbed_assert_stub.cpp \ + +include ../../MakefileWorker.mk + +CPPUTESTFLAGS += -DFEA_TRACE_SUPPORT + diff --git a/features/cellular/UNITTESTS/at/at_cellularbase/at_cellularbasetest.cpp b/features/cellular/UNITTESTS/at/at_cellularbase/at_cellularbasetest.cpp new file mode 100644 index 0000000000..4ad85917da --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularbase/at_cellularbasetest.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) 2015, 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 "CppUTest/TestHarness.h" +#include "test_at_cellularbase.h" +#include "AT_CellularBase.h" + +TEST_GROUP(AT_CellularBase) +{ + Test_AT_CellularBase* unit; + + void setup() + { + unit = new Test_AT_CellularBase(); + } + + void teardown() + { + delete unit; + } +}; + +TEST(AT_CellularBase, Create) +{ + CHECK(unit != NULL); +} + +TEST(AT_CellularBase, test_AT_CellularBase_get_at_handler) +{ + unit->test_AT_CellularBase_get_at_handler(); +} + +TEST(AT_CellularBase, test_AT_CellularBase_get_device_error) +{ + unit->test_AT_CellularBase_get_device_error(); +} + diff --git a/features/cellular/UNITTESTS/at/at_cellularbase/main.cpp b/features/cellular/UNITTESTS/at/at_cellularbase/main.cpp new file mode 100644 index 0000000000..a7c8e49fd9 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularbase/main.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, 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 "CppUTest/CommandLineTestRunner.h" +#include "CppUTest/TestPlugin.h" +#include "CppUTest/TestRegistry.h" +#include "CppUTestExt/MockSupportPlugin.h" +int main(int ac, char** av) +{ + return CommandLineTestRunner::RunAllTests(ac, av); +} + +IMPORT_TEST_GROUP(AT_CellularBase); + diff --git a/features/cellular/UNITTESTS/at/at_cellularbase/test_at_cellularbase.cpp b/features/cellular/UNITTESTS/at/at_cellularbase/test_at_cellularbase.cpp new file mode 100644 index 0000000000..978966564c --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularbase/test_at_cellularbase.cpp @@ -0,0 +1,59 @@ +/* + * 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 "CppUTest/TestHarness.h" +#include "test_at_cellularbase.h" +#include "EventQueue.h" +#include "AT_CellularBase.h" +#include "ATHandler_stub.h" +#include "FileHandle_stub.h" +#include + +using namespace mbed; +using namespace events; + +Test_AT_CellularBase::Test_AT_CellularBase() +{ + +} + +Test_AT_CellularBase::~Test_AT_CellularBase() +{ +} + +void Test_AT_CellularBase::test_AT_CellularBase_get_at_handler() +{ + EventQueue eq; + FileHandle_stub fh; + ATHandler ah(&fh, eq, 100, ","); + AT_CellularBase at(ah); + + CHECK(&ah == &at.get_at_handler()); +} + +void Test_AT_CellularBase::test_AT_CellularBase_get_device_error() +{ + EventQueue eq; + FileHandle_stub fh; + ATHandler ah(&fh, eq, 0, ","); + AT_CellularBase at(ah); + + ATHandler_stub::device_err_value.errCode = 8; + + CHECK_EQUAL(8, at.get_device_error().errCode); + + ATHandler_stub::device_err_value.errCode = 0; +} diff --git a/features/cellular/UNITTESTS/at/at_cellularbase/test_at_cellularbase.h b/features/cellular/UNITTESTS/at/at_cellularbase/test_at_cellularbase.h new file mode 100644 index 0000000000..b384b9cc83 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularbase/test_at_cellularbase.h @@ -0,0 +1,33 @@ +/* + * 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. + */ +#ifndef TEST_AT_CELLULARBASE_H +#define TEST_AT_CELLULARBASE_H + +class Test_AT_CellularBase +{ +public: + Test_AT_CellularBase(); + + virtual ~Test_AT_CellularBase(); + + void test_AT_CellularBase_get_at_handler(); + + void test_AT_CellularBase_get_device_error(); +}; + +#endif // TEST_AT_CELLULARBASE_H + diff --git a/features/cellular/UNITTESTS/at/at_cellulardevice/Makefile b/features/cellular/UNITTESTS/at/at_cellulardevice/Makefile new file mode 100644 index 0000000000..cdc3e27799 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellulardevice/Makefile @@ -0,0 +1,29 @@ +include ../../makefile_defines.txt + +COMPONENT_NAME = AT_CellularDevice_unit + +#This must be changed manually +SRC_FILES = \ + ../../../framework/AT/AT_CellularDevice.cpp + +TEST_SRC_FILES = \ + main.cpp \ + at_cellulardevicetest.cpp \ + test_at_cellulardevice.cpp \ + ../../stubs/AT_CellularNetwork_stub.cpp \ + ../../stubs/ATHandler_stub.cpp \ + ../../stubs/AT_CellularSMS_stub.cpp \ + ../../stubs/AT_CellularSIM_stub.cpp \ + ../../stubs/AT_CellularPower_stub.cpp \ + ../../stubs/AT_CellularInformation_stub.cpp \ + ../../stubs/CellularUtil_stub.cpp \ + ../../stubs/AT_CellularBase_stub.cpp \ + ../../stubs/NetworkInterface_stub.cpp \ + ../../stubs/EventQueue_stub.cpp \ + ../../stubs/FileHandle_stub.cpp \ + ../../stubs/mbed_assert_stub.cpp \ + +include ../../MakefileWorker.mk + +CPPUTESTFLAGS += -DFEA_TRACE_SUPPORT + diff --git a/features/cellular/UNITTESTS/at/at_cellulardevice/at_cellulardevicetest.cpp b/features/cellular/UNITTESTS/at/at_cellulardevice/at_cellulardevicetest.cpp new file mode 100644 index 0000000000..1c5165203c --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellulardevice/at_cellulardevicetest.cpp @@ -0,0 +1,99 @@ +/* + * 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 "CppUTest/TestHarness.h" +#include "test_at_cellulardevice.h" + +TEST_GROUP(AT_CellularDevice) +{ + Test_AT_CellularDevice* unit; + + void setup() + { + unit = new Test_AT_CellularDevice(); + } + + void teardown() + { + delete unit; + } +}; + +TEST(AT_CellularDevice, Create) +{ + CHECK(unit != NULL); +} + +TEST(AT_CellularDevice, test_AT_CellularDevice_constructor) +{ + unit->test_AT_CellularDevice_constructor(); +} + +TEST(AT_CellularDevice, test_AT_CellularDevice_get_at_handler) +{ + unit->test_AT_CellularDevice_get_at_handler(); +} + +TEST(AT_CellularDevice, test_AT_CellularDevice_open_network) +{ + unit->test_AT_CellularDevice_open_network(); +} + +TEST(AT_CellularDevice, test_AT_CellularDevice_open_sms) +{ + unit->test_AT_CellularDevice_open_sms(); +} + +TEST(AT_CellularDevice, test_AT_CellularDevice_open_power) +{ + unit->test_AT_CellularDevice_open_power(); +} + +TEST(AT_CellularDevice, test_AT_CellularDevice_open_sim) +{ + unit->test_AT_CellularDevice_open_sim(); +} + +TEST(AT_CellularDevice, test_AT_CellularDevice_open_information) +{ + unit->test_AT_CellularDevice_open_information(); +} + +TEST(AT_CellularDevice, test_AT_CellularDevice_close_network) +{ + unit->test_AT_CellularDevice_close_network(); +} + +TEST(AT_CellularDevice, test_AT_CellularDevice_close_sms) +{ + unit->test_AT_CellularDevice_close_sms(); +} + +TEST(AT_CellularDevice, test_AT_CellularDevice_close_power) +{ + unit->test_AT_CellularDevice_close_power(); +} + +TEST(AT_CellularDevice, test_AT_CellularDevice_close_sim) +{ + unit->test_AT_CellularDevice_close_sim(); +} + +TEST(AT_CellularDevice, test_AT_CellularDevice_close_information) +{ + unit->test_AT_CellularDevice_close_information(); +} + diff --git a/features/cellular/UNITTESTS/at/at_cellulardevice/main.cpp b/features/cellular/UNITTESTS/at/at_cellulardevice/main.cpp new file mode 100644 index 0000000000..c498759f38 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellulardevice/main.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, 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 "CppUTest/CommandLineTestRunner.h" +#include "CppUTest/TestPlugin.h" +#include "CppUTest/TestRegistry.h" +#include "CppUTestExt/MockSupportPlugin.h" +int main(int ac, char** av) +{ + return CommandLineTestRunner::RunAllTests(ac, av); +} + +IMPORT_TEST_GROUP(AT_CellularDevice); + diff --git a/features/cellular/UNITTESTS/at/at_cellulardevice/test_at_cellulardevice.cpp b/features/cellular/UNITTESTS/at/at_cellulardevice/test_at_cellulardevice.cpp new file mode 100644 index 0000000000..21ccedc61b --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellulardevice/test_at_cellulardevice.cpp @@ -0,0 +1,157 @@ +/* + * 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 "CppUTest/TestHarness.h" +#include "test_at_cellulardevice.h" +#include "AT_CellularDevice.h" +#include "ATHandler_stub.h" +#include "AT_CellularBase_stub.h" +#include + +using namespace mbed; +using namespace events; + +Test_AT_CellularDevice::Test_AT_CellularDevice() +{ + +} + +Test_AT_CellularDevice::~Test_AT_CellularDevice() +{ +} + +void Test_AT_CellularDevice::test_AT_CellularDevice_constructor() +{ + EventQueue que; + AT_CellularDevice dev(que); + + CellularDevice *dev2 = new AT_CellularDevice(que); + delete dev2; +} + +void Test_AT_CellularDevice::test_AT_CellularDevice_get_at_handler() +{ + EventQueue que; + AT_CellularDevice dev(que); + FileHandle_stub fh1; + FileHandle_stub fh2; + FileHandle_stub fh3; + + dev.open_network(&fh1); + dev.open_sms(&fh2); + AT_CellularBase_stub::handler_value = AT_CellularBase_stub::handler_at_constructor_value; + dev.open_sim(&fh3); + ATHandler_stub::fh_value = &fh1; + dev.open_power(&fh1); + + ATHandler_stub::fh_value = NULL; +} + +void Test_AT_CellularDevice::test_AT_CellularDevice_open_network() +{ + EventQueue que; + AT_CellularDevice dev(que); + FileHandle_stub fh1; + + CHECK(!dev.open_network(NULL)); + CHECK(dev.open_network(&fh1)); +} + +void Test_AT_CellularDevice::test_AT_CellularDevice_open_sms() +{ + EventQueue que; + AT_CellularDevice dev(que); + FileHandle_stub fh1; + + CHECK(!dev.open_sms(NULL)); + CHECK(dev.open_sms(&fh1)); +} + +void Test_AT_CellularDevice::test_AT_CellularDevice_open_power() +{ + EventQueue que; + AT_CellularDevice dev(que); + FileHandle_stub fh1; + + CHECK(!dev.open_power(NULL)); + CHECK(dev.open_power(&fh1)); +} + +void Test_AT_CellularDevice::test_AT_CellularDevice_open_sim() +{ + EventQueue que; + AT_CellularDevice dev(que); + FileHandle_stub fh1; + + CHECK(! dev.open_sim(NULL)); + CHECK(dev.open_sim(&fh1)); +} + +void Test_AT_CellularDevice::test_AT_CellularDevice_open_information() +{ + EventQueue que; + AT_CellularDevice dev(que); + FileHandle_stub fh1; + + CHECK(!dev.open_information(NULL)); + CHECK(dev.open_information(&fh1)); +} + +void Test_AT_CellularDevice::test_AT_CellularDevice_close_network() +{ + +} + +void Test_AT_CellularDevice::test_AT_CellularDevice_close_sms() +{ + +} + +void Test_AT_CellularDevice::test_AT_CellularDevice_close_power() +{ + +} + +void Test_AT_CellularDevice::test_AT_CellularDevice_close_sim() +{ + +} + +void Test_AT_CellularDevice::test_AT_CellularDevice_close_information() +{ + EventQueue que; + AT_CellularDevice dev(que); + FileHandle_stub fh1; + ATHandler_stub::int_value = 0; + + CHECK(dev.open_information(&fh1)); + + ATHandler_stub::fh_value = NULL; + AT_CellularBase_stub::handler_value = NULL; + dev.close_information(); + + ATHandler_stub::fh_value = &fh1; + ATHandler at(&fh1, que, 0, ","); + AT_CellularBase_stub::handler_value = &at; + + CHECK(dev.open_information(&fh1)); + AT_CellularBase_stub::handler_value = AT_CellularBase_stub::handler_at_constructor_value; + + dev.close_information(); + + ATHandler_stub::fh_value = NULL; +} + diff --git a/features/cellular/UNITTESTS/at/at_cellulardevice/test_at_cellulardevice.h b/features/cellular/UNITTESTS/at/at_cellulardevice/test_at_cellulardevice.h new file mode 100644 index 0000000000..83873ec4a5 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellulardevice/test_at_cellulardevice.h @@ -0,0 +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. + */ +#ifndef TEST_AT_CELLULARDEVICE_H +#define TEST_AT_CELLULARDEVICE_H + +class Test_AT_CellularDevice +{ +public: + Test_AT_CellularDevice(); + + virtual ~Test_AT_CellularDevice(); + + void test_AT_CellularDevice_constructor(); + + void test_AT_CellularDevice_get_at_handler(); //tests also releasing of those + + void test_AT_CellularDevice_open_network(); + + void test_AT_CellularDevice_open_sms(); + + void test_AT_CellularDevice_open_power(); + + void test_AT_CellularDevice_open_sim(); + + void test_AT_CellularDevice_open_information(); + + void test_AT_CellularDevice_close_network(); + + void test_AT_CellularDevice_close_sms(); + + void test_AT_CellularDevice_close_power(); + + void test_AT_CellularDevice_close_sim(); + + void test_AT_CellularDevice_close_information(); +}; + +#endif // TEST_AT_CELLULARDEVICE_H + diff --git a/features/cellular/UNITTESTS/at/at_cellularinformation/Makefile b/features/cellular/UNITTESTS/at/at_cellularinformation/Makefile new file mode 100644 index 0000000000..cd74bc1b01 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularinformation/Makefile @@ -0,0 +1,22 @@ +include ../../makefile_defines.txt + +COMPONENT_NAME = AT_CellularInformation_unit + +#This must be changed manually +SRC_FILES = \ + ../../../framework/AT/AT_CellularInformation.cpp + +TEST_SRC_FILES = \ + main.cpp \ + at_cellularinformationtest.cpp \ + test_at_cellularinformation.cpp \ + ../../stubs/ATHandler_stub.cpp \ + ../../stubs/AT_CellularBase_stub.cpp \ + ../../stubs/EventQueue_stub.cpp \ + ../../stubs/FileHandle_stub.cpp \ + ../../stubs/mbed_assert_stub.cpp \ + +include ../../MakefileWorker.mk + +CPPUTESTFLAGS += -DFEA_TRACE_SUPPORT + diff --git a/features/cellular/UNITTESTS/at/at_cellularinformation/at_cellularinformationtest.cpp b/features/cellular/UNITTESTS/at/at_cellularinformation/at_cellularinformationtest.cpp new file mode 100644 index 0000000000..0fec4753c1 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularinformation/at_cellularinformationtest.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2015, 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 "CppUTest/TestHarness.h" +#include "test_at_cellularinformation.h" + +TEST_GROUP(AT_CellularInformation) +{ + Test_AT_CellularInformation* unit; + + void setup() + { + unit = new Test_AT_CellularInformation(); + } + + void teardown() + { + delete unit; + } +}; + +TEST(AT_CellularInformation, Create) +{ + CHECK(unit != NULL); +} + +TEST(AT_CellularInformation, test_AT_CellularInformation_get_manufacturer) +{ + unit->test_AT_CellularInformation_get_manufacturer(); +} + +TEST(AT_CellularInformation, test_AT_CellularInformation_get_model) +{ + unit->test_AT_CellularInformation_get_model(); +} + +TEST(AT_CellularInformation, test_AT_CellularInformation_get_revision) +{ + unit->test_AT_CellularInformation_get_revision(); +} + diff --git a/features/cellular/UNITTESTS/at/at_cellularinformation/main.cpp b/features/cellular/UNITTESTS/at/at_cellularinformation/main.cpp new file mode 100644 index 0000000000..48b9907f07 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularinformation/main.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, 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 "CppUTest/CommandLineTestRunner.h" +#include "CppUTest/TestPlugin.h" +#include "CppUTest/TestRegistry.h" +#include "CppUTestExt/MockSupportPlugin.h" +int main(int ac, char** av) +{ + return CommandLineTestRunner::RunAllTests(ac, av); +} + +IMPORT_TEST_GROUP(AT_CellularInformation); + diff --git a/features/cellular/UNITTESTS/at/at_cellularinformation/test_at_cellularinformation.cpp b/features/cellular/UNITTESTS/at/at_cellularinformation/test_at_cellularinformation.cpp new file mode 100644 index 0000000000..2c182d98bf --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularinformation/test_at_cellularinformation.cpp @@ -0,0 +1,81 @@ +/* + * 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 "CppUTest/TestHarness.h" +#include "test_at_cellularinformation.h" +#include +#include "ATHandler_stub.h" +#include "EventQueue.h" +#include "FileHandle_stub.h" +#include "ATHandler.h" +#include "AT_CellularInformation.h" +#include "AT_CellularBase.h" + +using namespace mbed; +using namespace events; + +Test_AT_CellularInformation::Test_AT_CellularInformation() +{ + +} + +Test_AT_CellularInformation::~Test_AT_CellularInformation() +{ +} + +void Test_AT_CellularInformation::test_AT_CellularInformation_get_manufacturer() +{ + EventQueue eq; + FileHandle_stub fh; + ATHandler ah(&fh, eq, 0, ","); + AT_CellularInformation aci(ah); + + ATHandler_stub::nsapi_error_value = 8; + + char buf[8]; + CHECK(8 == aci.get_manufacturer(buf, 8)); +} + +void Test_AT_CellularInformation::test_AT_CellularInformation_get_model() +{ + EventQueue eq; + FileHandle_stub fh; + ATHandler ah(&fh, eq, 0, ","); + AT_CellularInformation aci(ah); + + ATHandler_stub::nsapi_error_value = 7; + + char buf[8]; + CHECK(7 == aci.get_model(buf, 8)); +} + +void Test_AT_CellularInformation::test_AT_CellularInformation_get_revision() +{ + EventQueue eq; + FileHandle_stub fh; + ATHandler ah(&fh, eq, 0, ","); + + //Used heap var here to visit heap constructor + AT_CellularInformation *aci = new AT_CellularInformation(ah); + + ATHandler_stub::nsapi_error_value = 6; + + char buf[8]; + CHECK(6 == aci->get_revision(buf, 8)); + + delete aci; +} + diff --git a/features/cellular/UNITTESTS/at/at_cellularinformation/test_at_cellularinformation.h b/features/cellular/UNITTESTS/at/at_cellularinformation/test_at_cellularinformation.h new file mode 100644 index 0000000000..458d5a0810 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularinformation/test_at_cellularinformation.h @@ -0,0 +1,35 @@ +/* + * 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. + */ +#ifndef TEST_AT_CELLULARINFORMATION_H +#define TEST_AT_CELLULARINFORMATION_H + +class Test_AT_CellularInformation +{ +public: + Test_AT_CellularInformation(); + + virtual ~Test_AT_CellularInformation(); + + void test_AT_CellularInformation_get_manufacturer(); + + void test_AT_CellularInformation_get_model(); + + void test_AT_CellularInformation_get_revision(); +}; + +#endif // TEST_AT_CELLULARINFORMATION_H + diff --git a/features/cellular/UNITTESTS/at/at_cellularnetwork/Makefile b/features/cellular/UNITTESTS/at/at_cellularnetwork/Makefile new file mode 100644 index 0000000000..197f1186e4 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularnetwork/Makefile @@ -0,0 +1,25 @@ +include ../../makefile_defines.txt + +COMPONENT_NAME = AT_CellularNetwork_unit + +#This must be changed manually +SRC_FILES = \ + ../../../framework/AT/AT_CellularNetwork.cpp + +TEST_SRC_FILES = \ + main.cpp \ + at_cellularnetworktest.cpp \ + test_at_cellularnetwork.cpp \ + ../../stubs/ATHandler_stub.cpp \ + ../../stubs/AT_CellularBase_stub.cpp \ + ../../stubs/EventQueue_stub.cpp \ + ../../stubs/FileHandle_stub.cpp \ + ../../stubs/NetworkInterface_stub.cpp \ + ../../stubs/CellularUtil_stub.cpp \ + ../../stubs/us_ticker_stub.cpp \ + ../../stubs/mbed_assert_stub.cpp \ + +include ../../MakefileWorker.mk + +CPPUTESTFLAGS += -DFEA_TRACE_SUPPORT + diff --git a/features/cellular/UNITTESTS/at/at_cellularnetwork/at_cellularnetworktest.cpp b/features/cellular/UNITTESTS/at/at_cellularnetwork/at_cellularnetworktest.cpp new file mode 100644 index 0000000000..48e3518296 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularnetwork/at_cellularnetworktest.cpp @@ -0,0 +1,159 @@ +/* + * Copyright (c) 2015, 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 "CppUTest/TestHarness.h" +#include "test_at_cellularnetwork.h" + +TEST_GROUP(AT_CellularNetwork) +{ + Test_AT_CellularNetwork* unit; + + void setup() + { + unit = new Test_AT_CellularNetwork(); + } + + void teardown() + { + delete unit; + } +}; + +TEST(AT_CellularNetwork, Create) +{ + CHECK(unit != NULL); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_constructor) +{ + unit->test_AT_CellularNetwork_constructor(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_set_credentials) +{ + unit->test_AT_CellularNetwork_set_credentials(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_connect) +{ + unit->test_AT_CellularNetwork_connect(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_disconnect) +{ + unit->test_AT_CellularNetwork_disconnect(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_get_stack) +{ + unit->test_AT_CellularNetwork_get_stack(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_set_registration) +{ + unit->test_AT_CellularNetwork_set_registration(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_get_registration_status) +{ + unit->test_AT_CellularNetwork_get_registration_status(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_set_attach) +{ + unit->test_AT_CellularNetwork_set_attach(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_get_attach) +{ + unit->test_AT_CellularNetwork_get_attach(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_get_rate_control) +{ + unit->test_AT_CellularNetwork_get_rate_control(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_get_apn_backoff_timer) +{ + unit->test_AT_CellularNetwork_get_apn_backoff_timer(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_get_ip_address) +{ + unit->test_AT_CellularNetwork_get_ip_address(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_set_access_technology) +{ + unit->test_AT_CellularNetwork_set_access_technology(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_scan_plmn) +{ + unit->test_AT_CellularNetwork_scan_plmn(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_set_ciot_optimization_config) +{ + unit->test_AT_CellularNetwork_set_ciot_optimization_config(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_get_ciot_optimization_config) +{ + unit->test_AT_CellularNetwork_get_ciot_optimization_config(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_set_stack_type) +{ + unit->test_AT_CellularNetwork_set_stack_type(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_get_stack_type) +{ + unit->test_AT_CellularNetwork_get_stack_type(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_get_pdpcontext_params) +{ + unit->test_AT_CellularNetwork_get_pdpcontext_params(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_get_extended_signal_quality) +{ + unit->test_AT_CellularNetwork_get_extended_signal_quality(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_get_signal_quality) +{ + unit->test_AT_CellularNetwork_get_signal_quality(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_get_cell_id) +{ + unit->test_AT_CellularNetwork_get_cell_id(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_get_3gpp_error) +{ + unit->test_AT_CellularNetwork_get_3gpp_error(); +} + +TEST(AT_CellularNetwork, test_AT_CellularNetwork_get_operator_params) +{ + unit->test_AT_CellularNetwork_get_operator_params(); +} + diff --git a/features/cellular/UNITTESTS/at/at_cellularnetwork/main.cpp b/features/cellular/UNITTESTS/at/at_cellularnetwork/main.cpp new file mode 100644 index 0000000000..2c45fb6cbf --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularnetwork/main.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, 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 "CppUTest/CommandLineTestRunner.h" +#include "CppUTest/TestPlugin.h" +#include "CppUTest/TestRegistry.h" +#include "CppUTestExt/MockSupportPlugin.h" +int main(int ac, char** av) +{ + return CommandLineTestRunner::RunAllTests(ac, av); +} + +IMPORT_TEST_GROUP(AT_CellularNetwork); + diff --git a/features/cellular/UNITTESTS/at/at_cellularnetwork/test_at_cellularnetwork.cpp b/features/cellular/UNITTESTS/at/at_cellularnetwork/test_at_cellularnetwork.cpp new file mode 100644 index 0000000000..c0571e36d8 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularnetwork/test_at_cellularnetwork.cpp @@ -0,0 +1,336 @@ +/* + * 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 "CppUTest/TestHarness.h" +#include "test_at_cellularnetwork.h" +#include +#include "AT_CellularNetwork.h" +#include "EventQueue.h" +#include "ATHandler.h" +#include "AT_CellularDevice.h" +#include "FileHandle_stub.h" +#include "CellularLog.h" +#include "ATHandler_stub.h" + +using namespace mbed; +using namespace events; + +class my_AT_CN : public AT_CellularNetwork { +public: + my_AT_CN(ATHandler &atHandler) : AT_CellularNetwork(atHandler) {} + virtual ~my_AT_CN() {} + NetworkStack *get_stack() {return AT_CellularNetwork::get_stack();} +}; + +void conn_stat_cb(nsapi_error_t error) +{ + +} + +Test_AT_CellularNetwork::Test_AT_CellularNetwork() +{ + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK; + ATHandler_stub::int_value = -1; +} + +Test_AT_CellularNetwork::~Test_AT_CellularNetwork() +{ +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_constructor() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork *cn = new AT_CellularNetwork(at); + + delete cn; +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_set_credentials() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + CHECK(NSAPI_ERROR_OK == cn.set_credentials("apn", CellularNetwork::CHAP)); + + CHECK(NSAPI_ERROR_OK == cn.set_credentials("apn")); +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_connect() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + cn.set_stack_type(IPV4V6_STACK); + CHECK(NSAPI_ERROR_NO_CONNECTION == cn.connect("APN", "a", "b")); + + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_CONNECTION_LOST; + CHECK(NSAPI_ERROR_NO_CONNECTION == cn.connect("APN")); +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_disconnect() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + CHECK(NSAPI_ERROR_OK == cn.disconnect()); +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_get_stack() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + my_AT_CN cn(at); + CHECK(!cn.get_stack()); +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_set_registration() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_CONNECTION_LOST; + CHECK(NSAPI_ERROR_CONNECTION_LOST == cn.set_registration()); +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_get_registration_status() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + CellularNetwork::RegistrationStatus stat; + CHECK(NSAPI_ERROR_OK == cn.get_registration_status(CellularNetwork::C_EREG, stat)); +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_set_attach() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_CONNECTION_LOST; + CHECK(NSAPI_ERROR_CONNECTION_LOST == cn.set_attach()); +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_get_attach() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + CellularNetwork::AttachStatus stat; + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_CONNECTION_LOST; + CHECK(NSAPI_ERROR_CONNECTION_LOST == cn.get_attach(stat)); +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_get_rate_control() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + int ur; + CellularNetwork::RateControlExceptionReports reports; + CellularNetwork::RateControlUplinkTimeUnit timeUnit; + CHECK(NSAPI_ERROR_OK == cn.get_rate_control(reports, timeUnit, ur)); +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_get_apn_backoff_timer() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + int time; + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_CONNECTION_LOST; + CHECK(NSAPI_ERROR_CONNECTION_LOST == cn.get_apn_backoff_timer(time)); +} + + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_get_ip_address() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + CHECK(!cn.get_ip_address()); +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_set_access_technology() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + CHECK(NSAPI_ERROR_UNSUPPORTED == cn.set_access_technology(CellularNetwork::operator_t::RAT_UNKNOWN)); + CHECK(NSAPI_ERROR_UNSUPPORTED == cn.set_access_technology(CellularNetwork::operator_t::RAT_GSM_COMPACT)); +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_scan_plmn() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + int c; + CellularNetwork::operList_t ops; + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_CONNECTION_LOST; + CHECK(NSAPI_ERROR_CONNECTION_LOST == cn.scan_plmn(ops, c)); +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_set_ciot_optimization_config() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_CONNECTION_LOST; + CHECK(NSAPI_ERROR_CONNECTION_LOST == cn.set_ciot_optimization_config(CellularNetwork::SUPPORTED_UE_OPT_NO_SUPPORT, CellularNetwork::PREFERRED_UE_OPT_NO_PREFERENCE)); +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_get_ciot_optimization_config() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + CellularNetwork::Supported_UE_Opt sup; + CellularNetwork::Preferred_UE_Opt pref; + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_CONNECTION_LOST; + CHECK(NSAPI_ERROR_CONNECTION_LOST == cn.get_ciot_optimization_config(sup, pref)); +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_set_stack_type() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + CHECK(NSAPI_ERROR_PARAMETER == cn.set_stack_type(IPV4_STACK)); + + CHECK(NSAPI_ERROR_OK == cn.set_stack_type(DEFAULT_STACK)); +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_get_stack_type() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + CHECK(DEFAULT_STACK == cn.get_stack_type()); +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_get_pdpcontext_params() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + CellularNetwork::pdpContextList_t list; + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_CONNECTION_LOST; + CHECK(NSAPI_ERROR_CONNECTION_LOST == cn.get_pdpcontext_params(list)); +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_get_extended_signal_quality() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + int rx,be,rs,ec,rsrq,rsrp; + CHECK(NSAPI_ERROR_DEVICE_ERROR == cn.get_extended_signal_quality(rx, be,rs,ec,rsrq, rsrp)); + + ATHandler_stub::int_value = 1; + CHECK(NSAPI_ERROR_OK == cn.get_extended_signal_quality(rx, be,rs,ec,rsrq, rsrp)); +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_get_signal_quality() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + int rs,ber; + CHECK(NSAPI_ERROR_DEVICE_ERROR == cn.get_signal_quality(rs,ber)); + + ATHandler_stub::int_value = 1; + CHECK(NSAPI_ERROR_OK == cn.get_signal_quality(rs,ber)); +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_get_cell_id() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + int id; + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_CONNECTION_LOST; + CHECK(NSAPI_ERROR_CONNECTION_LOST == cn.get_cell_id(id)); +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_get_3gpp_error() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + ATHandler_stub::int_value = 8; + CHECK(8 == cn.get_3gpp_error()); +} + +void Test_AT_CellularNetwork::test_AT_CellularNetwork_get_operator_params() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularNetwork cn(at); + int format; + CellularNetwork::operator_t ops; + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_CONNECTION_LOST; + CHECK(NSAPI_ERROR_CONNECTION_LOST == cn.get_operator_params(format, ops)); +} + diff --git a/features/cellular/UNITTESTS/at/at_cellularnetwork/test_at_cellularnetwork.h b/features/cellular/UNITTESTS/at/at_cellularnetwork/test_at_cellularnetwork.h new file mode 100644 index 0000000000..f36fdf034a --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularnetwork/test_at_cellularnetwork.h @@ -0,0 +1,77 @@ +/* + * 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. + */ +#ifndef TEST_AT_CELLULARNETWORK_H +#define TEST_AT_CELLULARNETWORK_H + +class Test_AT_CellularNetwork +{ +public: + Test_AT_CellularNetwork(); + + virtual ~Test_AT_CellularNetwork(); + + void test_AT_CellularNetwork_constructor(); + + void test_AT_CellularNetwork_set_credentials(); + + void test_AT_CellularNetwork_connect(); + + void test_AT_CellularNetwork_disconnect(); + + void test_AT_CellularNetwork_get_stack(); + + void test_AT_CellularNetwork_set_registration(); + + void test_AT_CellularNetwork_get_registration_status(); + + void test_AT_CellularNetwork_set_attach(); + + void test_AT_CellularNetwork_get_attach(); + + void test_AT_CellularNetwork_get_rate_control(); + + void test_AT_CellularNetwork_get_apn_backoff_timer(); + + void test_AT_CellularNetwork_get_ip_address(); + + void test_AT_CellularNetwork_set_access_technology(); + + void test_AT_CellularNetwork_scan_plmn(); + + void test_AT_CellularNetwork_set_ciot_optimization_config(); + + void test_AT_CellularNetwork_get_ciot_optimization_config(); + + void test_AT_CellularNetwork_set_stack_type(); + + void test_AT_CellularNetwork_get_stack_type(); + + void test_AT_CellularNetwork_get_pdpcontext_params(); + + void test_AT_CellularNetwork_get_extended_signal_quality(); + + void test_AT_CellularNetwork_get_signal_quality(); + + void test_AT_CellularNetwork_get_cell_id(); + + void test_AT_CellularNetwork_get_3gpp_error(); + + void test_AT_CellularNetwork_get_operator_params(); +}; + +#endif // TEST_AT_CELLULARNETWORK_H + diff --git a/features/cellular/UNITTESTS/at/at_cellularpower/Makefile b/features/cellular/UNITTESTS/at/at_cellularpower/Makefile new file mode 100644 index 0000000000..6ebcef37e4 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularpower/Makefile @@ -0,0 +1,23 @@ +include ../../makefile_defines.txt + +COMPONENT_NAME = AT_CellularPower_unit + +#This must be changed manually +SRC_FILES = \ + ../../../framework/AT/AT_CellularPower.cpp + +TEST_SRC_FILES = \ + main.cpp \ + at_cellularpowertest.cpp \ + test_at_cellularpower.cpp \ + ../../stubs/ATHandler_stub.cpp \ + ../../stubs/AT_CellularBase_stub.cpp \ + ../../stubs/EventQueue_stub.cpp \ + ../../stubs/FileHandle_stub.cpp \ + ../../stubs/CellularUtil_stub.cpp \ + ../../stubs/mbed_assert_stub.cpp \ + +include ../../MakefileWorker.mk + +CPPUTESTFLAGS += -DFEA_TRACE_SUPPORT + diff --git a/features/cellular/UNITTESTS/at/at_cellularpower/at_cellularpowertest.cpp b/features/cellular/UNITTESTS/at/at_cellularpower/at_cellularpowertest.cpp new file mode 100644 index 0000000000..e7c7072606 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularpower/at_cellularpowertest.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015, 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 "CppUTest/TestHarness.h" +#include "test_at_cellularpower.h" + +TEST_GROUP(AT_CellularPower) +{ + Test_AT_CellularPower* unit; + + void setup() + { + unit = new Test_AT_CellularPower(); + } + + void teardown() + { + delete unit; + } +}; + +TEST(AT_CellularPower, Create) +{ + CHECK(unit != NULL); +} + +TEST(AT_CellularPower, test_AT_CellularPower_constructor) +{ + unit->test_AT_CellularPower_constructor(); +} + +TEST(AT_CellularPower, test_AT_CellularPower_on) +{ + unit->test_AT_CellularPower_on(); +} + +TEST(AT_CellularPower, test_AT_CellularPower_off) +{ + unit->test_AT_CellularPower_off(); +} + +TEST(AT_CellularPower, test_AT_CellularPower_set_at_mode) +{ + unit->test_AT_CellularPower_set_at_mode(); +} + +TEST(AT_CellularPower, test_AT_CellularPower_set_power_level) +{ + unit->test_AT_CellularPower_set_power_level(); +} + +TEST(AT_CellularPower, test_AT_CellularPower_reset) +{ + unit->test_AT_CellularPower_reset(); +} + +TEST(AT_CellularPower, test_AT_CellularPower_opt_power_save_mode) +{ + unit->test_AT_CellularPower_opt_power_save_mode(); +} + +TEST(AT_CellularPower, test_AT_CellularPower_opt_receive_period) +{ + unit->test_AT_CellularPower_opt_receive_period(); +} + diff --git a/features/cellular/UNITTESTS/at/at_cellularpower/main.cpp b/features/cellular/UNITTESTS/at/at_cellularpower/main.cpp new file mode 100644 index 0000000000..a610f2976b --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularpower/main.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, 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 "CppUTest/CommandLineTestRunner.h" +#include "CppUTest/TestPlugin.h" +#include "CppUTest/TestRegistry.h" +#include "CppUTestExt/MockSupportPlugin.h" +int main(int ac, char** av) +{ + return CommandLineTestRunner::RunAllTests(ac, av); +} + +IMPORT_TEST_GROUP(AT_CellularPower); + diff --git a/features/cellular/UNITTESTS/at/at_cellularpower/test_at_cellularpower.cpp b/features/cellular/UNITTESTS/at/at_cellularpower/test_at_cellularpower.cpp new file mode 100644 index 0000000000..f26485e2e2 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularpower/test_at_cellularpower.cpp @@ -0,0 +1,138 @@ +/* + * 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 "CppUTest/TestHarness.h" +#include "test_at_cellularpower.h" +#include +#include "AT_CellularNetwork.h" +#include "EventQueue.h" +#include "ATHandler.h" +#include "AT_CellularPower.h" +#include "FileHandle_stub.h" +#include "ATHandler_stub.h" + +using namespace mbed; +using namespace events; + +Test_AT_CellularPower::Test_AT_CellularPower() +{ + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK; +} + +Test_AT_CellularPower::~Test_AT_CellularPower() +{ +} + +void Test_AT_CellularPower::test_AT_CellularPower_constructor() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularPower *pow = new AT_CellularPower(at); + + delete pow; +} + +void Test_AT_CellularPower::test_AT_CellularPower_on() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularPower pow(at); + CHECK(NSAPI_ERROR_UNSUPPORTED == pow.on()) +} + +void Test_AT_CellularPower::test_AT_CellularPower_off() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularPower pow(at); + CHECK(NSAPI_ERROR_UNSUPPORTED == pow.off()) +} + +void Test_AT_CellularPower::test_AT_CellularPower_set_at_mode() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularPower pow(at); + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_AUTH_FAILURE; + CHECK(NSAPI_ERROR_AUTH_FAILURE == pow.set_at_mode()) +} + +void Test_AT_CellularPower::test_AT_CellularPower_set_power_level() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularPower pow(at); + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_AUTH_FAILURE; + CHECK(NSAPI_ERROR_AUTH_FAILURE == pow.set_power_level(6)); +} + +void Test_AT_CellularPower::test_AT_CellularPower_reset() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularPower pow(at); + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_AUTH_FAILURE; + CHECK(NSAPI_ERROR_AUTH_FAILURE == pow.reset()); +} + +void Test_AT_CellularPower::test_AT_CellularPower_opt_power_save_mode() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularPower pow(at); + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_AUTH_FAILURE; + CHECK(NSAPI_ERROR_AUTH_FAILURE == pow.opt_power_save_mode(0,0)); + + CHECK(NSAPI_ERROR_AUTH_FAILURE == pow.opt_power_save_mode(10,0)); + + CHECK(NSAPI_ERROR_AUTH_FAILURE == pow.opt_power_save_mode(912,0)); + + CHECK(NSAPI_ERROR_AUTH_FAILURE == pow.opt_power_save_mode(1834,1834)); + + CHECK(NSAPI_ERROR_AUTH_FAILURE == pow.opt_power_save_mode(18345,18345)); + + CHECK(NSAPI_ERROR_AUTH_FAILURE == pow.opt_power_save_mode(101234,101234)); + + CHECK(NSAPI_ERROR_AUTH_FAILURE == pow.opt_power_save_mode(1012345,1012345)); + + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK; + CHECK(NSAPI_ERROR_OK == pow.opt_power_save_mode(39612345,39612345)); +} + +void Test_AT_CellularPower::test_AT_CellularPower_opt_receive_period() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularPower pow(at); + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_AUTH_FAILURE; + CHECK(NSAPI_ERROR_AUTH_FAILURE == pow.opt_receive_period(1, CellularPower::EDRXUTRAN_Iu_mode, 3)); +} diff --git a/features/cellular/UNITTESTS/at/at_cellularpower/test_at_cellularpower.h b/features/cellular/UNITTESTS/at/at_cellularpower/test_at_cellularpower.h new file mode 100644 index 0000000000..cd32d6acd6 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularpower/test_at_cellularpower.h @@ -0,0 +1,45 @@ +/* + * 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. + */ +#ifndef TEST_AT_CELLULARPOWER_H +#define TEST_AT_CELLULARPOWER_H + +class Test_AT_CellularPower +{ +public: + Test_AT_CellularPower(); + + virtual ~Test_AT_CellularPower(); + + void test_AT_CellularPower_constructor(); + + void test_AT_CellularPower_on(); + + void test_AT_CellularPower_off(); + + void test_AT_CellularPower_set_at_mode(); + + void test_AT_CellularPower_set_power_level(); + + void test_AT_CellularPower_reset(); + + void test_AT_CellularPower_opt_power_save_mode(); + + void test_AT_CellularPower_opt_receive_period(); +}; + +#endif // TEST_AT_CELLULARPOWER_H + diff --git a/features/cellular/UNITTESTS/at/at_cellularsim/Makefile b/features/cellular/UNITTESTS/at/at_cellularsim/Makefile new file mode 100644 index 0000000000..8c50af13cc --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularsim/Makefile @@ -0,0 +1,24 @@ +include ../../makefile_defines.txt + +COMPONENT_NAME = AT_CellularSIM_unit + +#This must be changed manually +SRC_FILES = \ + ../../../framework/AT/AT_CellularSIM.cpp + +TEST_SRC_FILES = \ + main.cpp \ + at_cellularsimtest.cpp \ + test_at_cellularsim.cpp \ + ../../stubs/ATHandler_stub.cpp \ + ../../stubs/AT_CellularBase_stub.cpp \ + ../../stubs/EventQueue_stub.cpp \ + ../../stubs/FileHandle_stub.cpp \ + ../../stubs/CellularUtil_stub.cpp \ + ../../stubs/us_ticker_stub.cpp \ + ../../stubs/mbed_assert_stub.cpp \ + +include ../../MakefileWorker.mk + +CPPUTESTFLAGS += -DFEA_TRACE_SUPPORT + diff --git a/features/cellular/UNITTESTS/at/at_cellularsim/at_cellularsimtest.cpp b/features/cellular/UNITTESTS/at/at_cellularsim/at_cellularsimtest.cpp new file mode 100644 index 0000000000..f472d2afb4 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularsim/at_cellularsimtest.cpp @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2015, 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 "CppUTest/TestHarness.h" +#include "test_at_cellularsim.h" + +TEST_GROUP(AT_CellularSIM) +{ + Test_AT_CellularSIM* unit; + + void setup() + { + unit = new Test_AT_CellularSIM(); + } + + void teardown() + { + delete unit; + } +}; + +TEST(AT_CellularSIM, Create) +{ + CHECK(unit != NULL); +} + +TEST(AT_CellularSIM, test_AT_CellularSIM_constructor) +{ + unit->test_AT_CellularSIM_constructor(); +} + +TEST(AT_CellularSIM, test_AT_CellularSIM_set_pin) +{ + unit->test_AT_CellularSIM_set_pin(); +} + +TEST(AT_CellularSIM, test_AT_CellularSIM_change_pin) +{ + unit->test_AT_CellularSIM_change_pin(); +} + +TEST(AT_CellularSIM, test_AT_CellularSIM_set_pin_query) +{ + unit->test_AT_CellularSIM_set_pin_query(); +} + +TEST(AT_CellularSIM, test_AT_CellularSIM_get_sim_state) +{ + unit->test_AT_CellularSIM_get_sim_state(); +} + diff --git a/features/cellular/UNITTESTS/at/at_cellularsim/main.cpp b/features/cellular/UNITTESTS/at/at_cellularsim/main.cpp new file mode 100644 index 0000000000..0566c80f33 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularsim/main.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, 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 "CppUTest/CommandLineTestRunner.h" +#include "CppUTest/TestPlugin.h" +#include "CppUTest/TestRegistry.h" +#include "CppUTestExt/MockSupportPlugin.h" +int main(int ac, char** av) +{ + return CommandLineTestRunner::RunAllTests(ac, av); +} + +IMPORT_TEST_GROUP(AT_CellularSIM); + diff --git a/features/cellular/UNITTESTS/at/at_cellularsim/test_at_cellularsim.cpp b/features/cellular/UNITTESTS/at/at_cellularsim/test_at_cellularsim.cpp new file mode 100644 index 0000000000..71d782c302 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularsim/test_at_cellularsim.cpp @@ -0,0 +1,131 @@ +/* + * 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 "CppUTest/TestHarness.h" +#include "test_at_cellularsim.h" +#include +#include "AT_CellularNetwork.h" +#include "EventQueue.h" +#include "ATHandler.h" +#include "AT_CellularSIM.h" +#include "FileHandle_stub.h" +#include "CellularLog.h" +#include "ATHandler_stub.h" + +using namespace mbed; +using namespace events; + +Test_AT_CellularSIM::Test_AT_CellularSIM() +{ + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK; + ATHandler_stub::read_string_value = NULL; + ATHandler_stub::ssize_value = 0; +} + +Test_AT_CellularSIM::~Test_AT_CellularSIM() +{ +} + +void Test_AT_CellularSIM::test_AT_CellularSIM_constructor() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularSIM *sim = new AT_CellularSIM(at); + + delete sim; +} + +void Test_AT_CellularSIM::test_AT_CellularSIM_set_pin() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularSIM sim(at); + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_AUTH_FAILURE; + CHECK(NSAPI_ERROR_AUTH_FAILURE == sim.set_pin("12")); + + char table2[] = "READY"; + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK; + ATHandler_stub::read_string_value = table2; + ATHandler_stub::ssize_value = 5; + CHECK(NSAPI_ERROR_OK == sim.set_pin("12")); +} + +void Test_AT_CellularSIM::test_AT_CellularSIM_change_pin() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularSIM sim(at); + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_AUTH_FAILURE; + CHECK(NSAPI_ERROR_AUTH_FAILURE == sim.change_pin("12", "34")); +} + +void Test_AT_CellularSIM::test_AT_CellularSIM_set_pin_query() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularSIM sim(at); + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_AUTH_FAILURE; + CHECK(NSAPI_ERROR_AUTH_FAILURE == sim.set_pin_query("12", true)); + + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_AUTH_FAILURE; + CHECK(NSAPI_ERROR_AUTH_FAILURE == sim.set_pin_query("12", false)); +} + +void Test_AT_CellularSIM::test_AT_CellularSIM_get_sim_state() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularSIM sim(at); + CellularSIM::SimState state; + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_AUTH_FAILURE; + ATHandler_stub::ssize_value = -1; + CHECK(NSAPI_ERROR_AUTH_FAILURE == sim.get_sim_state(state)); + CHECK(CellularSIM::SimStateUnknown == state); + + char table2[] = "READY"; + ATHandler_stub::read_string_value = table2; + ATHandler_stub::ssize_value = 5; + CHECK(NSAPI_ERROR_AUTH_FAILURE == sim.get_sim_state(state)); + CHECK(CellularSIM::SimStateReady == state); + + char table3[] = "SIM PIN"; + ATHandler_stub::read_string_value = table3; + ATHandler_stub::ssize_value = 7; + CHECK(NSAPI_ERROR_AUTH_FAILURE == sim.get_sim_state(state)); + CHECK(CellularSIM::SimStatePinNeeded == state); + + char table4[] = "SIM PUK"; + ATHandler_stub::read_string_value = table4; + ATHandler_stub::ssize_value = 7; + CHECK(NSAPI_ERROR_AUTH_FAILURE == sim.get_sim_state(state)); + CHECK(CellularSIM::SimStatePukNeeded == state); + + char table5[] = "SOME CRAP"; + ATHandler_stub::read_string_value = table5; + ATHandler_stub::ssize_value = 9; + CHECK(NSAPI_ERROR_AUTH_FAILURE == sim.get_sim_state(state)); + CHECK(CellularSIM::SimStateUnknown == state); +} diff --git a/features/cellular/UNITTESTS/at/at_cellularsim/test_at_cellularsim.h b/features/cellular/UNITTESTS/at/at_cellularsim/test_at_cellularsim.h new file mode 100644 index 0000000000..95e296270f --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularsim/test_at_cellularsim.h @@ -0,0 +1,39 @@ +/* + * 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. + */ +#ifndef TEST_AT_CELLULARSIM_H +#define TEST_AT_CELLULARSIM_H + +class Test_AT_CellularSIM +{ +public: + Test_AT_CellularSIM(); + + virtual ~Test_AT_CellularSIM(); + + void test_AT_CellularSIM_constructor(); + + void test_AT_CellularSIM_set_pin(); + + void test_AT_CellularSIM_change_pin(); + + void test_AT_CellularSIM_set_pin_query(); + + void test_AT_CellularSIM_get_sim_state(); +}; + +#endif // TEST_AT_CELLULARSIM_H + diff --git a/features/cellular/UNITTESTS/at/at_cellularsms/Makefile b/features/cellular/UNITTESTS/at/at_cellularsms/Makefile new file mode 100644 index 0000000000..dd7a07ce1b --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularsms/Makefile @@ -0,0 +1,25 @@ +include ../../makefile_defines.txt + +COMPONENT_NAME = AT_CellularSMS_unit + +#This must be changed manually +SRC_FILES = \ + ../../../framework/AT/AT_CellularSMS.cpp + +TEST_SRC_FILES = \ + main.cpp \ + at_cellularsmstest.cpp \ + test_at_cellularsms.cpp \ + ../../stubs/ATHandler_stub.cpp \ + ../../stubs/AT_CellularBase_stub.cpp \ + ../../stubs/EventQueue_stub.cpp \ + ../../stubs/FileHandle_stub.cpp \ + ../../stubs/CellularUtil_stub.cpp \ + ../../stubs/us_ticker_stub.cpp \ + ../../stubs/mbed_assert_stub.cpp \ + ../../stubs/mbed_wait_api_stub.cpp \ + +include ../../MakefileWorker.mk + +CPPUTESTFLAGS += -DFEA_TRACE_SUPPORT + diff --git a/features/cellular/UNITTESTS/at/at_cellularsms/at_cellularsmstest.cpp b/features/cellular/UNITTESTS/at/at_cellularsms/at_cellularsmstest.cpp new file mode 100644 index 0000000000..88754bfc4a --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularsms/at_cellularsmstest.cpp @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2015, 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 "CppUTest/TestHarness.h" +#include "test_at_cellularsms.h" + +TEST_GROUP(AT_CellularSMS) +{ + Test_AT_CellularSMS* unit; + + void setup() + { + unit = new Test_AT_CellularSMS(); + } + + void teardown() + { + delete unit; + } +}; + +TEST(AT_CellularSMS, Create) +{ + CHECK(unit != NULL); +} + +TEST(AT_CellularSMS, test_AT_CellularSMS_constructor) +{ + unit->test_AT_CellularSMS_constructor(); +} + +TEST(AT_CellularSMS, test_AT_CellularSMS_initialize) +{ + unit->test_AT_CellularSMS_initialize(); +} + +TEST(AT_CellularSMS, test_AT_CellularSMS_send_sms) +{ + unit->test_AT_CellularSMS_send_sms(); +} + +TEST(AT_CellularSMS, test_AT_CellularSMS_get_sms) +{ + unit->test_AT_CellularSMS_get_sms(); +} + +TEST(AT_CellularSMS, test_AT_CellularSMS_set_sms_callback) +{ + unit->test_AT_CellularSMS_set_sms_callback(); +} + +TEST(AT_CellularSMS, test_AT_CellularSMS_set_cpms) +{ + unit->test_AT_CellularSMS_set_cpms(); +} + +TEST(AT_CellularSMS, test_AT_CellularSMS_set_csca) +{ + unit->test_AT_CellularSMS_set_csca(); +} + +TEST(AT_CellularSMS, test_AT_CellularSMS_set_cscs) +{ + unit->test_AT_CellularSMS_set_cscs(); +} + +TEST(AT_CellularSMS, test_AT_CellularSMS_delete_all_messages) +{ + unit->test_AT_CellularSMS_delete_all_messages(); +} + +TEST(AT_CellularSMS, test_AT_CellularSMS_set_extra_sim_wait_time) +{ + unit->test_AT_CellularSMS_set_extra_sim_wait_time(); +} diff --git a/features/cellular/UNITTESTS/at/at_cellularsms/main.cpp b/features/cellular/UNITTESTS/at/at_cellularsms/main.cpp new file mode 100644 index 0000000000..a1fc31e69a --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularsms/main.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, 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 "CppUTest/CommandLineTestRunner.h" +#include "CppUTest/TestPlugin.h" +#include "CppUTest/TestRegistry.h" +#include "CppUTestExt/MockSupportPlugin.h" +int main(int ac, char** av) +{ + return CommandLineTestRunner::RunAllTests(ac, av); +} + +IMPORT_TEST_GROUP(AT_CellularSMS); + diff --git a/features/cellular/UNITTESTS/at/at_cellularsms/test_at_cellularsms.cpp b/features/cellular/UNITTESTS/at/at_cellularsms/test_at_cellularsms.cpp new file mode 100644 index 0000000000..f505be0db1 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularsms/test_at_cellularsms.cpp @@ -0,0 +1,207 @@ +/* + * 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 "CppUTest/TestHarness.h" +#include "test_at_cellularsms.h" +#include +#include "AT_CellularNetwork.h" +#include "EventQueue.h" +#include "ATHandler.h" +#include "ATHandler_stub.h" +#include "AT_CellularSMS.h" +#include "FileHandle_stub.h" +#include "CellularLog.h" + +using namespace mbed; +using namespace events; + +Test_AT_CellularSMS::Test_AT_CellularSMS() +{ + ATHandler_stub::return_given_size = false; + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK; +} + +Test_AT_CellularSMS::~Test_AT_CellularSMS() +{ +} + +void Test_AT_CellularSMS::test_AT_CellularSMS_constructor() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularSMS *sms = new AT_CellularSMS(at); + + delete sms; +} + +void Test_AT_CellularSMS::test_AT_CellularSMS_initialize() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularSMS sms(at); + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_AUTH_FAILURE; + CHECK(NSAPI_ERROR_AUTH_FAILURE == sms.initialize(CellularSMS::CellularSMSMmodeText)); +} + + +void Test_AT_CellularSMS::test_AT_CellularSMS_send_sms() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularSMS sms(at); + CHECK(NSAPI_ERROR_PARAMETER == sms.send_sms(NULL, "2", 1)); + + sms.initialize(CellularSMS::CellularSMSMmodeText); + ATHandler_stub::size_value = 1; + CHECK(1 == sms.send_sms("1", "22", 2)); + + ATHandler_stub::size_value = 2; + CHECK(2 == sms.send_sms("1", "22", 2)); + + sms.initialize(CellularSMS::CellularSMSMmodePDU); + CHECK(2 == sms.send_sms("1", "23", 2)); + + ATHandler_stub::nsapi_error_ok_counter = 1; + ATHandler_stub::size_value = 32; + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_AUTH_FAILURE; + CHECK(NSAPI_ERROR_AUTH_FAILURE == sms.send_sms("1", "23232323", 8)); + + ATHandler_stub::nsapi_error_ok_counter = 2; + ATHandler_stub::size_value = 32; + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_AUTH_FAILURE; + CHECK(NSAPI_ERROR_AUTH_FAILURE == sms.send_sms("1", "23232323", 8)); + + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_OK; + char table[] = "232323232323232323232323232323232323232323232323232323\ + 232323232323232323232323232323232323232323232323232323\ + 232323232323232323232323232323232323232323232323232323\ + 23232323232323232323232323232323232323\0"; + ATHandler_stub::size_value = 0; + ATHandler_stub::return_given_size = true; + CHECK(218 == sms.send_sms("1", table, strlen(table))); + + CHECK(218 == sms.send_sms("12", table, strlen(table))); +} + + +void Test_AT_CellularSMS::test_AT_CellularSMS_get_sms() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularSMS sms(at); + char buf[16]; + char phone[21]; + char stamp[21]; + int size; + CHECK(NSAPI_ERROR_PARAMETER == sms.get_sms(NULL, 16, phone, 21, stamp, 21, &size)); + + ATHandler_stub::resp_info_true_counter = 1; + ATHandler_stub::int_value = 0; + CHECK(-1 == sms.get_sms(buf, 16, phone, 21, stamp, 21, &size)); + + ATHandler_stub::resp_info_true_counter = 2; + ATHandler_stub::int_value = 11; + CHECK(0 == sms.get_sms(buf, 16, phone, 21, stamp, 21, &size)); + //TODO: Should make add_info to happen, before calling get_sms! + + ATHandler_stub::resp_info_true_counter = 2; + ATHandler_stub::int_value = 11; + sms.initialize(CellularSMS::CellularSMSMmodePDU); + CHECK(0 == sms.get_sms(buf, 16, phone, 21, stamp, 21, &size)); + + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_AUTH_FAILURE; + CHECK(NSAPI_ERROR_AUTH_FAILURE == sms.get_sms(buf, 16, phone, 21, stamp, 21, &size)); +} + + +void Test_AT_CellularSMS::test_AT_CellularSMS_set_sms_callback() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularSMS sms(at); + sms.set_sms_callback(NULL); +} + + +void Test_AT_CellularSMS::test_AT_CellularSMS_set_cpms() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularSMS sms(at); + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_AUTH_FAILURE; + CHECK(NSAPI_ERROR_AUTH_FAILURE == sms.set_cpms("2", "3", "4")); +} + + +void Test_AT_CellularSMS::test_AT_CellularSMS_set_csca() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularSMS sms(at); + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_AUTH_FAILURE; + CHECK(NSAPI_ERROR_AUTH_FAILURE == sms.set_csca("2", 1)); +} + + +void Test_AT_CellularSMS::test_AT_CellularSMS_set_cscs() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularSMS sms(at); + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_AUTH_FAILURE; + CHECK(NSAPI_ERROR_AUTH_FAILURE == sms.set_cscs("2")); +} + + +void Test_AT_CellularSMS::test_AT_CellularSMS_delete_all_messages() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularSMS sms(at); + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_AUTH_FAILURE; + CHECK(NSAPI_ERROR_AUTH_FAILURE == sms.delete_all_messages()); +} + + +void Test_AT_CellularSMS::test_AT_CellularSMS_set_extra_sim_wait_time() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + AT_CellularSMS sms(at); + sms.set_extra_sim_wait_time(56); + +} + diff --git a/features/cellular/UNITTESTS/at/at_cellularsms/test_at_cellularsms.h b/features/cellular/UNITTESTS/at/at_cellularsms/test_at_cellularsms.h new file mode 100644 index 0000000000..43eb7ebdf5 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularsms/test_at_cellularsms.h @@ -0,0 +1,49 @@ +/* + * 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. + */ +#ifndef TEST_AT_CELLULARSMS_H +#define TEST_AT_CELLULARSMS_H + +class Test_AT_CellularSMS +{ +public: + Test_AT_CellularSMS(); + + virtual ~Test_AT_CellularSMS(); + + void test_AT_CellularSMS_constructor(); + + void test_AT_CellularSMS_initialize(); + + void test_AT_CellularSMS_send_sms(); + + void test_AT_CellularSMS_get_sms(); + + void test_AT_CellularSMS_set_sms_callback(); + + void test_AT_CellularSMS_set_cpms(); + + void test_AT_CellularSMS_set_csca(); + + void test_AT_CellularSMS_set_cscs(); + + void test_AT_CellularSMS_delete_all_messages(); + + void test_AT_CellularSMS_set_extra_sim_wait_time(); +}; + +#endif // TEST_AT_CELLULARSMS_H + diff --git a/features/cellular/UNITTESTS/at/at_cellularstack/Makefile b/features/cellular/UNITTESTS/at/at_cellularstack/Makefile new file mode 100644 index 0000000000..5371687a3e --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularstack/Makefile @@ -0,0 +1,26 @@ +include ../../makefile_defines.txt + +COMPONENT_NAME = AT_CellularStack_unit + +#This must be changed manually +SRC_FILES = \ + ../../../framework/AT/AT_CellularStack.cpp + +TEST_SRC_FILES = \ + main.cpp \ + at_cellularstacktest.cpp \ + test_at_cellularstack.cpp \ + ../../stubs/ATHandler_stub.cpp \ + ../../stubs/AT_CellularBase_stub.cpp \ + ../../stubs/EventQueue_stub.cpp \ + ../../stubs/FileHandle_stub.cpp \ + ../../stubs/CellularUtil_stub.cpp \ + ../../stubs/us_ticker_stub.cpp \ + ../../stubs/NetworkStack_stub.cpp \ + ../../stubs/SocketAddress_stub.cpp \ + ../../stubs/mbed_assert_stub.cpp \ + +include ../../MakefileWorker.mk + +CPPUTESTFLAGS += -DFEA_TRACE_SUPPORT + diff --git a/features/cellular/UNITTESTS/at/at_cellularstack/at_cellularstacktest.cpp b/features/cellular/UNITTESTS/at/at_cellularstack/at_cellularstacktest.cpp new file mode 100644 index 0000000000..d4815f92ae --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularstack/at_cellularstacktest.cpp @@ -0,0 +1,104 @@ +/* + * Copyright (c) 2015, 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 "CppUTest/TestHarness.h" +#include "test_at_cellularstack.h" + +TEST_GROUP(AT_CellularStack) +{ + Test_AT_CellularStack* unit; + + void setup() + { + unit = new Test_AT_CellularStack(); + } + + void teardown() + { + delete unit; + } +}; + +TEST(AT_CellularStack, Create) +{ + CHECK(unit != NULL); +} + +TEST(AT_CellularStack, test_AT_CellularStack_constructor) +{ + unit->test_AT_CellularStack_constructor(); +} + +TEST(AT_CellularStack, test_AT_CellularStack_get_ip_address) +{ + unit->test_AT_CellularStack_get_ip_address(); +} + +TEST(AT_CellularStack, test_AT_CellularStack_socket_open) +{ + unit->test_AT_CellularStack_socket_open(); +} + +TEST(AT_CellularStack, test_AT_CellularStack_socket_close) +{ + unit->test_AT_CellularStack_socket_close(); +} + +TEST(AT_CellularStack, test_AT_CellularStack_socket_bind) +{ + unit->test_AT_CellularStack_socket_bind(); +} + +TEST(AT_CellularStack, test_AT_CellularStack_socket_listen) +{ + unit->test_AT_CellularStack_socket_listen(); +} + +TEST(AT_CellularStack, test_AT_CellularStack_socket_connect) +{ + unit->test_AT_CellularStack_socket_connect(); +} + +TEST(AT_CellularStack, test_AT_CellularStack_socket_accept) +{ + unit->test_AT_CellularStack_socket_accept(); +} + +TEST(AT_CellularStack, test_AT_CellularStack_socket_send) +{ + unit->test_AT_CellularStack_socket_send(); +} + +TEST(AT_CellularStack, test_AT_CellularStack_socket_recv) +{ + unit->test_AT_CellularStack_socket_recv(); +} + +TEST(AT_CellularStack, test_AT_CellularStack_socket_sendto) +{ + unit->test_AT_CellularStack_socket_sendto(); +} + +TEST(AT_CellularStack, test_AT_CellularStack_socket_recvfrom) +{ + unit->test_AT_CellularStack_socket_recvfrom(); +} + +TEST(AT_CellularStack, test_AT_CellularStack_socket_attach) +{ + unit->test_AT_CellularStack_socket_attach(); +} + diff --git a/features/cellular/UNITTESTS/at/at_cellularstack/main.cpp b/features/cellular/UNITTESTS/at/at_cellularstack/main.cpp new file mode 100644 index 0000000000..46520ddd58 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularstack/main.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, 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 "CppUTest/CommandLineTestRunner.h" +#include "CppUTest/TestPlugin.h" +#include "CppUTest/TestRegistry.h" +#include "CppUTestExt/MockSupportPlugin.h" +int main(int ac, char** av) +{ + return CommandLineTestRunner::RunAllTests(ac, av); +} + +IMPORT_TEST_GROUP(AT_CellularStack); + diff --git a/features/cellular/UNITTESTS/at/at_cellularstack/test_at_cellularstack.cpp b/features/cellular/UNITTESTS/at/at_cellularstack/test_at_cellularstack.cpp new file mode 100644 index 0000000000..eef98a7ce1 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularstack/test_at_cellularstack.cpp @@ -0,0 +1,325 @@ +/* + * 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 "CppUTest/TestHarness.h" +#include "test_at_cellularstack.h" +#include +#include "AT_CellularNetwork.h" +#include "EventQueue.h" +#include "ATHandler.h" +#include "AT_CellularStack.h" +#include "FileHandle_stub.h" +#include "CellularLog.h" +#include "ATHandler_stub.h" +#include "SocketAddress.h" + +using namespace mbed; +using namespace events; + +class MyStack : public AT_CellularStack { +public: + bool bool_value; + bool max_sock_value; + nsapi_error_t create_error; + int max_packet_size; + + MyStack(ATHandler &atr, int cid, nsapi_ip_stack_t typ) : AT_CellularStack(atr, cid, typ) + { + bool_value = false; + max_sock_value = 0; + create_error = NSAPI_ERROR_OK; + max_packet_size = 0; + } + + virtual int get_max_socket_count(){return max_sock_value;} + + virtual int get_max_packet_size(){return max_packet_size;} + + virtual bool is_protocol_supported(nsapi_protocol_t protocol){return bool_value;} + + virtual nsapi_error_t socket_close_impl(int sock_id){return NSAPI_ERROR_OK;} + + virtual nsapi_error_t create_socket_impl(CellularSocket *socket){return create_error;} + + virtual nsapi_size_or_error_t socket_sendto_impl(CellularSocket *socket, const SocketAddress &address, + const void *data, nsapi_size_t size){return NSAPI_ERROR_OK;} + + virtual nsapi_size_or_error_t socket_recvfrom_impl(CellularSocket *socket, SocketAddress *address, + void *buffer, nsapi_size_t size) {return NSAPI_ERROR_OK;} + + virtual nsapi_error_t socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto) {return AT_CellularStack::socket_open(handle, proto);} + + virtual nsapi_error_t socket_close(nsapi_socket_t handle) {return AT_CellularStack::socket_close(handle);} + + virtual nsapi_error_t socket_bind(nsapi_socket_t handle, const SocketAddress &address) {return AT_CellularStack::socket_bind(handle, address);} + + virtual nsapi_error_t socket_listen(nsapi_socket_t handle, int backlog) {return AT_CellularStack::socket_listen(handle, backlog);} + + virtual nsapi_error_t socket_connect(nsapi_socket_t handle, const SocketAddress &address) {return AT_CellularStack::socket_connect(handle, address);} + + virtual nsapi_error_t socket_accept(nsapi_socket_t server, + nsapi_socket_t *handle, SocketAddress *address=0) {return AT_CellularStack::socket_accept(server, handle, address);} + + virtual nsapi_size_or_error_t socket_send(nsapi_socket_t handle, + const void *data, nsapi_size_t size) {return AT_CellularStack::socket_send(handle, data, size);} + + virtual nsapi_size_or_error_t socket_recv(nsapi_socket_t handle, + void *data, nsapi_size_t size) {return AT_CellularStack::socket_recv(handle, data, size);} + + virtual nsapi_size_or_error_t socket_sendto(nsapi_socket_t handle, const SocketAddress &address, + const void *data, nsapi_size_t size) {return AT_CellularStack::socket_sendto(handle, address, data, size);} + + virtual nsapi_size_or_error_t socket_recvfrom(nsapi_socket_t handle, SocketAddress *address, + void *buffer, nsapi_size_t size) {return AT_CellularStack::socket_recvfrom(handle, address, buffer, size);} + + virtual void socket_attach(nsapi_socket_t handle, void (*callback)(void *), void *data) {return AT_CellularStack::socket_attach(handle, callback, data);} +}; + +Test_AT_CellularStack::Test_AT_CellularStack() +{ + ATHandler_stub::ssize_value = 0; + ATHandler_stub::bool_value = false; + ATHandler_stub::read_string_value = NULL; +} + +Test_AT_CellularStack::~Test_AT_CellularStack() +{ +} + +void Test_AT_CellularStack::test_AT_CellularStack_constructor() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + MyStack *st = new MyStack(at, 0, IPV4_STACK); + + delete st; +} + +void Test_AT_CellularStack::test_AT_CellularStack_get_ip_address() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + MyStack st(at, 0, IPV6_STACK); + CHECK(0 == strlen(st.get_ip_address())); + + char table[] = "1.2.3.4.5.65.7.8.9.10.11\0"; + ATHandler_stub::ssize_value = -1; + ATHandler_stub::bool_value = true; + ATHandler_stub::read_string_value = table; + CHECK(NULL == st.get_ip_address()); + + ATHandler_stub::ssize_value = strlen(table); + ATHandler_stub::bool_value = true; + ATHandler_stub::read_string_value = table; + CHECK(st.get_ip_address()); +} + +void Test_AT_CellularStack::test_AT_CellularStack_socket_open() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + MyStack st(at, 0, IPV6_STACK); + st.bool_value = false; + CHECK(NSAPI_ERROR_UNSUPPORTED == st.socket_open(NULL, NSAPI_TCP)); + + st.bool_value = true; + st.max_sock_value = 0; + nsapi_socket_t sock; + CHECK(NSAPI_ERROR_NO_SOCKET == st.socket_open(&sock, NSAPI_TCP)); + + MyStack st2(at, 0, IPV6_STACK); + st2.bool_value = true; + st2.max_sock_value = 1; + nsapi_socket_t sock2; + CHECK(NSAPI_ERROR_OK == st2.socket_open(&sock2, NSAPI_TCP)); +} + +void Test_AT_CellularStack::test_AT_CellularStack_socket_close() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + MyStack st(at, 0, IPV6_STACK); + nsapi_socket_t soc = NULL; + CHECK(NSAPI_ERROR_DEVICE_ERROR == st.socket_close(soc)); + + st.bool_value = true; + st.max_sock_value = 1; + nsapi_socket_t sock; + CHECK(NSAPI_ERROR_OK == st.socket_open(&sock, NSAPI_TCP)); + st.max_sock_value = 0; + CHECK(NSAPI_ERROR_DEVICE_ERROR == st.socket_close(sock)); + + MyStack st2(at, 0, IPV6_STACK); + st2.max_sock_value = 1; + st2.bool_value = true; + nsapi_socket_t sock2; + CHECK(NSAPI_ERROR_OK == st2.socket_open(&sock2, NSAPI_TCP)); + CHECK(NSAPI_ERROR_OK == st2.socket_close(sock2)); +} + +void Test_AT_CellularStack::test_AT_CellularStack_socket_bind() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + MyStack st(at, 0, IPV6_STACK); + nsapi_socket_t sock; + SocketAddress addr; + ATHandler_stub::nsapi_error_value = NSAPI_ERROR_ALREADY; + CHECK(NSAPI_ERROR_DEVICE_ERROR == st.socket_bind(NULL, addr)); + + CHECK(NSAPI_ERROR_ALREADY == st.socket_bind(sock, addr)); +} + +void Test_AT_CellularStack::test_AT_CellularStack_socket_listen() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + MyStack st(at, 0, IPV6_STACK); + nsapi_socket_t sock; + CHECK(0 == st.socket_listen(sock, 4)); +} + +void Test_AT_CellularStack::test_AT_CellularStack_socket_connect() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + MyStack st(at, 0, IPV6_STACK); + SocketAddress addr; + CHECK(NSAPI_ERROR_DEVICE_ERROR == st.socket_connect(NULL, addr)); + + nsapi_socket_t sock; + CHECK(NSAPI_ERROR_OK == st.socket_connect(sock, addr)); +} + +void Test_AT_CellularStack::test_AT_CellularStack_socket_accept() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + MyStack st(at, 0, IPV6_STACK); + nsapi_socket_t sock; + CHECK(0 == st.socket_accept(NULL, &sock)); +} + +void Test_AT_CellularStack::test_AT_CellularStack_socket_send() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + MyStack st(at, 0, IPV6_STACK); + CHECK(NSAPI_ERROR_DEVICE_ERROR == st.socket_send(NULL, "addr", 4)); + + nsapi_socket_t sock; + CHECK(NSAPI_ERROR_DEVICE_ERROR == st.socket_send(sock, "addr", 4)); + + SocketAddress addr; + st.max_sock_value = 1; + st.bool_value = true; + st.socket_open(&sock, NSAPI_TCP); + st.socket_connect(sock, addr); + CHECK(NSAPI_ERROR_DEVICE_ERROR == st.socket_send(sock, "addr", 4)); +} + +void Test_AT_CellularStack::test_AT_CellularStack_socket_sendto() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + MyStack st(at, 0, IPV6_STACK); + + nsapi_socket_t sock; + SocketAddress addr; + CHECK(NSAPI_ERROR_DEVICE_ERROR == st.socket_sendto(NULL, addr, "addr", 4)); + + st.max_sock_value = 1; + st.bool_value = true; + st.socket_open(&sock, NSAPI_TCP); + st.socket_connect(sock, addr); + st.create_error = NSAPI_ERROR_CONNECTION_LOST; + CHECK(NSAPI_ERROR_CONNECTION_LOST == st.socket_sendto(sock, addr, "addr", 4)); + + st.create_error = NSAPI_ERROR_OK; + st.max_packet_size = 6; + CHECK(NSAPI_ERROR_OK == st.socket_sendto(sock, addr, "addr", 4)); +} + +void Test_AT_CellularStack::test_AT_CellularStack_socket_recv() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + MyStack st(at, 0, IPV6_STACK); + char table[4]; + CHECK(NSAPI_ERROR_DEVICE_ERROR == st.socket_recv(NULL, table, 4)); +} + +void Test_AT_CellularStack::test_AT_CellularStack_socket_recvfrom() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + MyStack st(at, 0, IPV6_STACK); + char table[4]; + CHECK(NSAPI_ERROR_DEVICE_ERROR == st.socket_recvfrom(NULL, NULL, table, 4)); + + nsapi_socket_t sock; + SocketAddress addr; + st.max_sock_value = 1; + st.bool_value = true; + st.socket_open(&sock, NSAPI_TCP); + st.socket_connect(sock, addr); + st.create_error = NSAPI_ERROR_CONNECTION_LOST; + CHECK(NSAPI_ERROR_CONNECTION_LOST == st.socket_recvfrom(sock, &addr, table, 4)); + + st.create_error = NSAPI_ERROR_OK; + st.max_packet_size = 6; + CHECK(NSAPI_ERROR_OK == st.socket_recvfrom(sock, &addr, table, 4)); +} + +void Test_AT_CellularStack::test_AT_CellularStack_socket_attach() +{ + EventQueue que; + FileHandle_stub fh1; + ATHandler at(&fh1, que, 0, ","); + + MyStack st(at, 0, IPV6_STACK); + + st.socket_attach(NULL, NULL, NULL); + nsapi_socket_t sock; + st.max_sock_value = 1; + st.bool_value = true; + st.socket_open(&sock, NSAPI_TCP); + st.socket_attach(sock, NULL, NULL); +} diff --git a/features/cellular/UNITTESTS/at/at_cellularstack/test_at_cellularstack.h b/features/cellular/UNITTESTS/at/at_cellularstack/test_at_cellularstack.h new file mode 100644 index 0000000000..1c77553618 --- /dev/null +++ b/features/cellular/UNITTESTS/at/at_cellularstack/test_at_cellularstack.h @@ -0,0 +1,55 @@ +/* + * 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. + */ +#ifndef TEST_AT_CELLULARSTACK_H +#define TEST_AT_CELLULARSTACK_H + +class Test_AT_CellularStack +{ +public: + Test_AT_CellularStack(); + + virtual ~Test_AT_CellularStack(); + + void test_AT_CellularStack_constructor(); + + void test_AT_CellularStack_get_ip_address(); + + void test_AT_CellularStack_socket_open(); + + void test_AT_CellularStack_socket_close(); + + void test_AT_CellularStack_socket_bind(); + + void test_AT_CellularStack_socket_listen(); + + void test_AT_CellularStack_socket_connect(); + + void test_AT_CellularStack_socket_accept(); + + void test_AT_CellularStack_socket_send(); + + void test_AT_CellularStack_socket_recv(); + + void test_AT_CellularStack_socket_sendto(); + + void test_AT_CellularStack_socket_recvfrom(); + + void test_AT_CellularStack_socket_attach(); +}; + +#endif // TEST_AT_CELLULARSTACK_H + diff --git a/features/cellular/UNITTESTS/at/athandler/Makefile b/features/cellular/UNITTESTS/at/athandler/Makefile new file mode 100644 index 0000000000..c0bc7b422b --- /dev/null +++ b/features/cellular/UNITTESTS/at/athandler/Makefile @@ -0,0 +1,27 @@ +include ../../makefile_defines.txt + +COMPONENT_NAME = ATHandler_unit + +#This must be changed manually +SRC_FILES = \ + ../../../framework/AT/ATHandler.cpp + +TEST_SRC_FILES = \ + main.cpp \ + athandlertest.cpp \ + test_athandler.cpp \ + ../../stubs/AT_CellularBase_stub.cpp \ + ../../stubs/EventQueue_stub.cpp \ + ../../stubs/FileHandle_stub.cpp \ + ../../stubs/CellularUtil_stub.cpp \ + ../../stubs/us_ticker_stub.cpp \ + ../../stubs/mbed_wait_api_stub.cpp \ + ../../stubs/mbed_assert_stub.cpp \ + ../../stubs/mbed_poll_stub.cpp \ + ../../stubs/Timer_stub.cpp \ + ../../stubs/equeue_stub.cpp \ + +include ../../MakefileWorker.mk + +CPPUTESTFLAGS += -DFEA_TRACE_SUPPORT + diff --git a/features/cellular/UNITTESTS/at/athandler/athandlertest.cpp b/features/cellular/UNITTESTS/at/athandler/athandlertest.cpp new file mode 100644 index 0000000000..916608c0dd --- /dev/null +++ b/features/cellular/UNITTESTS/at/athandler/athandlertest.cpp @@ -0,0 +1,218 @@ +/* + * Copyright (c) 2015, 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 "CppUTest/TestHarness.h" +#include "test_athandler.h" + +TEST_GROUP(ATHandler) +{ + Test_ATHandler* unit; + + void setup() + { + unit = new Test_ATHandler(); + } + + void teardown() + { + delete unit; + } +}; + +TEST(ATHandler, Create) +{ + CHECK(unit != NULL); +} + +TEST(ATHandler, test_ATHandler_constructor) +{ + unit->test_ATHandler_constructor(); +} + +TEST(ATHandler, test_ATHandler_get_file_handle) +{ + unit->test_ATHandler_get_file_handle(); +} + +TEST(ATHandler, test_ATHandler_set_file_handle) +{ + unit->test_ATHandler_set_file_handle(); +} + +TEST(ATHandler, test_ATHandler_lock) +{ + unit->test_ATHandler_lock(); +} + +TEST(ATHandler, test_ATHandler_unlock) +{ + unit->test_ATHandler_unlock(); +} + +TEST(ATHandler, test_ATHandler_unlock_return_error) +{ + unit->test_ATHandler_unlock_return_error(); +} + +TEST(ATHandler, test_ATHandler_set_urc_handler) +{ + unit->test_ATHandler_set_urc_handler(); +} + +TEST(ATHandler, test_ATHandler_get_last_error) +{ + unit->test_ATHandler_get_last_error(); +} + +TEST(ATHandler, test_ATHandler_get_last_device_error) +{ + unit->test_ATHandler_get_last_device_error(); +} + +TEST(ATHandler, test_ATHandler_inc_ref_count) +{ + unit->test_ATHandler_inc_ref_count(); +} + +TEST(ATHandler, test_ATHandler_dec_ref_count) +{ + unit->test_ATHandler_dec_ref_count(); +} + +TEST(ATHandler, test_ATHandler_get_ref_count) +{ + unit->test_ATHandler_get_ref_count(); +} + +TEST(ATHandler, test_ATHandler_set_at_timeout) +{ + unit->test_ATHandler_set_at_timeout(); +} + +TEST(ATHandler, test_ATHandler_restore_at_timeout) +{ + unit->test_ATHandler_restore_at_timeout(); +} + +TEST(ATHandler, test_ATHandler_clear_error) +{ + unit->test_ATHandler_clear_error(); +} + +TEST(ATHandler, test_ATHandler_process_oob) +{ + unit->test_ATHandler_process_oob(); +} + +TEST(ATHandler, test_ATHandler_set_filehandle_sigio) +{ + unit->test_ATHandler_set_filehandle_sigio(); +} + +TEST(ATHandler, test_ATHandler_flush) +{ + unit->test_ATHandler_flush(); +} + +TEST(ATHandler, test_ATHandler_cmd_start) +{ + unit->test_ATHandler_cmd_start(); +} + +TEST(ATHandler, test_ATHandler_write_int) +{ + unit->test_ATHandler_write_int(); +} + +TEST(ATHandler, test_ATHandler_write_string) +{ + unit->test_ATHandler_write_string(); +} + +TEST(ATHandler, test_ATHandler_cmd_stop) +{ + unit->test_ATHandler_cmd_stop(); +} + +TEST(ATHandler, test_ATHandler_write_bytes) +{ + unit->test_ATHandler_write_bytes(); +} + +TEST(ATHandler, test_ATHandler_set_stop_tag) +{ + unit->test_ATHandler_set_stop_tag(); +} + +TEST(ATHandler, test_ATHandler_set_delimiter) +{ + unit->test_ATHandler_set_delimiter(); +} + +TEST(ATHandler, test_ATHandler_skip_param) +{ + unit->test_ATHandler_skip_param(); +} + +TEST(ATHandler, test_ATHandler_read_bytes) +{ + unit->test_ATHandler_read_bytes(); +} + +TEST(ATHandler, test_ATHandler_read_string) +{ + unit->test_ATHandler_read_string(); +} + +TEST(ATHandler, test_ATHandler_read_int) +{ + unit->test_ATHandler_read_int(); +} + +TEST(ATHandler, test_ATHandler_resp_start) +{ + unit->test_ATHandler_resp_start(); +} + +TEST(ATHandler, test_ATHandler_resp_stop) +{ + unit->test_ATHandler_resp_stop(); +} + +TEST(ATHandler, test_ATHandler_info_resp) +{ + unit->test_ATHandler_info_resp(); +} + +TEST(ATHandler, test_ATHandler_info_elem) +{ + unit->test_ATHandler_info_elem(); +} + +TEST(ATHandler, test_ATHandler_consume_to_stop_tag) +{ + unit->test_ATHandler_consume_to_stop_tag(); +} + +TEST(ATHandler, test_ATHandler_enable_debug) +{ + unit->test_ATHandler_enable_debug(); +} + +TEST(ATHandler, test_ATHandler_get_3gpp_error) +{ + unit->test_ATHandler_get_3gpp_error(); +} diff --git a/features/cellular/UNITTESTS/at/athandler/main.cpp b/features/cellular/UNITTESTS/at/athandler/main.cpp new file mode 100644 index 0000000000..beac7f7f37 --- /dev/null +++ b/features/cellular/UNITTESTS/at/athandler/main.cpp @@ -0,0 +1,28 @@ +/* + * Copyright (c) 2015, 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 "CppUTest/CommandLineTestRunner.h" +#include "CppUTest/TestPlugin.h" +#include "CppUTest/TestRegistry.h" +#include "CppUTestExt/MockSupportPlugin.h" +int main(int ac, char** av) +{ + return CommandLineTestRunner::RunAllTests(ac, av); +} + +IMPORT_TEST_GROUP(ATHandler); + diff --git a/features/cellular/UNITTESTS/at/athandler/test_athandler.cpp b/features/cellular/UNITTESTS/at/athandler/test_athandler.cpp new file mode 100644 index 0000000000..7dd9075603 --- /dev/null +++ b/features/cellular/UNITTESTS/at/athandler/test_athandler.cpp @@ -0,0 +1,773 @@ +/* + * 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 "CppUTest/TestHarness.h" +#include "test_athandler.h" +#include +#include "AT_CellularNetwork.h" +#include "EventQueue.h" +#include "ATHandler.h" +#include "AT_CellularStack.h" +#include "FileHandle_stub.h" +#include "CellularLog.h" +#include "mbed_poll_stub.h" + +#include "Timer_stub.h" + +using namespace mbed; +using namespace events; + +void urc_callback() +{ +} + +Test_ATHandler::Test_ATHandler() +{ + +} + +Test_ATHandler::~Test_ATHandler() +{ +} + +void Test_ATHandler::test_ATHandler_constructor() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler *at = new ATHandler(&fh1, que, 0, ","); + + delete at; + + at = new ATHandler(&fh1, que, 0, NULL); + + delete at; +} + +void Test_ATHandler::test_ATHandler_get_file_handle() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + CHECK_EQUAL(&fh1, at.get_file_handle()); +} + +void Test_ATHandler::test_ATHandler_set_file_handle() +{ + EventQueue que; + FileHandle_stub fh1, fh2; + + ATHandler at(&fh1, que, 0, ","); + + at.set_file_handle(&fh2); +} + +void Test_ATHandler::test_ATHandler_lock() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + + at.lock(); +} + +void Test_ATHandler::test_ATHandler_unlock() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + filehandle_stub_short_value_counter = 1; + fh1.short_value = POLLIN; + at.unlock(); +} + +void Test_ATHandler::test_ATHandler_unlock_return_error() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + CHECK(NSAPI_ERROR_OK == at.unlock_return_error()); +} + +void Test_ATHandler::test_ATHandler_set_urc_handler() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + const char ch[] = "testtesttesttest"; + at.set_urc_handler(ch, &urc_callback); +} + +void Test_ATHandler::test_ATHandler_get_last_error() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + CHECK(NSAPI_ERROR_OK == at.get_last_error()); +} + +void Test_ATHandler::test_ATHandler_get_last_device_error() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + CHECK(0 == at.get_last_device_error().errCode); +} + +void Test_ATHandler::test_ATHandler_inc_ref_count() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + at.inc_ref_count(); +} + +void Test_ATHandler::test_ATHandler_dec_ref_count() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + at.dec_ref_count(); +} + +void Test_ATHandler::test_ATHandler_get_ref_count() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + CHECK(1 == at.get_ref_count()); + + at.inc_ref_count(); + CHECK(2 == at.get_ref_count()); + + at.inc_ref_count(); + CHECK(3 == at.get_ref_count()); + + at.dec_ref_count(); + at.dec_ref_count(); + CHECK(1 == at.get_ref_count()); +} + +void Test_ATHandler::test_ATHandler_set_at_timeout() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + at.set_at_timeout(8); + + at.set_at_timeout(80, true); +} + +void Test_ATHandler::test_ATHandler_restore_at_timeout() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + at.set_at_timeout(80, true); + at.set_at_timeout(800); + at.restore_at_timeout(); +} + +void Test_ATHandler::test_ATHandler_clear_error() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + at.clear_error(); +} + +void Test_ATHandler::test_ATHandler_process_oob() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + filehandle_stub_short_value_counter = 1; + fh1.short_value = POLLIN; + at.set_urc_handler("s", &urc_callback); + at.process_oob(); + + filehandle_stub_short_value_counter = 2; + at.process_oob(); + + //at.fill_buffer(); + uint8_t buf[5]; + at.clear_error(); + char table[] = "ssssssssssssssssssssssssssssssss\0"; + filehandle_stub_table = table; + filehandle_stub_table_pos = 0; + at.read_bytes(buf, 5); + + filehandle_stub_short_value_counter = 2; + at.process_oob(); + + at.clear_error(); + timer_stub_value = 0; + filehandle_stub_table_pos = 0; + at.read_bytes(buf, 5); + + filehandle_stub_short_value_counter = 1; + at.process_oob(); + + char table2[4]; + table2[0] = '\r'; + table2[1] = '\r'; + table2[2] = '\n'; + table2[3] = 0; + filehandle_stub_table = table2; + + at.clear_error(); + timer_stub_value = 0; + filehandle_stub_table_pos = 0; + at.read_bytes(buf, 1); + + filehandle_stub_short_value_counter = 1; + at.process_oob(); + + + filehandle_stub_table = table; + + + filehandle_stub_short_value_counter = 0; + filehandle_stub_table_pos = 0; + filehandle_stub_table = NULL; +} + +void Test_ATHandler::test_ATHandler_set_filehandle_sigio() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + at.set_filehandle_sigio(); +} + +void Test_ATHandler::test_ATHandler_flush() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + filehandle_stub_short_value_counter = 1; + fh1.short_value = POLLIN; + at.flush(); +} + +void Test_ATHandler::test_ATHandler_cmd_start() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + mbed_poll_stub::revents_value = POLLOUT; + mbed_poll_stub::int_value = 1; + fh1.size_value = 1; + at.cmd_start("s"); + mbed_poll_stub::revents_value = POLLIN; + mbed_poll_stub::int_value = 0; + + at.cmd_start("s"); + + at.cmd_start("s"); +} + +void Test_ATHandler::test_ATHandler_write_int() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + at.write_int(4); + + at.clear_error(); + mbed_poll_stub::revents_value = POLLOUT; + mbed_poll_stub::int_value = 1; + fh1.size_value = 1; + at.write_int(4); + + at.write_int(2147483647); + + at.write_int(2147483647+1); + +// at.at_error(0, DeviceErrorType(0)); +// at.write_int(4); +} + +void Test_ATHandler::test_ATHandler_write_string() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + at.write_string("help"); + CHECK(NSAPI_ERROR_DEVICE_ERROR == at.get_last_error()); + + at.clear_error(); + mbed_poll_stub::revents_value = POLLOUT; + mbed_poll_stub::int_value = 1; + fh1.size_value = 1; + at.cmd_start("s"); + at.write_string("help", true); + CHECK(NSAPI_ERROR_DEVICE_ERROR == at.get_last_error()); + + at.clear_error(); + mbed_poll_stub::revents_value = POLLOUT; + mbed_poll_stub::int_value = 1; + fh1.size_value = 3; + at.write_string("help", true); + CHECK(NSAPI_ERROR_DEVICE_ERROR == at.get_last_error()); + + at.clear_error(); + mbed_poll_stub::revents_value = POLLOUT; + mbed_poll_stub::int_value = 1; + fh1.size_value = 7; + at.write_string("help", true); + CHECK(NSAPI_ERROR_OK == at.get_last_error()); +} + +void Test_ATHandler::test_ATHandler_cmd_stop() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + at.cmd_stop(); + + at.write_string("help", true); + + at.cmd_stop(); + CHECK(NSAPI_ERROR_DEVICE_ERROR == at.get_last_error()); +} + +void Test_ATHandler::test_ATHandler_write_bytes() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + uint8_t data[] = "data"; + at.write_bytes(data, 4); + + at.write_bytes(data, 4); + CHECK(NSAPI_ERROR_DEVICE_ERROR == at.get_last_error()); +} + +void Test_ATHandler::test_ATHandler_set_stop_tag() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + at.set_stop_tag("s"); +} + +void Test_ATHandler::test_ATHandler_set_delimiter() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + at.set_delimiter('+'); +} + +void Test_ATHandler::test_ATHandler_skip_param() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + at.skip_param(); + + char table[] = "ssssssssssssssssssssssssssssOK\r\n\0"; + filehandle_stub_table = table; + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + at.resp_start(); + at.skip_param(); + CHECK(at.get_last_error() == NSAPI_ERROR_DEVICE_ERROR); + + char table1[] = "ss,sssssssssssss,sssssssssssOK\r\n\0"; + filehandle_stub_table = table1; + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + at.resp_start(); + at.skip_param(); + + char table2[] = "sssOK\r\n\0"; + filehandle_stub_table = table2; + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + at.resp_start(); + at.skip_param(); + + char table3[] = "sssssssOK\nssss\0"; + filehandle_stub_table = table3; + filehandle_stub_table_pos = 0; + + //Need to create a new instance because stop tag already found + ATHandler at2(&fh1, que, 0, ","); + at2.flush(); + at2.clear_error(); + at2.resp_start(); + at2.skip_param(); + + at2.skip_param(4, 3); + + filehandle_stub_table = table3; + filehandle_stub_table_pos = 0; + + at2.flush(); + at2.clear_error(); + at2.resp_start(); + at2.skip_param(4, 3); + + filehandle_stub_table = table3; + filehandle_stub_table_pos = 0; + + at2.flush(); + at2.clear_error(); + at2.resp_start(); + at2.skip_param(24, 17); +} + +void Test_ATHandler::test_ATHandler_read_bytes() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + uint8_t buf[5]; + CHECK(-1 == at.read_bytes(buf, 25)); + + CHECK(-1 == at.read_bytes(buf, 5)); + + char table[] = "ssssssssssssssssssssssssssssOK\r\n\0"; + filehandle_stub_table = table; + filehandle_stub_table_pos = 0; + + at.clear_error(); + CHECK(5 == at.read_bytes(buf, 5)); +} + +void Test_ATHandler::test_ATHandler_read_string() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + + char table[] = "\"s,\"OK\r\n\0"; + filehandle_stub_table = table; + filehandle_stub_table_pos = 0; + + char buf[5]; + uint8_t buf2[5]; + at.flush(); + at.clear_error(); + at.resp_start(); + at.read_bytes(buf2, 5); + CHECK(-1 == at.read_string(buf, 15)); + + filehandle_stub_table = table; + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + at.resp_start(); + at.read_bytes(buf2, 1); + CHECK(1 == at.read_string(buf, 5, true)); + + char table2[] = "\"s\"OK\r\n\0"; + filehandle_stub_table = table2; + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + at.resp_start(); + at.read_bytes(buf2, 1); + CHECK(1 == at.read_string(buf, 5, true)); + + char table3[] = "sss\rsss\0"; + filehandle_stub_table = table3; + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + at.resp_start("s"); + at.read_string(buf, 5, true); + + char table4[] = "\"s\"\0"; + filehandle_stub_table = table4; + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + at.resp_start("s"); + at.read_string(buf, 5, true); + + filehandle_stub_table = NULL; + filehandle_stub_table_pos = 0; +} + +void Test_ATHandler::test_ATHandler_read_int() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + + int32_t ret= at.read_int(); + CHECK(-1 == ret); + + char table[] = "\",\"OK\r\n\0"; + filehandle_stub_table = table; + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + at.resp_start(); + + ret= at.read_int(); + CHECK(-1 == ret); + + char table2[] = "\"2,\"OK\r\n\0"; + filehandle_stub_table = table2; + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + at.resp_start(); + + ret= at.read_int(); + CHECK(2 == ret); + +} + +void Test_ATHandler::test_ATHandler_resp_start() +{ + EventQueue que; + FileHandle_stub fh1; + + filehandle_stub_table = NULL; + filehandle_stub_table_pos = 0; + + ATHandler at(&fh1, que, 0, ","); + at.resp_start(); + at.resp_start(); + + char table2[] = "\"2,\"OK\r\n\0"; + filehandle_stub_table = table2; + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + at.resp_start("ssssaaaassssaaaassss"); //too long prefix + + char table3[] = "+CME ERROR: 108\0"; + filehandle_stub_table = table3; + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + at.resp_start(); + + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + at.resp_start(); + + char table4[] = "+CMS ERROR: 6\0"; + filehandle_stub_table = table4; + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + at.resp_start(); + + char table5[] = "ERROR\r\n\0"; + filehandle_stub_table = table5; + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + at.resp_start(); + + char table6[] = "OK\r\n\0"; + filehandle_stub_table = table6; + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + at.resp_start(); + + char table7[] = "ssssss\0"; + filehandle_stub_table = table7; + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + at.set_urc_handler("ss", NULL); + at.resp_start(); +} + +void Test_ATHandler::test_ATHandler_resp_stop() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + + char table[] = "21 OK\r\n\0"; + filehandle_stub_table = table; + filehandle_stub_table_pos = 0; + + at.info_elem('2'); + at.set_stop_tag("OK\r\n"); + at.resp_stop(); + + char table3[] = "+CME ERROR: 108\0"; + filehandle_stub_table = table3; + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + at.resp_start(); + + at.resp_stop(); + + char table7[] = "ssssss\0"; + filehandle_stub_table = table7; + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + at.resp_start("ss", false); + at.resp_stop(); +} + +void Test_ATHandler::test_ATHandler_info_resp() +{ + EventQueue que; + FileHandle_stub fh1; + + filehandle_stub_table = NULL; + + ATHandler at(&fh1, que, 0, ","); + CHECK(at.info_resp()); + + at.resp_start(); + CHECK(!at.info_resp()); + + char table2[] = "21 OK\r\n\0"; + filehandle_stub_table = table2; + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + at.resp_start("21"); + CHECK(at.info_resp()); + + CHECK(!at.info_resp()); + + char table3[] = "21 OK\r\n\0"; + filehandle_stub_table = table3; + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + CHECK(at.info_resp()); +} + +void Test_ATHandler::test_ATHandler_info_elem() +{ + EventQueue que; + FileHandle_stub fh1; + + char table[] = "21 OK\r\n\0"; + filehandle_stub_table = table; + filehandle_stub_table_pos = 0; + + ATHandler at(&fh1, que, 0, ","); + CHECK(!at.info_elem(char(79))); + + char table2[] = "21 OK\r\n\0"; + filehandle_stub_table = table2; + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + at.resp_start("21"); + CHECK(at.info_elem(char(79))); + + CHECK(at.info_elem('2')); + + filehandle_stub_table = NULL; + filehandle_stub_table_pos = 0; + + at.flush(); + at.clear_error(); + at.resp_start("21"); + CHECK(!at.info_elem('2')); +} + +void Test_ATHandler::test_ATHandler_consume_to_stop_tag() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + CHECK(at.consume_to_stop_tag()); +} + +void Test_ATHandler::test_ATHandler_enable_debug() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + at.enable_debug(true); + + at.enable_debug(false); +} + +void Test_ATHandler::test_ATHandler_get_3gpp_error() +{ + EventQueue que; + FileHandle_stub fh1; + + ATHandler at(&fh1, que, 0, ","); + int ret = at.get_3gpp_error(); +} diff --git a/features/cellular/UNITTESTS/at/athandler/test_athandler.h b/features/cellular/UNITTESTS/at/athandler/test_athandler.h new file mode 100644 index 0000000000..0acecc693c --- /dev/null +++ b/features/cellular/UNITTESTS/at/athandler/test_athandler.h @@ -0,0 +1,101 @@ +/* + * 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. + */ +#ifndef TEST_ATHANDLER_H +#define TEST_ATHANDLER_H + +class Test_ATHandler +{ +public: + Test_ATHandler(); + + virtual ~Test_ATHandler(); + + void test_ATHandler_constructor(); + + void test_ATHandler_get_file_handle(); + + void test_ATHandler_set_file_handle(); + + void test_ATHandler_lock(); + + void test_ATHandler_unlock(); + + void test_ATHandler_unlock_return_error(); + + void test_ATHandler_set_urc_handler(); + + void test_ATHandler_get_last_error(); + + void test_ATHandler_get_last_device_error(); + + void test_ATHandler_inc_ref_count(); + + void test_ATHandler_dec_ref_count(); + + void test_ATHandler_get_ref_count(); + + void test_ATHandler_set_at_timeout(); + + void test_ATHandler_restore_at_timeout(); + + void test_ATHandler_clear_error(); + + void test_ATHandler_process_oob(); + + void test_ATHandler_set_filehandle_sigio(); + + void test_ATHandler_flush(); + + void test_ATHandler_cmd_start(); + + void test_ATHandler_write_int(); + + void test_ATHandler_write_string(); + + void test_ATHandler_cmd_stop(); + + void test_ATHandler_write_bytes(); + + void test_ATHandler_set_stop_tag(); + + void test_ATHandler_set_delimiter(); + + void test_ATHandler_skip_param(); + + void test_ATHandler_read_bytes(); + + void test_ATHandler_read_string(); + + void test_ATHandler_read_int(); + + void test_ATHandler_resp_start(); + + void test_ATHandler_resp_stop(); + + void test_ATHandler_info_resp(); + + void test_ATHandler_info_elem(); + + void test_ATHandler_consume_to_stop_tag(); + + void test_ATHandler_enable_debug(); + + void test_ATHandler_get_3gpp_error(); +}; + +#endif // TEST_ATHANDLER_H + diff --git a/features/cellular/UNITTESTS/common/util/Makefile b/features/cellular/UNITTESTS/common/util/Makefile new file mode 100644 index 0000000000..9e7614bf0b --- /dev/null +++ b/features/cellular/UNITTESTS/common/util/Makefile @@ -0,0 +1,17 @@ +include ../../makefile_defines.txt + +COMPONENT_NAME = util_unit + +#This must be changed manually +SRC_FILES = \ + ../../../framework/common/CellularUtil.cpp + +TEST_SRC_FILES = \ + main.cpp \ + utiltest.cpp \ + test_util.cpp \ + +include ../../MakefileWorker.mk + +CPPUTESTFLAGS += -DFEA_TRACE_SUPPORT + diff --git a/features/cellular/UNITTESTS/common/util/main.cpp b/features/cellular/UNITTESTS/common/util/main.cpp new file mode 100644 index 0000000000..4438de28a8 --- /dev/null +++ b/features/cellular/UNITTESTS/common/util/main.cpp @@ -0,0 +1,28 @@ +/* + * 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 "CppUTest/CommandLineTestRunner.h" +#include "CppUTest/TestPlugin.h" +#include "CppUTest/TestRegistry.h" +#include "CppUTestExt/MockSupportPlugin.h" +int main(int ac, char** av) +{ + return CommandLineTestRunner::RunAllTests(ac, av); +} + +IMPORT_TEST_GROUP(util); + diff --git a/features/cellular/UNITTESTS/common/util/test_util.cpp b/features/cellular/UNITTESTS/common/util/test_util.cpp new file mode 100644 index 0000000000..30459e02d0 --- /dev/null +++ b/features/cellular/UNITTESTS/common/util/test_util.cpp @@ -0,0 +1,177 @@ +/* + * 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 "CppUTest/TestHarness.h" +#include "test_util.h" +#include +#include "CellularUtil.h" + +using namespace mbed_cellular_util; + +Test_util::Test_util() +{ + +} + +Test_util::~Test_util() +{ +} + +void Test_util::test_util_uint_to_binary_string() +{ + char str[33]; + uint_to_binary_str(15, str, 33, 32); + str[32] = '\0'; + // 15 is "1111" in binary but we ask all 32 bits so it should return "00000000000000000000000000001111" + STRCMP_EQUAL("00000000000000000000000000001111", str); + + // test NULL pointer + uint_to_binary_str(15, NULL, 0, 32); + + // test give too small buffer + char too_small[5]; + uint_to_binary_str(15, too_small, 5, 6); +} + +void Test_util::test_util_char_str_to_hex() +{ + // basic conversion test, happy days + char hex_buf[50]; + uint16_t number_of_hex_chars = char_str_to_hex_str("1234", 4, hex_buf); + hex_buf[number_of_hex_chars] = '\0'; + STRCMP_EQUAL("31323334", hex_buf); + LONGS_EQUAL(8, number_of_hex_chars); + + number_of_hex_chars = char_str_to_hex_str("wuhuu", 5, hex_buf); + hex_buf[number_of_hex_chars] = '\0'; + STRCMP_EQUAL("7775687575", hex_buf); + LONGS_EQUAL(10, number_of_hex_chars); + + // First don't omit the leading zero and then omit and check that leading zero is missing + number_of_hex_chars = char_str_to_hex_str("\nwuhuu", 6, hex_buf); + hex_buf[number_of_hex_chars] = '\0'; + STRCMP_EQUAL("0A7775687575", hex_buf); + LONGS_EQUAL(12, number_of_hex_chars); + + number_of_hex_chars = char_str_to_hex_str("\nwuhuu", 6, hex_buf, true); + hex_buf[number_of_hex_chars] = '\0'; + STRCMP_EQUAL("A7775687575", hex_buf); + LONGS_EQUAL(11, number_of_hex_chars); + + // test giving a null pointer + number_of_hex_chars = char_str_to_hex_str(NULL, 4, hex_buf); + LONGS_EQUAL(0, number_of_hex_chars); + number_of_hex_chars = char_str_to_hex_str("1234", 4, NULL); + LONGS_EQUAL(0, number_of_hex_chars); +} + +void Test_util::test_util_convert_ipv6() +{ + // leading zeros omitted + char ipv6[64]; + strncpy(ipv6, "1.1.1.1.1.1.1.1.1.1.1.1.1.1.1.1", 64); + convert_ipv6(ipv6); + STRCMP_EQUAL("101:101:101:101:101:101:101:101", ipv6); + LONGS_EQUAL(31, strlen(ipv6)); + + // some omitted and some not so much + strncpy(ipv6, "255.1.120.2.244.12.55.45.201.110.11.2.233.154.85.96", 64); + convert_ipv6(ipv6); + STRCMP_EQUAL("FF01:7802:F40C:372D:C96E:B02:E99A:5560", ipv6); + LONGS_EQUAL(38, strlen(ipv6)); + + // test giving a null pointer + convert_ipv6(NULL); +} + +void Test_util::test_util_prefer_ipv6() +{ + char tt[20] = "62.241.198.246"; + char temp[64] = "2001:14B8:1000:000:000:000:000:002"; + + // not enough space to swap, arrays should stay the same + prefer_ipv6(tt, sizeof(tt), temp, sizeof(temp)); + STRCMP_EQUAL("62.241.198.246", tt); + STRCMP_EQUAL("2001:14B8:1000:000:000:000:000:002", temp); + + // should swap as first one was ip4 and later was ipv6 and enough space + char tt2[64] = "62.241.198.246"; + prefer_ipv6(tt2, sizeof(tt2), temp, sizeof(temp)); + STRCMP_EQUAL("62.241.198.246", temp); + STRCMP_EQUAL("2001:14B8:1000:000:000:000:000:002", tt2); +} + +void Test_util::test_util_separate_ip_addresses() +{ + char* s = (char*)malloc(128); + + char ip[64] = {0}; + char subnet[64] = {0}; + + strncpy(s, "32.1.20.187.1.112.139.245.251.136.232.110.123.51.230.138.0.1.2.3.4.5.6.7.8.9.10.11.12.13.14.15", 94); + separate_ip_addresses(s, ip, sizeof(ip), subnet, sizeof(subnet)); + STRCMP_EQUAL("2001:14BB:170:8BF5:FB88:E86E:7B33:E68A", ip); + STRCMP_EQUAL("001:203:405:607:809:A0B:C0D:E0F", subnet); + + strncpy(s, "32:1:20:187:1:112:139:245:251:136:232:110:123:51:230:138 0:1:2:3:4:5:6:7:8:9:10:11:12:13:14:15", 94); + separate_ip_addresses(s, ip, sizeof(ip), subnet, sizeof(subnet)); + STRCMP_EQUAL("32:1:20:187:1:112:139:245:251:136:232:110:123:51:230:138", ip); + STRCMP_EQUAL("0:1:2:3:4:5:6:7:8:9:10:11:12:13:14:15", subnet); + + ip[0] = '\0'; + subnet[0] = '\0'; + strncpy(s, "1.2.3.4\0", 8); + separate_ip_addresses(s, ip, sizeof(ip), subnet, sizeof(subnet)); + STRCMP_EQUAL("1.2.3.4", ip); + STRCMP_EQUAL("", subnet); + + ip[0] = '\0'; + subnet[0] = '\0'; + strncpy(s, "1.2.3.4.5.6.7.8\0", 16); + separate_ip_addresses(s, ip, sizeof(ip), subnet, sizeof(subnet)); + STRCMP_EQUAL("1.2.3.4", ip); + STRCMP_EQUAL("5.6.7.8", subnet); + + ip[0] = '\0'; + subnet[0] = '\0'; + strncpy(s, "1.2.3.4.5.6.7.8.9.10.11.12.13.14.15.16\0", 39); + separate_ip_addresses(s, ip, sizeof(ip), subnet, sizeof(subnet)); + STRCMP_EQUAL("102:304:506:708:90A:B0C:D0E:F10", ip); + STRCMP_EQUAL("", subnet); + + ip[0] = '\0'; + subnet[0] = '\0'; + strncpy(s, "32:1:20:187:1:112:139:245:251:136:232:110:123:51:230:138\0", 57); + separate_ip_addresses(s, ip, sizeof(ip), subnet, sizeof(subnet)); + STRCMP_EQUAL("32:1:20:187:1:112:139:245:251:136:232:110:123:51:230:138", ip); + STRCMP_EQUAL("", subnet); + + ip[0] = '\0'; + subnet[0] = '\0'; + strncpy(s, "1.2.3.4 32:1:20:187:1:112:139:245:251:136:232:110:123:51:230:138\0", 65); + separate_ip_addresses(s, ip, sizeof(ip), subnet, sizeof(subnet)); + STRCMP_EQUAL("1.2.3.4", ip); + STRCMP_EQUAL("32:1:20:187:1:112:139:245:251:136:232:110:123:51:230:138", subnet); + + ip[0] = '\0'; + subnet[0] = '\0'; + strncpy(s, "1.2.3.4 5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20\0", 51); + separate_ip_addresses(s, ip, sizeof(ip), subnet, sizeof(subnet)); + STRCMP_EQUAL("1.2.3.4", ip); + STRCMP_EQUAL("506:708:90A:B0C:D0E:F10:1112:1314", subnet); + STRCMP_EQUAL("1.2.3.4 5.6.7.8.9.10.11.12.13.14.15.16.17.18.19.20", s); + +} diff --git a/features/cellular/UNITTESTS/common/util/test_util.h b/features/cellular/UNITTESTS/common/util/test_util.h new file mode 100644 index 0000000000..1a343db256 --- /dev/null +++ b/features/cellular/UNITTESTS/common/util/test_util.h @@ -0,0 +1,39 @@ +/* + * 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. + */ +#ifndef TEST_UTIL_H +#define TEST_UTIL_H + +class Test_util +{ +public: + Test_util(); + + virtual ~Test_util(); + + void test_util_uint_to_binary_string(); + + void test_util_char_str_to_hex(); + + void test_util_convert_ipv6(); + + void test_util_prefer_ipv6(); + + void test_util_separate_ip_addresses(); +}; + +#endif // TEST_UTIL_H + diff --git a/features/cellular/UNITTESTS/common/util/utiltest.cpp b/features/cellular/UNITTESTS/common/util/utiltest.cpp new file mode 100644 index 0000000000..dff7b105ad --- /dev/null +++ b/features/cellular/UNITTESTS/common/util/utiltest.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2015, 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 "CppUTest/TestHarness.h" +#include "test_util.h" + +TEST_GROUP(util) +{ + Test_util* unit; + + void setup() + { + unit = new Test_util(); + } + + void teardown() + { + delete unit; + } +}; + +TEST(util, Create) +{ + CHECK(unit != NULL); +} + +TEST(util, test_util_uint_to_binary_string) +{ + unit->test_util_uint_to_binary_string(); +} + +TEST(util, char_str_to_hex) +{ + unit->test_util_char_str_to_hex(); +} + +TEST(util, convert_ipv6) +{ + unit->test_util_convert_ipv6(); +} + +TEST(util, prefer_ipv6) +{ + unit->test_util_prefer_ipv6(); +} + +TEST(util, separate_ip_addresses) +{ + unit->test_util_separate_ip_addresses(); +} diff --git a/features/cellular/UNITTESTS/makefile_defines.txt b/features/cellular/UNITTESTS/makefile_defines.txt new file mode 100755 index 0000000000..d11de61cfd --- /dev/null +++ b/features/cellular/UNITTESTS/makefile_defines.txt @@ -0,0 +1,32 @@ +#--- Inputs ----# +CPPUTEST_HOME = /usr +CPPUTEST_USE_EXTENSIONS = Y +CPPUTEST_USE_VPATH = Y +CPPUTEST_USE_GCOV = Y +CPPUTEST_USE_MEM_LEAK_DETECTION = N +CPP_PLATFORM = gcc +INCLUDE_DIRS =\ + .\ + ../../stubs\ + ../../target_h\ + ../../..\ + ../../../../../features \ + ../../../../../features/netsocket \ + ../../../../.. \ + ../../../../../rtos \ + ../../../../../rtos/TARGET_CORTEX \ + ../../../../../platform \ + ../../../../../hal \ + ../../../../../events \ + ../../../../../events/equeue \ + ../../../../../drivers \ + ../../../framework\ + ../../../framework/common\ + ../../../framework/AT\ + ../../../framework/API\ + /usr/include\ + $(CPPUTEST_HOME)/include\ + +CPPUTESTFLAGS = -D__thumb2__ -w -D__INLINE=__inline +CPPUTEST_CFLAGS += -std=gnu99 + diff --git a/features/cellular/UNITTESTS/run_tests b/features/cellular/UNITTESTS/run_tests new file mode 100755 index 0000000000..c8c81bb6aa --- /dev/null +++ b/features/cellular/UNITTESTS/run_tests @@ -0,0 +1,48 @@ +#!/bin/bash +echo +echo Build Cellular unit tests +echo + +#replace by empty string if no branch coverage is needed +#branch_cov="--rc lcov_branch_coverage=1" +branch_cov="" +#branch_data="--rc branch-coverage=1" +branch_data="--no-branch-coverage" + +# Remember to add new test folder to Makefile +make clean >/dev/null 2>&1 +make all + +echo +echo Create results +echo +mkdir results + +find ./ -name '*.xml' | xargs cp -t ./results/ + +echo +echo Create coverage document +echo +mkdir coverages +cd coverages + +lcov -q -d ../. -c -o app.info $branch_cov +lcov -q -r app.info "/test*" -o app.info $branch_cov +lcov -q -r app.info "/usr*" -o app.info $branch_cov +lcov -q -r app.info "/UNITTESTS/common*" -o app.info $branch_cov +lcov -q -r app.info "/UNITTESTS/*" -o app.info $branch_cov +lcov -q -r app.info "/UNITTESTS/stubs*" -o app.info $branch_cov +lcov -q -r app.info "/UNITTESTS/target_h*" -o app.info $branch_cov +lcov -q -r app.info "/mbed-client*" -o app.info $branch_cov +lcov -q -r app.info "/mbed-os/events*" -o app.info $branch_cov +lcov -q -r app.info "/mbed-os/features/netsocket*" -o app.info $branch_cov +lcov -q -r app.info "/mbed-os/platform*" -o app.info $branch_cov +genhtml $branch_data app.info +cd .. +echo +echo +echo +echo Have a nice bug hunt! +echo +echo +echo diff --git a/features/cellular/UNITTESTS/stubs/ATCmdParser.cpp b/features/cellular/UNITTESTS/stubs/ATCmdParser.cpp new file mode 100644 index 0000000000..8bee7b9d1f --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/ATCmdParser.cpp @@ -0,0 +1,420 @@ +/* + * Copyright (c) 2017, 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 "ATCmdParser.h" +#include "mbed_poll.h" +#include "mbed_debug.h" + +#ifdef LF +#undef LF +#define LF 10 +#else +#define LF 10 +#endif + +#ifdef CR +#undef CR +#define CR 13 +#else +#define CR 13 +#endif + +// getc/putc handling with timeouts +int ATCmdParser::putc(char c) +{ + pollfh fhs; + fhs.fh = _fh; + fhs.events = POLLOUT; + + int count = poll(&fhs, 1, _timeout); + if (count > 0 && (fhs.revents & POLLOUT)) { + return _fh->write(&c, 1) == 1 ? 0 : -1; + } else { + return -1; + } +} + +int ATCmdParser::getc() +{ + pollfh fhs; + fhs.fh = _fh; + fhs.events = POLLIN; + + int count = poll(&fhs, 1, _timeout); + if (count > 0 && (fhs.revents & POLLIN)) { + unsigned char ch; + return _fh->read(&ch, 1) == 1 ? ch : -1; + } else { + return -1; + } +} + +void ATCmdParser::flush() +{ + while (_fh->readable()) { + unsigned char ch; + _fh->read(&ch, 1); + } +} + + +// read/write handling with timeouts +int ATCmdParser::write(const char *data, int size) +{ + int i = 0; + for ( ; i < size; i++) { + if (putc(data[i]) < 0) { + return -1; + } + } + return i; +} + +int ATCmdParser::read(char *data, int size) +{ + int i = 0; + for ( ; i < size; i++) { + int c = getc(); + if (c < 0) { + return -1; + } + data[i] = c; + } + return i; +} + + +// printf/scanf handling +int ATCmdParser::vprintf(const char *format, va_list args) +{ + + if (vsprintf(_buffer, format, args) < 0) { + return false; + } + + int i = 0; + for ( ; _buffer[i]; i++) { + if (putc(_buffer[i]) < 0) { + return -1; + } + } + return i; +} + +int ATCmdParser::vscanf(const char *format, va_list args) +{ + // Since format is const, we need to copy it into our buffer to + // add the line's null terminator and clobber value-matches with asterisks. + // + // We just use the beginning of the buffer to avoid unnecessary allocations. + int i = 0; + int offset = 0; + + while (format[i]) { + if (format[i] == '%' && format[i+1] != '%' && format[i+1] != '*') { + _buffer[offset++] = '%'; + _buffer[offset++] = '*'; + i++; + } else { + _buffer[offset++] = format[i++]; + } + } + + // Scanf has very poor support for catching errors + // fortunately, we can abuse the %n specifier to determine + // if the entire string was matched. + _buffer[offset++] = '%'; + _buffer[offset++] = 'n'; + _buffer[offset++] = 0; + + // To workaround scanf's lack of error reporting, we actually + // make two passes. One checks the validity with the modified + // format string that only stores the matched characters (%n). + // The other reads in the actual matched values. + // + // We keep trying the match until we succeed or some other error + // derails us. + int j = 0; + + while (true) { + // Ran out of space + if (j+1 >= _buffer_size - offset) { + return false; + } + // Recieve next character + int c = getc(); + if (c < 0) { + return -1; + } + _buffer[offset + j++] = c; + _buffer[offset + j] = 0; + + // Check for match + int count = -1; + sscanf(_buffer+offset, _buffer, &count); + + // We only succeed if all characters in the response are matched + if (count == j) { + // Store the found results + vsscanf(_buffer+offset, format, args); + return j; + } + } +} + + +// Command parsing with line handling +bool ATCmdParser::vsend(const char *command, va_list args) +{ + // Create and send command + if (vsprintf(_buffer, command, args) < 0) { + return false; + } + + for (int i = 0; _buffer[i]; i++) { + if (putc(_buffer[i]) < 0) { + return false; + } + } + + // Finish with newline + for (size_t i = 0; _output_delimiter[i]; i++) { + if (putc(_output_delimiter[i]) < 0) { + return false; + } + } + + debug_if(_dbg_on, "AT> %s\n", _buffer); + return true; +} + +bool ATCmdParser::vrecv(const char *response, va_list args) +{ +restart: + _aborted = false; + // Iterate through each line in the expected response + while (response[0]) { + // Since response is const, we need to copy it into our buffer to + // add the line's null terminator and clobber value-matches with asterisks. + // + // We just use the beginning of the buffer to avoid unnecessary allocations. + int i = 0; + int offset = 0; + bool whole_line_wanted = false; + + while (response[i]) { + if (response[i] == '%' && response[i+1] != '%' && response[i+1] != '*') { + _buffer[offset++] = '%'; + _buffer[offset++] = '*'; + i++; + } else { + _buffer[offset++] = response[i++]; + // Find linebreaks, taking care not to be fooled if they're in a %[^\n] conversion specification + if (response[i - 1] == '\n' && !(i >= 3 && response[i-3] == '[' && response[i-2] == '^')) { + whole_line_wanted = true; + break; + } + } + } + + // Scanf has very poor support for catching errors + // fortunately, we can abuse the %n specifier to determine + // if the entire string was matched. + _buffer[offset++] = '%'; + _buffer[offset++] = 'n'; + _buffer[offset++] = 0; + + debug_if(_dbg_on, "AT? %s\n", _buffer); + // To workaround scanf's lack of error reporting, we actually + // make two passes. One checks the validity with the modified + // format string that only stores the matched characters (%n). + // The other reads in the actual matched values. + // + // We keep trying the match until we succeed or some other error + // derails us. + int j = 0; + + while (true) { + // Receive next character + int c = getc(); + if (c < 0) { + debug_if(_dbg_on, "AT(Timeout)\n"); + return false; + } + // Simplify newlines (borrowed from retarget.cpp) + if ((c == CR && _in_prev != LF) || + (c == LF && _in_prev != CR)) { + _in_prev = c; + c = '\n'; + } else if ((c == CR && _in_prev == LF) || + (c == LF && _in_prev == CR)) { + _in_prev = c; + // onto next character + continue; + } else { + _in_prev = c; + } + _buffer[offset + j++] = c; + _buffer[offset + j] = 0; + + // Check for oob data + for (struct oob *oob = _oobs; oob; oob = oob->next) { + if ((unsigned)j == oob->len && memcmp( + oob->prefix, _buffer+offset, oob->len) == 0) { + debug_if(_dbg_on, "AT! %s\n", oob->prefix); + oob->cb(); + + if (_aborted) { + debug_if(_dbg_on, "AT(Aborted)\n"); + return false; + } + // oob may have corrupted non-reentrant buffer, + // so we need to set it up again + goto restart; + } + } + + // Check for match + int count = -1; + if (whole_line_wanted && c != '\n') { + // Don't attempt scanning until we get delimiter if they included it in format + // This allows recv("Foo: %s\n") to work, and not match with just the first character of a string + // (scanf does not itself match whitespace in its format string, so \n is not significant to it) + } else { + sscanf(_buffer+offset, _buffer, &count); + } + + // We only succeed if all characters in the response are matched + if (count == j) { + debug_if(_dbg_on, "AT= %s\n", _buffer+offset); + // Reuse the front end of the buffer + memcpy(_buffer, response, i); + _buffer[i] = 0; + + // Store the found results + vsscanf(_buffer+offset, _buffer, args); + + // Jump to next line and continue parsing + response += i; + break; + } + + // Clear the buffer when we hit a newline or ran out of space + // running out of space usually means we ran into binary data + if (c == '\n' || j+1 >= _buffer_size - offset) { + debug_if(_dbg_on, "AT< %s", _buffer+offset); + j = 0; + } + } + } + + return true; +} + +// Mapping to vararg functions +int ATCmdParser::printf(const char *format, ...) +{ + va_list args; + va_start(args, format); + int res = vprintf(format, args); + va_end(args); + return res; +} + +int ATCmdParser::scanf(const char *format, ...) +{ + va_list args; + va_start(args, format); + int res = vscanf(format, args); + va_end(args); + return res; +} + +bool ATCmdParser::send(const char *command, ...) +{ + va_list args; + va_start(args, command); + bool res = vsend(command, args); + va_end(args); + return res; +} + +bool ATCmdParser::recv(const char *response, ...) +{ + va_list args; + va_start(args, response); + bool res = vrecv(response, args); + va_end(args); + return res; +} + +// oob registration +void ATCmdParser::oob(const char *prefix, Callback cb) +{ + struct oob *oob = new struct oob; + oob->len = strlen(prefix); + oob->prefix = prefix; + oob->cb = cb; + oob->next = _oobs; + _oobs = oob; +} + +void ATCmdParser::abort() +{ + _aborted = true; +} + +bool ATCmdParser::process_oob() +{ + if (!_fh->readable()) { + return false; + } + + int i = 0; + while (true) { + // Receive next character + int c = getc(); + if (c < 0) { + return false; + } + _buffer[i++] = c; + _buffer[i] = 0; + + // Check for oob data + struct oob *oob = _oobs; + while (oob) { + if (i == (int)oob->len && memcmp( + oob->prefix, _buffer, oob->len) == 0) { + debug_if(_dbg_on, "AT! %s\r\n", oob->prefix); + oob->cb(); + return true; + } + oob = oob->next; + } + + // Clear the buffer when we hit a newline or ran out of space + // running out of space usually means we ran into binary data + if (i+1 >= _buffer_size || + strcmp(&_buffer[i-_output_delim_size], _output_delimiter) == 0) { + + debug_if(_dbg_on, "AT< %s", _buffer); + i = 0; + } + } +} + + diff --git a/features/cellular/UNITTESTS/stubs/ATHandler_stub.cpp b/features/cellular/UNITTESTS/stubs/ATHandler_stub.cpp new file mode 100644 index 0000000000..33489c1338 --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/ATHandler_stub.cpp @@ -0,0 +1,227 @@ +/* + * Copyright (c) 2017, 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 +#include "nsapi_types.h" +#include "ATHandler.h" +#include "EventQueue.h" +#include "ATHandler_stub.h" + +using namespace mbed; +using namespace events; + +#include "CellularLog.h" + +const int DEFAULT_AT_TIMEOUT = 1000; // at default timeout in milliseconds + +nsapi_error_t ATHandler_stub::nsapi_error_value = 0; +uint8_t ATHandler_stub::nsapi_error_ok_counter = 0; +int ATHandler_stub::int_value = -1; +ssize_t ATHandler_stub::ssize_value = 0; +char* ATHandler_stub::read_string_value = NULL; +size_t ATHandler_stub::size_value = 0; +size_t ATHandler_stub::return_given_size = false; +bool ATHandler_stub::bool_value = false; +uint8_t ATHandler_stub::uint8_value = 0; +FileHandle_stub *ATHandler_stub::fh_value = NULL; +device_err_t ATHandler_stub::device_err_value; +Callback ATHandler_stub::callback = NULL; +uint8_t ATHandler_stub::resp_info_true_counter = false; + +ATHandler::ATHandler(FileHandle *fh, EventQueue &queue, int timeout, const char *output_delimiter) : + _nextATHandler(0), + _fileHandle(fh), + _queue(queue) +{ +} + +void ATHandler::enable_debug(bool enable) +{ +} + +ATHandler::~ATHandler() +{ +} + +void ATHandler::inc_ref_count() +{ +} + +void ATHandler::dec_ref_count() +{ +} + +int ATHandler::get_ref_count() +{ + return ATHandler_stub::int_value; +} + +FileHandle *ATHandler::get_file_handle() +{ + return ATHandler_stub::fh_value; +} + +void ATHandler::set_file_handle(FileHandle *fh) +{ +} + +void ATHandler::set_urc_handler(const char *urc, mbed::Callback cb) +{ + ATHandler_stub::callback = cb; +} + +nsapi_error_t ATHandler::get_last_error() const +{ + if (ATHandler_stub::nsapi_error_ok_counter) { + ATHandler_stub::nsapi_error_ok_counter--; + return NSAPI_ERROR_OK; + } + return ATHandler_stub::nsapi_error_value; +} + +void ATHandler::lock() +{ +} + +void ATHandler::unlock() +{ +} + +nsapi_error_t ATHandler::unlock_return_error() +{ + return ATHandler_stub::nsapi_error_value; +} + +void ATHandler::set_at_timeout(uint32_t timeout_milliseconds, bool default_timeout) +{ +} + +void ATHandler::restore_at_timeout() +{ +} + +void ATHandler::process_oob() +{ +} + +void ATHandler::clear_error() +{ +} + +void ATHandler::skip_param(uint32_t count) { + +} + +void ATHandler::skip_param(ssize_t len, uint32_t count) +{ +} + +ssize_t ATHandler::read_bytes(uint8_t *buf, size_t len) +{ + return ATHandler_stub::ssize_value; +} + +ssize_t ATHandler::read_string(char *buf, size_t size, bool read_even_stop_tag) +{ + if (ATHandler_stub::read_string_value && ATHandler_stub::ssize_value >= 0) { + memcpy(buf, ATHandler_stub::read_string_value, ATHandler_stub::ssize_value); + } + return ATHandler_stub::ssize_value; +} + +int ATHandler::read_int() +{ + return ATHandler_stub::int_value; +} + +void ATHandler::set_delimiter(char delimiter) +{ +} + +void ATHandler::set_default_delimiter() +{ +} + +void ATHandler::set_stop_tag(const char *stop_tag_seq) +{ +} + +int ATHandler::get_3gpp_error() +{ + return ATHandler_stub::int_value; +} + +void ATHandler::resp_start(const char *prefix, bool stop) +{ +} + +bool ATHandler::info_resp() +{ + if (ATHandler_stub::resp_info_true_counter) { + ATHandler_stub::resp_info_true_counter--; + return true; + } + return ATHandler_stub::bool_value; +} + +bool ATHandler::info_elem(char start_tag) +{ + return ATHandler_stub::bool_value; +} + +bool ATHandler::consume_to_stop_tag() +{ + return ATHandler_stub::bool_value; +} + +void ATHandler::resp_stop() +{ +} + +void ATHandler::cmd_start(const char* cmd) +{ +} + +void ATHandler::write_int(int param) +{ +} + +void ATHandler::write_string(const char* param, bool useQuotations) +{ +} + +size_t ATHandler::write_bytes(const uint8_t* param, size_t len) +{ + if (ATHandler_stub::return_given_size) { + return len; + } + return ATHandler_stub::size_value; +} + +void ATHandler::cmd_stop() +{ +} + +device_err_t ATHandler::get_last_device_error() const +{ + return ATHandler_stub::device_err_value; +} + +void ATHandler::flush() +{ + +} diff --git a/features/cellular/UNITTESTS/stubs/ATHandler_stub.h b/features/cellular/UNITTESTS/stubs/ATHandler_stub.h new file mode 100644 index 0000000000..72fd269583 --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/ATHandler_stub.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017, 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 "stdint.h" +#include "stdbool.h" +#include +#include "nsapi_types.h" +#include "ATHandler.h" +#include "FileHandle_stub.h" +#include "Callback.h" + + +namespace ATHandler_stub { + extern nsapi_error_t nsapi_error_value; + extern uint8_t nsapi_error_ok_counter; + extern int int_value; + extern ssize_t ssize_value; + extern char* read_string_value; + extern size_t size_value; + extern size_t return_given_size; + extern bool bool_value; + extern uint8_t resp_info_true_counter; + extern uint8_t uint8_value; + extern mbed::FileHandle_stub *fh_value; + extern mbed::device_err_t device_err_value; + extern mbed::Callback callback; +} diff --git a/features/cellular/UNITTESTS/stubs/AT_CellularBase_stub.cpp b/features/cellular/UNITTESTS/stubs/AT_CellularBase_stub.cpp new file mode 100644 index 0000000000..0a6daf2d00 --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/AT_CellularBase_stub.cpp @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017, 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 "nsapi_types.h" +#include "AT_CellularBase.h" +#include "AT_CellularBase_stub.h" + + +using namespace mbed; + +ATHandler *AT_CellularBase_stub::handler_value = NULL; +ATHandler *AT_CellularBase_stub::handler_at_constructor_value = NULL; +device_err_t AT_CellularBase_stub::device_err_value; + +AT_CellularBase::AT_CellularBase(ATHandler& at) : _at(at) +{ + AT_CellularBase_stub::handler_at_constructor_value = &_at; +} + +ATHandler& AT_CellularBase::get_at_handler() +{ + return *AT_CellularBase_stub::handler_value; +} + +device_err_t AT_CellularBase::get_device_error() const +{ + return AT_CellularBase_stub::device_err_value; +} + diff --git a/features/cellular/UNITTESTS/stubs/AT_CellularBase_stub.h b/features/cellular/UNITTESTS/stubs/AT_CellularBase_stub.h new file mode 100644 index 0000000000..dd57c8a547 --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/AT_CellularBase_stub.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) 2017, 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 "ATHandler.h" + +namespace AT_CellularBase_stub { + extern mbed::ATHandler *handler_value; + extern mbed::ATHandler *handler_at_constructor_value; + extern mbed::device_err_t device_err_value; +} diff --git a/features/cellular/UNITTESTS/stubs/AT_CellularDevice_stub.cpp b/features/cellular/UNITTESTS/stubs/AT_CellularDevice_stub.cpp new file mode 100644 index 0000000000..7051910e0c --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/AT_CellularDevice_stub.cpp @@ -0,0 +1,91 @@ +/* + * Copyright (c) 2017, 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 "AT_CellularDevice.h" + +AT_CellularDevice::AT_CellularDevice(EventQueue &queue) : + _atHandlers(0), _network(0), _sms(0), _sim(0), _power(0), _multiplexer(0), _information(0), _queue(queue) +{ +} + +AT_CellularDevice::~AT_CellularDevice() +{ +} + +ATHandler* AT_CellularDevice::get_at_handler(FileHandle *fileHandle) +{ + return NULL; +} + +void AT_CellularDevice::release_at_handler(ATHandler* at_handler) +{ + +} + +CellularNetwork *AT_CellularDevice::open_network(FileHandle *fh) +{ + return NULL; +} + +CellularSMS *AT_CellularDevice::open_sms(FileHandle *fh) +{ + return NULL; +} + +CellularSIM *AT_CellularDevice::open_sim(FileHandle *fh) +{ + return NULL; +} + +CellularPower *AT_CellularDevice::open_power(FileHandle *fh) +{ + return NULL; +} + +CellularMultiplexer *AT_CellularDevice::open_multiplexer(FileHandle *fh) +{ + return NULL; +} + +CellularInformation *AT_CellularDevice::open_information(FileHandle *fh) +{ + return NULL; +} + +void AT_CellularDevice::close_network() +{ +} + +void AT_CellularDevice::close_sms() +{ +} + +void AT_CellularDevice::close_power() +{ +} + +void AT_CellularDevice::close_sim() +{ +} + +void AT_CellularDevice::close_multiplexer() +{ +} + +void AT_CellularDevice::close_information() +{ +} diff --git a/features/cellular/UNITTESTS/stubs/AT_CellularInformation_stub.cpp b/features/cellular/UNITTESTS/stubs/AT_CellularInformation_stub.cpp new file mode 100644 index 0000000000..a9cf1b5b0b --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/AT_CellularInformation_stub.cpp @@ -0,0 +1,44 @@ +/* + * 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 "AT_CellularInformation.h" +#include "nsapi_types.h" + +using namespace mbed; + +AT_CellularInformation::AT_CellularInformation(ATHandler &at) : AT_CellularBase(at) +{ +} + +AT_CellularInformation::~AT_CellularInformation() +{ +} + +nsapi_error_t AT_CellularInformation::get_manufacturer(char *buf, size_t buf_size) +{ + return 0; +} + +nsapi_error_t AT_CellularInformation::get_model(char *buf, size_t buf_size) +{ + return 0; +} + +nsapi_error_t AT_CellularInformation::get_revision(char *buf, size_t buf_size) +{ + return 0; +} diff --git a/features/cellular/UNITTESTS/stubs/AT_CellularMultiplexer_stub.cpp b/features/cellular/UNITTESTS/stubs/AT_CellularMultiplexer_stub.cpp new file mode 100644 index 0000000000..c397d5fb38 --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/AT_CellularMultiplexer_stub.cpp @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2017, 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 "AT_CellularMultiplexer.h" +#include "CellularLog.h" +#include "nsapi_types.h" + +using namespace mbed; + +AT_CellularMultiplexer::AT_CellularMultiplexer(ATHandler &at) : AT_CellularBase(at) +{ +} + +AT_CellularMultiplexer::~AT_CellularMultiplexer() +{ +} + +nsapi_error_t AT_CellularMultiplexer::multiplexer_mode_start() +{ + return 0; +} diff --git a/features/cellular/UNITTESTS/stubs/AT_CellularNetwork_stub.cpp b/features/cellular/UNITTESTS/stubs/AT_CellularNetwork_stub.cpp new file mode 100644 index 0000000000..c18cd32b4c --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/AT_CellularNetwork_stub.cpp @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2017, 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 "AT_CellularNetwork.h" +#include "CellularNetwork.h" +#include "CellularUtil.h" +#include "CellularLog.h" +#include "FileHandle.h" +#include "nsapi_types.h" + +using namespace mbed; +using namespace mbed_cellular_util; + +AT_CellularNetwork::AT_CellularNetwork(ATHandler &atHandler) : AT_CellularBase(atHandler) +{ +} + +AT_CellularNetwork::~AT_CellularNetwork() +{ +} + +nsapi_error_t AT_CellularNetwork::set_credentials(const char *apn, + const char *username, const char *password) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularNetwork::set_credentials(const char *apn, + AuthenticationType type, const char *username, const char *password) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularNetwork::connect(const char *apn, + const char *username, const char *password) +{ + return connect(); +} + +nsapi_error_t AT_CellularNetwork::connect() +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularNetwork::open_data_channel() +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularNetwork::disconnect() +{ + return NSAPI_ERROR_OK; +} + +void AT_CellularNetwork::attach(Callback status_cb) +{ +} + +nsapi_connection_status_t AT_CellularNetwork::get_connection_status() const +{ + return NSAPI_STATUS_LOCAL_UP; +} + +nsapi_error_t AT_CellularNetwork::set_blocking(bool blocking) +{ + return NSAPI_ERROR_OK;; +} + +nsapi_error_t AT_CellularNetwork::set_context_to_be_activated() +{ + return NSAPI_ERROR_OK; +} + +//bool AT_CellularNetwork::set_new_context(nsapi_ip_stack_t stack, int cid) +//{ +// return false; +//} + +//bool AT_CellularNetwork::get_context(nsapi_ip_stack_t requested_stack) +//{ +// return false; +//} + +nsapi_ip_stack_t AT_CellularNetwork::string_to_stack_type(const char* pdp_type) +{ + return IPV4_STACK; +} + +nsapi_error_t AT_CellularNetwork::set_registration_urc(bool urc_on) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularNetwork::set_registration(const char *plmn) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularNetwork::get_registration_status(RegistrationType type, RegistrationStatus &status) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularNetwork::get_cell_id(int &cell_id) +{ + return NSAPI_ERROR_OK; +} + +bool AT_CellularNetwork::has_registration(RegistrationType reg_type) +{ + return false; +} + +nsapi_error_t AT_CellularNetwork::set_attach(int timeout) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularNetwork::get_attach(AttachStatus &status) +{ + return NSAPI_ERROR_OK; +} + + +nsapi_error_t AT_CellularNetwork::get_apn_backoff_timer(int &backoffTime) +{ + return NSAPI_ERROR_OK; +} + +NetworkStack *AT_CellularNetwork::get_stack() +{ + return NULL; +} + +const char *AT_CellularNetwork::get_ip_address() +{ + return NULL; +} + +nsapi_error_t AT_CellularNetwork::set_stack_type(nsapi_ip_stack_t stack_type) +{ + return NSAPI_ERROR_OK; +} + +nsapi_ip_stack_t AT_CellularNetwork::get_stack_type() +{ + return IPV4_STACK; +} + +bool AT_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack) +{ + return false; +} + +void AT_CellularNetwork::urc_no_carrier() +{ + +} + +nsapi_error_t AT_CellularNetwork::set_access_technology_impl(operator_t::RadioAccessTechnology opsAct) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularNetwork::set_access_technology(operator_t::RadioAccessTechnology opAct) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularNetwork::scan_plmn(operList_t &operators, int &opsCount) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularNetwork::set_ciot_optimization_config(Supported_UE_Opt supported_opt, + Preferred_UE_Opt preferred_opt) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularNetwork::get_ciot_optimization_config(Supported_UE_Opt& supported_opt, + Preferred_UE_Opt& preferred_opt) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularNetwork::get_rate_control( + CellularNetwork::RateControlExceptionReports &reports, + CellularNetwork::RateControlUplinkTimeUnit &timeUnit, int &uplinkRate) +{ + return NSAPI_ERROR_OK; +} + + +nsapi_error_t AT_CellularNetwork::get_pdpcontext_params(pdpContextList_t& params_list) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularNetwork::get_extended_signal_quality(int &rxlev, int &ber, int &rscp, int &ecno, int &rsrq, int &rsrp) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularNetwork::get_signal_quality(int &rssi, int &ber) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularNetwork::get_operator_params(int &format, operator_t &operator_params) +{ + return NSAPI_ERROR_OK; +} + +int AT_CellularNetwork::get_3gpp_error() +{ + return 0; +} + diff --git a/features/cellular/UNITTESTS/stubs/AT_CellularPower_stub.cpp b/features/cellular/UNITTESTS/stubs/AT_CellularPower_stub.cpp new file mode 100644 index 0000000000..2a131ec2fb --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/AT_CellularPower_stub.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2017, 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 "AT_CellularPower.h" +#include "CellularUtil.h" +#include "CellularLog.h" + +using namespace mbed_cellular_util; +using namespace mbed; + +AT_CellularPower::AT_CellularPower(ATHandler &at) : AT_CellularBase(at) +{ +} + +AT_CellularPower::~AT_CellularPower() +{ +} + +nsapi_error_t AT_CellularPower::on() +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularPower::off() +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularPower::set_at_mode() +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularPower::set_power_level(int func_level) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularPower::reset() +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularPower::opt_power_save_mode(int periodic_time, int active_time) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularPower::opt_receive_period(int mode, EDRXAccessTechnology act_type, uint8_t edrx_value) +{ + return NSAPI_ERROR_OK; +} diff --git a/features/cellular/UNITTESTS/stubs/AT_CellularSIM_stub.cpp b/features/cellular/UNITTESTS/stubs/AT_CellularSIM_stub.cpp new file mode 100644 index 0000000000..85a7f04a64 --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/AT_CellularSIM_stub.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) 2017, 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 "AT_CellularSIM.h" +#include "CellularLog.h" + +using namespace mbed; + +AT_CellularSIM::AT_CellularSIM(ATHandler &at) : AT_CellularBase(at) +{ +} + +AT_CellularSIM::~AT_CellularSIM() +{ +} + +nsapi_error_t AT_CellularSIM::get_sim_state(SimState &state) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularSIM::set_pin(const char *sim_pin) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularSIM::change_pin(const char *sim_pin, const char *new_pin) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularSIM::set_pin_query(const char *sim_pin, bool query_pin) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularSIM::get_imsi(char* imsi) +{ + return NSAPI_ERROR_OK; +} diff --git a/features/cellular/UNITTESTS/stubs/AT_CellularSMS_stub.cpp b/features/cellular/UNITTESTS/stubs/AT_CellularSMS_stub.cpp new file mode 100644 index 0000000000..5f9461c1a3 --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/AT_CellularSMS_stub.cpp @@ -0,0 +1,190 @@ +/* + * Copyright (c) 2017, 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 +#include "AT_CellularSMS.h" +#include "CellularLog.h" + +using namespace mbed; + +#define CTRL_Z "\x1a" +#define ESC "\x1b" + +const int SMS_STATUS_SIZE = 12 + 1; +const int FIRST_OCTET_DELIVER_SUBMIT = 17; +const int TP_VALIDITY_PERIOD_24_HOURS = 167; +const int TP_PROTOCOL_IDENTIFIER = 0; +const int SMS_DATA_CODING_SCHEME = 0; + +const uint16_t SMS_MAX_8BIT_CONCATENATED_SINGLE_SMS_SIZE = 134; +const uint16_t SMS_MAX_GSM7_CONCATENATED_SINGLE_SMS_SIZE = 153; + + +AT_CellularSMS::AT_CellularSMS(ATHandler &at) : AT_CellularBase(at), _cb(0), _mode(CellularSMSMmodeText), + _use_8bit_encoding(false), _sim_wait_time(0), _sms_message_ref_number(1), _sms_info(NULL) +{ +} + +AT_CellularSMS::~AT_CellularSMS() +{ +} + +void AT_CellularSMS::cmt_urc() +{ +} + +void AT_CellularSMS::cmti_urc() +{ +} + +nsapi_error_t AT_CellularSMS::set_cnmi() +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularSMS::set_cmgf(int msg_format) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularSMS::set_csmp(int fo, int vp, int pid, int dcs) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularSMS::set_csdh(int show_header) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularSMS::initialize(CellularSMSMmode mode) +{ + return NSAPI_ERROR_OK; +} + +void AT_CellularSMS::set_extra_sim_wait_time(int sim_wait_time) +{ +} + +char* AT_CellularSMS::create_pdu(const char* phone_number, const char* message, uint8_t message_length, uint8_t msg_parts, + uint8_t msg_part_number, uint8_t& header_size) +{ + return NULL; +} + +nsapi_size_or_error_t AT_CellularSMS::send_sms(const char* phone_number, const char* message, int msg_len) +{ + return NSAPI_ERROR_OK; +} + +void AT_CellularSMS::set_sms_callback(Callback func) +{ +} + +nsapi_error_t AT_CellularSMS::set_cpms(const char *memr, const char *memw, const char *mems) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularSMS::set_csca(const char *sca, int type) +{ + return NSAPI_ERROR_OK; +} + +nsapi_size_or_error_t AT_CellularSMS::set_cscs(const char *chr_set) +{ + return NSAPI_ERROR_OK; +} + +//nsapi_error_t AT_CellularSMS::set_csms(int msg_service) +//{ +// return NSAPI_ERROR_OK; +//} + +nsapi_error_t AT_CellularSMS::delete_sms(sms_info_t* sms) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularSMS::delete_all_messages() +{ + return NSAPI_ERROR_OK; +} + +nsapi_size_or_error_t AT_CellularSMS::read_sms_from_index(int msg_index, char* buf, uint16_t len, char* phone_num, char* time_stamp) +{ + return NSAPI_ERROR_OK; +} + +// read msg in PDU mode +nsapi_size_or_error_t AT_CellularSMS::read_sms(sms_info_t* sms, char* buf, char* phone_num, char* time_stamp) +{ + return NSAPI_ERROR_OK; +} + +nsapi_size_or_error_t AT_CellularSMS::get_sms(char* buf, uint16_t len, char* phone_num, uint16_t phone_len, + char* time_stamp, uint16_t time_len, int *buf_size) +{ + return NSAPI_ERROR_OK; +} + +nsapi_size_or_error_t AT_CellularSMS::get_data_from_pdu(const char* pdu, sms_info_t *info, int *part_number, char *phone_number, char *msg) +{ + return NSAPI_ERROR_OK; +} + + // read params from User DEfined Header +int AT_CellularSMS::read_udh_from_pdu(const char* pdu, sms_info_t *info, int &part_number, int &padding_bits) +{ + return 0; +} + +nsapi_size_or_error_t AT_CellularSMS::read_pdu_payload(const char* pdu, int msg_len, int scheme, char *msg, int padding_bits) +{ + return NSAPI_ERROR_OK; +} + +void AT_CellularSMS::free_linked_list() +{ +} + +void AT_CellularSMS::add_info(sms_info_t* info, int index, int part_number) +{ +} + +// reads all the messages to the linked list AT_CellularSMS::_sms_info +nsapi_error_t AT_CellularSMS::list_messages() +{ + return NSAPI_ERROR_OK; +} + +AT_CellularSMS::sms_info_t* AT_CellularSMS::get_oldest_sms_index() +{ + return NULL; +} + +// if time_string_1 is greater (more fresh date) then return 1, same 0, smaller -1. Error -2 +int AT_CellularSMS::compare_time_strings(const char* time_string_1, const char* time_string_2) +{ + return 0; +} + +bool AT_CellularSMS::create_time(const char* time_string, time_t* time) +{ + return 0; +} + diff --git a/features/cellular/UNITTESTS/stubs/AT_CellularStack_stub.cpp b/features/cellular/UNITTESTS/stubs/AT_CellularStack_stub.cpp new file mode 100644 index 0000000000..640d8c1b68 --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/AT_CellularStack_stub.cpp @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2017, 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 "AT_CellularStack.h" +#include "CellularUtil.h" +#include "CellularLog.h" + +using namespace mbed_cellular_util; + +AT_CellularStack::AT_CellularStack(ATHandler &atHandler, int cid, nsapi_ip_stack_t stack_type) : _at(atHandler), _socket(NULL), _cid(cid), _stack_type(stack_type) +{ +} + +AT_CellularStack::~AT_CellularStack() +{ +} + +const char *AT_CellularStack::get_ip_address() +{ + return NULL; +} + +nsapi_error_t AT_CellularStack::socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularStack::socket_close(nsapi_socket_t handle) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularStack::socket_bind(nsapi_socket_t handle, const SocketAddress &addr) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularStack::socket_listen(nsapi_socket_t handle, int backlog) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularStack::socket_connect(nsapi_socket_t handle, const SocketAddress &addr) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularStack::socket_accept(void *server, void **socket, SocketAddress *addr) +{ + return NSAPI_ERROR_OK; +} + +nsapi_size_or_error_t AT_CellularStack::socket_send(nsapi_socket_t handle, const void *data, unsigned size) +{ + return NSAPI_ERROR_OK; +} + +nsapi_size_or_error_t AT_CellularStack::socket_sendto(nsapi_socket_t handle, const SocketAddress &addr, const void *data, unsigned size) +{ + return NSAPI_ERROR_OK; +} + +nsapi_size_or_error_t AT_CellularStack::socket_recv(nsapi_socket_t handle, void *data, unsigned size) +{ + return NSAPI_ERROR_OK; +} + +nsapi_size_or_error_t AT_CellularStack::socket_recvfrom(nsapi_socket_t handle, SocketAddress *addr, void *buffer, unsigned size) +{ + return NSAPI_ERROR_OK; +} + +void AT_CellularStack::socket_attach(nsapi_socket_t handle, void (*callback)(void *), void *data) +{ +} + diff --git a/features/cellular/UNITTESTS/stubs/CellularUtil_stub.cpp b/features/cellular/UNITTESTS/stubs/CellularUtil_stub.cpp new file mode 100644 index 0000000000..d6c9a1658f --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/CellularUtil_stub.cpp @@ -0,0 +1,113 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "CellularUtil.h" +#include +#include +#include + +namespace mbed_cellular_util { + +#define MAX_STRING_LEN 200 + +void str_copy_skip_char(char *dest, uint16_t dest_size, const char *src, char c) +{ +} + +void str_remove_char(char *src, char c) +{ +} + +void uint_to_binary_str(uint32_t num, char* str, uint8_t str_size, uint8_t bit_cnt) +{ +} + +// converts the given str to hex string to buf +uint16_t char_str_to_hex(const char* str, uint16_t len, char *buf, bool omit_leading_zero) +{ + return 0; +} + +void convert_ipv6(char* ip) +{ + +} + +char* find_dot_number(char* str, int dot_number) +{ + return NULL; +} + +void separate_ip4like_addresses(char* orig, char* ip, size_t ip_size, char* ip2, size_t ip2_size) +{ +} + +void separate_ip_addresses(char* orig, char* ip, size_t ip_size, char* ip2, size_t ip2_size) +{ +} + +void prefer_ipv6(char* ip, size_t ip_size, char* ip2, size_t ip2_size) +{ +} + +void int_to_hex_str(uint8_t num, char* buf) +{ + buf[0] = '0'; + buf[1] = '2'; +} + +int hex_str_to_int(const char *hex_string, int hex_string_length) +{ + return 0; +} + +int hex_str_to_char_str(const char* str, uint16_t len, char *buf) +{ + return 0; +} + +void uint_to_binary_str(uint32_t num, char* str, int str_size, int bit_cnt) +{ + +} + +int char_str_to_hex_str(const char* str, uint16_t len, char *buf, bool omit_leading_zero) +{ + //The code is dependent on this, so this is easiest just to put here + if (!str || !buf) { + return 0; + } + + char *ptr = buf; + int i=0; + while (i < len) { + if (omit_leading_zero == true && i == 0 && !(str[i]>>4 & 0x0F)) { + *ptr++ = hex_values[(str[i]) & 0x0F]; + } else { + *ptr++ = hex_values[((str[i])>>4) & 0x0F]; + *ptr++ = hex_values[(str[i]) & 0x0F]; + } + i++; + } + return ptr-buf; +} + +uint16_t get_dynamic_ip_port() +{ + return 0; +} + +} // namespace mbed_cellular_util diff --git a/features/cellular/UNITTESTS/stubs/EventQueue_stub.cpp b/features/cellular/UNITTESTS/stubs/EventQueue_stub.cpp new file mode 100644 index 0000000000..235e69b6c5 --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/EventQueue_stub.cpp @@ -0,0 +1,50 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "EventQueue.h" +#include "Callback.h" + +using namespace mbed; + +namespace events { + +EventQueue::EventQueue(unsigned event_size, unsigned char *event_pointer) { +} + +EventQueue::~EventQueue() { +} + +void EventQueue::dispatch(int ms) { +} + +void EventQueue::break_dispatch() { +} + +unsigned EventQueue::tick() { + return 0; +} + +void EventQueue::cancel(int id) { +} + +void EventQueue::background(Callback update) { +} + +void EventQueue::chain(EventQueue *target) { +} + +} diff --git a/features/cellular/UNITTESTS/stubs/FileHandle_stub.cpp b/features/cellular/UNITTESTS/stubs/FileHandle_stub.cpp new file mode 100644 index 0000000000..d14d52b6fb --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/FileHandle_stub.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "FileHandle_stub.h" + +namespace mbed { + +off_t FileHandle::size() +{ + return 0; +} + +std::FILE *fdopen(FileHandle *fh, const char *mode) +{ + return NULL; +} + +} diff --git a/features/cellular/UNITTESTS/stubs/FileHandle_stub.h b/features/cellular/UNITTESTS/stubs/FileHandle_stub.h new file mode 100644 index 0000000000..6097f90280 --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/FileHandle_stub.h @@ -0,0 +1,78 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __FILE_HANDLE_STUB_H__ +#define __FILE_HANDLE_STUB_H__ + +#include "FileHandle.h" + + +namespace mbed { + +static uint8_t filehandle_stub_short_value_counter = 0; +static char *filehandle_stub_table = NULL; +static uint8_t filehandle_stub_table_pos = 0; + +class FileHandle_stub : public FileHandle +{ +public: + size_t size_value; + + FileHandle_stub() {size_value = 0;} + + virtual ssize_t read(void *buffer, size_t size){ + if (filehandle_stub_table) { + ssize_t ret = strlen(filehandle_stub_table) - filehandle_stub_table_pos; + if (size < ret) { + ret = size; + } + memcpy(buffer, filehandle_stub_table, ret); + filehandle_stub_table_pos += ret; + return ret; + } + return 0; + } + + virtual ssize_t write(const void *buffer, size_t size){ + if( size_value ) { + size_value--; + return size; + } + return 0; + } + + virtual off_t seek(off_t offset, int whence = SEEK_SET){return 0;} + + virtual int close(){} + + virtual short poll(short events) const{ + if (filehandle_stub_short_value_counter) { + filehandle_stub_short_value_counter--; + return short_value; + } + return 0; + } + + virtual void sigio(Callback func){func();} + + short short_value; +}; + +} + +#endif + + diff --git a/features/cellular/UNITTESTS/stubs/NetworkInterface_stub.cpp b/features/cellular/UNITTESTS/stubs/NetworkInterface_stub.cpp new file mode 100644 index 0000000000..fb1ad4dcbd --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/NetworkInterface_stub.cpp @@ -0,0 +1,79 @@ +/* + * Copyright (c) 2015, 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 "netsocket/NetworkInterface.h" +#include "netsocket/NetworkStack.h" +#include + + +// Default network-interface state +const char *NetworkInterface::get_mac_address() +{ + return 0; +} + +const char *NetworkInterface::get_ip_address() +{ + return 0; +} + +const char *NetworkInterface::get_netmask() +{ + return 0; +} + +const char *NetworkInterface::get_gateway() +{ + return 0; +} + +nsapi_error_t NetworkInterface::set_network(const char *ip_address, const char *netmask, const char *gateway) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t NetworkInterface::set_dhcp(bool dhcp) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +// DNS operations go through the underlying stack by default +nsapi_error_t NetworkInterface::gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t NetworkInterface::add_dns_server(const SocketAddress &address) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +void NetworkInterface::attach(mbed::Callback status_cb) +{ + +} + +nsapi_connection_status_t NetworkInterface::get_connection_status() const +{ + return NSAPI_STATUS_LOCAL_UP; +} + +nsapi_error_t NetworkInterface::set_blocking(bool blocking) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + diff --git a/features/cellular/UNITTESTS/stubs/NetworkStack_stub.cpp b/features/cellular/UNITTESTS/stubs/NetworkStack_stub.cpp new file mode 100644 index 0000000000..0cbc1abb65 --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/NetworkStack_stub.cpp @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2015, 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 "NetworkStack.h" +#include "nsapi_dns.h" +#include "mbed.h" +#include "stddef.h" +#include + + +// Default NetworkStack operations +nsapi_error_t NetworkStack::gethostbyname(const char *name, SocketAddress *address, nsapi_version_t version) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t NetworkStack::add_dns_server(const SocketAddress &address) +{ + return NSAPI_ERROR_OK; +} + +nsapi_error_t NetworkStack::setstackopt(int level, int optname, const void *optval, unsigned optlen) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t NetworkStack::getstackopt(int level, int optname, void *optval, unsigned *optlen) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t NetworkStack::setsockopt(void *handle, int level, int optname, const void *optval, unsigned optlen) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t NetworkStack::getsockopt(void *handle, int level, int optname, void *optval, unsigned *optlen) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +// Conversion function for network stacks +NetworkStack *nsapi_create_stack(nsapi_stack_t *stack) +{ + return NULL; +} + +NetworkStack *nsapi_create_stack(NetworkStack *stack) +{ + return NULL; +} + diff --git a/features/cellular/UNITTESTS/stubs/Semaphore_stub.cpp b/features/cellular/UNITTESTS/stubs/Semaphore_stub.cpp new file mode 100644 index 0000000000..3782b77f8c --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/Semaphore_stub.cpp @@ -0,0 +1,57 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Semaphore.h" + +namespace rtos { + +Semaphore::Semaphore(int32_t count) +{ + +} + +Semaphore::Semaphore(int32_t count, uint16_t max_count) +{ + +} + +void Semaphore::constructor(int32_t count, uint16_t max_count) +{ + +} + +int32_t Semaphore::wait(uint32_t millisec) +{ + return 0; +} + +int32_t Semaphore::wait_until(uint64_t millisec) +{ + return 0; +} + +osStatus Semaphore::release(void) +{ + return 0; +} + +Semaphore::~Semaphore() +{ + +} + +} diff --git a/features/cellular/UNITTESTS/stubs/SocketAddress_stub.cpp b/features/cellular/UNITTESTS/stubs/SocketAddress_stub.cpp new file mode 100644 index 0000000000..3bc18d6c43 --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/SocketAddress_stub.cpp @@ -0,0 +1,133 @@ +/* + * Copyright (c) 2015, 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 "SocketAddress.h" +#include "NetworkInterface.h" +#include "NetworkStack.h" +#include +#include "mbed.h" + + +static bool ipv4_is_valid(const char *addr) +{ + return false; +} + +static bool ipv6_is_valid(const char *addr) +{ + return false; +} + +static void ipv4_from_address(uint8_t *bytes, const char *addr) +{ + +} + +static int ipv6_scan_chunk(uint16_t *shorts, const char *chunk) +{ + return 0; +} + +static void ipv6_from_address(uint8_t *bytes, const char *addr) +{ + +} + +static void ipv4_to_address(char *addr, const uint8_t *bytes) +{ + +} + +static void ipv6_to_address(char *addr, const uint8_t *bytes) +{ +} + + +SocketAddress::SocketAddress(nsapi_addr_t addr, uint16_t port) +{ +} + +SocketAddress::SocketAddress(const char *addr, uint16_t port) +{ +} + +SocketAddress::SocketAddress(const void *bytes, nsapi_version_t version, uint16_t port) +{ +} + +SocketAddress::SocketAddress(const SocketAddress &addr) +{ +} + +bool SocketAddress::set_ip_address(const char *addr) +{ + return false; +} + +void SocketAddress::set_ip_bytes(const void *bytes, nsapi_version_t version) +{ +} + +void SocketAddress::set_addr(nsapi_addr_t addr) +{ +} + +void SocketAddress::set_port(uint16_t port) +{ +} + +const char *SocketAddress::get_ip_address() const +{ + return NULL; +} + +const void *SocketAddress::get_ip_bytes() const +{ + return NULL; +} + +nsapi_version_t SocketAddress::get_ip_version() const +{ + nsapi_version_t ver; + return ver; +} + +nsapi_addr_t SocketAddress::get_addr() const +{ + nsapi_addr_t addr; + return _addr; +} + +uint16_t SocketAddress::get_port() const +{ + return 0; +} + +SocketAddress::operator bool() const +{ + return false; +} + +bool operator==(const SocketAddress &a, const SocketAddress &b) +{ + return false; +} + +bool operator!=(const SocketAddress &a, const SocketAddress &b) +{ + return false; +} diff --git a/features/cellular/UNITTESTS/stubs/Timer_stub.cpp b/features/cellular/UNITTESTS/stubs/Timer_stub.cpp new file mode 100644 index 0000000000..db3ba4cd95 --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/Timer_stub.cpp @@ -0,0 +1,63 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "Timer.h" +#include "Timer_stub.h" + +namespace mbed { + +Timer::Timer() { +} + +Timer::Timer(const ticker_data_t *data) { +} + +Timer::~Timer() { +} + +void Timer::start() { +} + +void Timer::stop() {; +} + +int Timer::read_us() { + return 0; +} + +float Timer::read() { + return 0; +} + +int Timer::read_ms() { + timer_stub_value += timer_stub_step; + return timer_stub_value; +} + +us_timestamp_t Timer::read_high_resolution_us() { + return 0; +} + +void Timer::reset() +{ +} + +Timer::operator float() { + return 0; +} + +} // namespace mbed diff --git a/features/cellular/UNITTESTS/stubs/Timer_stub.h b/features/cellular/UNITTESTS/stubs/Timer_stub.h new file mode 100644 index 0000000000..699fdd0c53 --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/Timer_stub.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef TIMER_STUB_H +#define TIMER_STUB_H + + +static uint16_t timer_stub_value = 0; +static uint16_t timer_stub_step = 20; + +#endif diff --git a/features/cellular/UNITTESTS/stubs/equeue_stub.c b/features/cellular/UNITTESTS/stubs/equeue_stub.c new file mode 100644 index 0000000000..cc5c267df1 --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/equeue_stub.c @@ -0,0 +1,104 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "equeue.h" + +int equeue_create(equeue_t *queue, size_t size) +{ + return 0; +} + +int equeue_create_inplace(equeue_t *queue, size_t size, void *buffer) +{ + return 0; +} + +void equeue_destroy(equeue_t *queue) +{ + +} + +void equeue_dispatch(equeue_t *queue, int ms) +{ + +} + +void equeue_break(equeue_t *queue) +{ + +} + +int equeue_call(equeue_t *queue, void (*cb)(void *), void *data) +{ + return 0; +} + +int equeue_call_in(equeue_t *queue, int ms, void (*cb)(void *), void *data) +{ + return 0; +} + +int equeue_call_every(equeue_t *queue, int ms, void (*cb)(void *), void *data) +{ + return 0; +} + +void *equeue_alloc(equeue_t *queue, size_t size) +{ + return NULL; +} + +void equeue_dealloc(equeue_t *queue, void *event) +{ + +} + +void equeue_event_delay(void *event, int ms) +{ + +} + +void equeue_event_period(void *event, int ms) +{ + +} + +void equeue_event_dtor(void *event, void (*dtor)(void *)) +{ + +} + +int equeue_post(equeue_t *queue, void (*cb)(void *), void *event) +{ + return 0; +} + +void equeue_cancel(equeue_t *queue, int id) +{ + +} + +void equeue_background(equeue_t *queue, + void (*update)(void *timer, int ms), void *timer) +{ + +} + +void equeue_chain(equeue_t *queue, equeue_t *target) +{ + +} diff --git a/features/cellular/UNITTESTS/stubs/mbed_assert_stub.cpp b/features/cellular/UNITTESTS/stubs/mbed_assert_stub.cpp new file mode 100644 index 0000000000..341881a7f5 --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/mbed_assert_stub.cpp @@ -0,0 +1,24 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbed_assert.h" + +void mbed_assert_internal(const char *expr, const char *file, int line) +{ + +} + diff --git a/features/cellular/UNITTESTS/stubs/mbed_poll_stub.cpp b/features/cellular/UNITTESTS/stubs/mbed_poll_stub.cpp new file mode 100644 index 0000000000..1914399d2a --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/mbed_poll_stub.cpp @@ -0,0 +1,32 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbed_poll.h" +#include "mbed_poll_stub.h" + +int mbed_poll_stub::revents_value = POLLOUT; +int mbed_poll_stub::int_value = 0; + +namespace mbed { + +int poll(pollfh fhs[], unsigned nfhs, int timeout) +{ + fhs->revents = mbed_poll_stub::revents_value; + return mbed_poll_stub::int_value; +} + +} diff --git a/features/cellular/UNITTESTS/stubs/mbed_poll_stub.h b/features/cellular/UNITTESTS/stubs/mbed_poll_stub.h new file mode 100644 index 0000000000..4d92b60b8e --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/mbed_poll_stub.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __MBED_POLL_STUB_H__ +#define __MBED_POLL_STUB_H__ + +#include + +namespace mbed_poll_stub { + extern int revents_value; + extern int int_value; +} + +#endif diff --git a/features/cellular/UNITTESTS/stubs/mbed_wait_api_stub.cpp b/features/cellular/UNITTESTS/stubs/mbed_wait_api_stub.cpp new file mode 100644 index 0000000000..5e4873be38 --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/mbed_wait_api_stub.cpp @@ -0,0 +1,27 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "mbed_wait_api.h" + +void wait(float s) { +} + +void wait_ms(int ms) { +} + +void wait_us(int us) { +} diff --git a/features/cellular/UNITTESTS/stubs/us_ticker_stub.cpp b/features/cellular/UNITTESTS/stubs/us_ticker_stub.cpp new file mode 100644 index 0000000000..3727e1f618 --- /dev/null +++ b/features/cellular/UNITTESTS/stubs/us_ticker_stub.cpp @@ -0,0 +1,54 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +#include "stdlib.h" +#include "us_ticker_api.h" + +const ticker_data_t* get_us_ticker_data(void) +{ + return NULL; +} + +void us_ticker_irq_handler(void) +{ +} + +void us_ticker_init(void) +{ +} + +uint32_t us_ticker_read(void) +{ + return 0; +} + +void us_ticker_set_interrupt(timestamp_t timestamp) +{ +} + +void us_ticker_disable_interrupt(void) +{ +} + +void us_ticker_clear_interrupt(void) +{ +} + +void us_ticker_fire_interrupt(void) +{ +} diff --git a/features/cellular/UNITTESTS/target_h/ATCmdParser.h b/features/cellular/UNITTESTS/target_h/ATCmdParser.h new file mode 100644 index 0000000000..9e56281702 --- /dev/null +++ b/features/cellular/UNITTESTS/target_h/ATCmdParser.h @@ -0,0 +1,34 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __AT_CMD_PARSER_H__ +#define __AT_CMD_PARSER_H__ + +#include "mbed.h" +#include +#include "FileHandle.h" + +class ATCmdParser +{ +public: + ATCmdParser(mbed::FileHandle *fh, const char *output_delimiter = "\r", + int buffer_size = 256, int timeout = 8000, bool debug = false){} + + ~ATCmdParser(){} +}; + +#endif //__AT_CMD_PARSER_H__ + diff --git a/features/cellular/UNITTESTS/target_h/PeripheralNames.h b/features/cellular/UNITTESTS/target_h/PeripheralNames.h new file mode 100644 index 0000000000..a431b392e7 --- /dev/null +++ b/features/cellular/UNITTESTS/target_h/PeripheralNames.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ diff --git a/features/cellular/UNITTESTS/target_h/PinNames.h b/features/cellular/UNITTESTS/target_h/PinNames.h new file mode 100644 index 0000000000..9f92be6f1d --- /dev/null +++ b/features/cellular/UNITTESTS/target_h/PinNames.h @@ -0,0 +1,27 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __PINNAMES_H__ +#define __PINNAMES_H__ + + + +typedef enum { + +} PinName; + +#endif + diff --git a/features/cellular/UNITTESTS/target_h/arm_math.h b/features/cellular/UNITTESTS/target_h/arm_math.h new file mode 100644 index 0000000000..a431b392e7 --- /dev/null +++ b/features/cellular/UNITTESTS/target_h/arm_math.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ diff --git a/features/cellular/UNITTESTS/target_h/cmsis.h b/features/cellular/UNITTESTS/target_h/cmsis.h new file mode 100644 index 0000000000..a431b392e7 --- /dev/null +++ b/features/cellular/UNITTESTS/target_h/cmsis.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ diff --git a/features/cellular/UNITTESTS/target_h/cmsis_compiler.h b/features/cellular/UNITTESTS/target_h/cmsis_compiler.h new file mode 100644 index 0000000000..a431b392e7 --- /dev/null +++ b/features/cellular/UNITTESTS/target_h/cmsis_compiler.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ diff --git a/features/cellular/UNITTESTS/target_h/cmsis_os2.h b/features/cellular/UNITTESTS/target_h/cmsis_os2.h new file mode 100644 index 0000000000..e1e28f797c --- /dev/null +++ b/features/cellular/UNITTESTS/target_h/cmsis_os2.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __CMSIS_OS2_H__ +#define __CMSIS_OS2_H__ + +//If conflicts, then remove these, copied from cmsis_os.h +typedef int32_t osStatus; + +#define osOK 0 + + + +//These are from cmsis_os2.h +typedef void *osSemaphoreId_t; + +typedef struct { + const char *name; ///< name of the semaphore + uint32_t attr_bits; ///< attribute bits + void *cb_mem; ///< memory for control block + uint32_t cb_size; ///< size of provided memory for control block +} osSemaphoreAttr_t; + +#define osWaitForever 0xFFFFFFFFU + + +#endif diff --git a/features/cellular/UNITTESTS/target_h/device.h b/features/cellular/UNITTESTS/target_h/device.h new file mode 100644 index 0000000000..a431b392e7 --- /dev/null +++ b/features/cellular/UNITTESTS/target_h/device.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ diff --git a/features/cellular/UNITTESTS/target_h/mbed.h b/features/cellular/UNITTESTS/target_h/mbed.h new file mode 100644 index 0000000000..e401087fec --- /dev/null +++ b/features/cellular/UNITTESTS/target_h/mbed.h @@ -0,0 +1,24 @@ +/* + * 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. + */ +#ifndef MBED_H +#define MBED_H + +#include +#include + +#endif // MBED_H + diff --git a/features/cellular/UNITTESTS/target_h/mbed_retarget.h b/features/cellular/UNITTESTS/target_h/mbed_retarget.h new file mode 100644 index 0000000000..80906a65f5 --- /dev/null +++ b/features/cellular/UNITTESTS/target_h/mbed_retarget.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define EAGAIN 11 diff --git a/features/cellular/UNITTESTS/target_h/mbed_rtos1_types.h b/features/cellular/UNITTESTS/target_h/mbed_rtos1_types.h new file mode 100644 index 0000000000..a431b392e7 --- /dev/null +++ b/features/cellular/UNITTESTS/target_h/mbed_rtos1_types.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ diff --git a/features/cellular/UNITTESTS/target_h/mbed_rtos_storage.h b/features/cellular/UNITTESTS/target_h/mbed_rtos_storage.h new file mode 100644 index 0000000000..34a08b0ae0 --- /dev/null +++ b/features/cellular/UNITTESTS/target_h/mbed_rtos_storage.h @@ -0,0 +1,22 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "cmsis_os2.h" +#include "rtx_os.h" +#include "rtx_lib.h" + +typedef os_semaphore_t mbed_rtos_storage_semaphore_t; diff --git a/features/cellular/UNITTESTS/target_h/mbed_rtx.h b/features/cellular/UNITTESTS/target_h/mbed_rtx.h new file mode 100644 index 0000000000..a431b392e7 --- /dev/null +++ b/features/cellular/UNITTESTS/target_h/mbed_rtx.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ diff --git a/features/cellular/UNITTESTS/target_h/nsapi_ppp.h b/features/cellular/UNITTESTS/target_h/nsapi_ppp.h new file mode 100644 index 0000000000..a431b392e7 --- /dev/null +++ b/features/cellular/UNITTESTS/target_h/nsapi_ppp.h @@ -0,0 +1,16 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ diff --git a/features/cellular/UNITTESTS/target_h/platform/mbed_retarget.h b/features/cellular/UNITTESTS/target_h/platform/mbed_retarget.h new file mode 100644 index 0000000000..80906a65f5 --- /dev/null +++ b/features/cellular/UNITTESTS/target_h/platform/mbed_retarget.h @@ -0,0 +1,18 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define EAGAIN 11 diff --git a/features/cellular/UNITTESTS/target_h/rtx_lib.h b/features/cellular/UNITTESTS/target_h/rtx_lib.h new file mode 100644 index 0000000000..23982a329b --- /dev/null +++ b/features/cellular/UNITTESTS/target_h/rtx_lib.h @@ -0,0 +1,24 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#ifndef __RTX_LIB_H__ +#define __RTX_LIB_H__ + +#include "rtx_os.h" + +#define os_semaphore_t osRtxSemaphore_t + +#endif diff --git a/features/cellular/UNITTESTS/target_h/rtx_os.h b/features/cellular/UNITTESTS/target_h/rtx_os.h new file mode 100644 index 0000000000..3f47ec8cf0 --- /dev/null +++ b/features/cellular/UNITTESTS/target_h/rtx_os.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef __RTX_OS__ +#define __RTX_OS__ + +#include "inttypes.h" + +typedef struct osRtxSemaphore_s { + uint8_t id; ///< Object Identifier + uint8_t state; ///< Object State + uint8_t flags; ///< Object Flags + uint8_t reserved; + const char *name; ///< Object Name + uint16_t tokens; ///< Current number of tokens + uint16_t max_tokens; ///< Maximum number of tokens +} osRtxSemaphore_t; + +#endif diff --git a/features/cellular/UNITTESTS/target_h/sys/syslimits.h b/features/cellular/UNITTESTS/target_h/sys/syslimits.h new file mode 100644 index 0000000000..bd27d352d5 --- /dev/null +++ b/features/cellular/UNITTESTS/target_h/sys/syslimits.h @@ -0,0 +1,17 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#define NAME_MAX 255 diff --git a/features/cellular/easy_cellular/CellularConnectionFSM.cpp b/features/cellular/easy_cellular/CellularConnectionFSM.cpp new file mode 100644 index 0000000000..2735349bbe --- /dev/null +++ b/features/cellular/easy_cellular/CellularConnectionFSM.cpp @@ -0,0 +1,572 @@ +/* + * Copyright (c) 2017, 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 "CellularConnectionFSM.h" + +#ifdef CELLULAR_DEVICE + +#ifndef MBED_TRACE_MAX_LEVEL +#define MBED_TRACE_MAX_LEVEL TRACE_LEVEL_INFO +#endif +#include "CellularLog.h" + +// timeout to wait for AT responses +#define TIMEOUT_POWER_ON (1*1000) +#define TIMEOUT_SIM_PIN (1*1000) +#define TIMEOUT_NETWORK (10*1000) +#define TIMEOUT_REGISTRATION (180*1000) + +// maximum time when retrying network register, attach and connect in seconds ( 20minutes ) +#define TIMEOUT_NETWORK_MAX (20*60) + +#define RETRY_COUNT_DEFAULT 3 + +namespace mbed { + +CellularConnectionFSM::CellularConnectionFSM() : + _serial(0), _state(STATE_INIT), _next_state(_state), _status_callback(0), _network(0), _power(0), _sim(0), + _queue(8 * EVENTS_EVENT_SIZE), _queue_thread(0), _retry_count(0), _state_retry_count(0), _at_queue(8 * EVENTS_EVENT_SIZE) +{ + memset(_sim_pin, 0, sizeof(_sim_pin)); +#if MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY == 0 + _start_time = 0; +#else + _start_time = rand() % (MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY); +#endif // MBED_CONF_CELLULAR_RANDOM_MAX_START_DELAY + + // set initial retry values in seconds + _retry_timeout_array[0] = 1; + _retry_timeout_array[1] = 2; + _retry_timeout_array[2] = 4; + _retry_timeout_array[3] = 16; + _retry_timeout_array[4] = 32; + _retry_timeout_array[5] = 60; + _retry_timeout_array[6] = 120; + _retry_timeout_array[7] = 360; + _retry_timeout_array[8] = 600; + _retry_timeout_array[9] = TIMEOUT_NETWORK_MAX; + _retry_array_length = MAX_RETRY_ARRAY_SIZE; + + _cellularDevice = new CELLULAR_DEVICE(_at_queue); +} + +CellularConnectionFSM::~CellularConnectionFSM() +{ + stop(); +} + +nsapi_error_t CellularConnectionFSM::init() +{ + _power = _cellularDevice->open_power(_serial); + if (!_power) { + stop(); + return NSAPI_ERROR_NO_MEMORY; + } + _network = _cellularDevice->open_network(_serial); + if (!_network) { + stop(); + return NSAPI_ERROR_NO_MEMORY; + } + + _sim = _cellularDevice->open_sim(_serial); + if (!_sim) { + stop(); + return NSAPI_ERROR_NO_MEMORY; + } + + _at_queue.chain(&_queue); + + tr_info("init done..."); + return NSAPI_ERROR_OK; +} + +bool CellularConnectionFSM::open_power(FileHandle *fh) +{ + if (!_power) { + _power = _cellularDevice->open_power(fh); + if (!_power) { + return false; + } + } + nsapi_error_t err = _power->on(); + if (err != NSAPI_ERROR_OK && err != NSAPI_ERROR_UNSUPPORTED) { + tr_warn("Cellular start failed. Power off/on."); + err = _power->off(); + if (err != NSAPI_ERROR_OK && err != NSAPI_ERROR_UNSUPPORTED) { + tr_error("Cellular power down failed!"); + } + return false; + } + return true; +} + +void CellularConnectionFSM::set_sim_pin(const char * sim_pin) +{ + strncpy(_sim_pin, sim_pin, sizeof(_sim_pin)); +} + +bool CellularConnectionFSM::open_sim() +{ + CellularSIM::SimState state = CellularSIM::SimStateUnknown; + // wait until SIM is readable + // here you could add wait(secs) if you know start delay of your SIM + while (_sim->get_sim_state(state) != NSAPI_ERROR_OK || state == CellularSIM::SimStateUnknown) { + tr_info("Waiting for SIM (state %d)...", state); + return false; + } + tr_info("Initial SIM state: %d", state); + + if (strlen(_sim_pin)) { + nsapi_error_t err; + if (state == CellularSIM::SimStatePinNeeded) { + tr_info("SIM pin required, entering pin: %s", _sim_pin); + err = _sim->set_pin(_sim_pin); + if (err) { + tr_error("SIM pin set failed with: %d, bailing out...", err); + return false; + } + // here you could add wait(secs) if you know delay of changing PIN on your SIM + for (int i = 0; i < MAX_SIM_READY_WAITING_TIME; i++) { + if (_sim->get_sim_state(state) == NSAPI_ERROR_OK && state == CellularSIM::SimStateReady) { + break; + } + tr_info("SIM state: %d", state); + return false; + } + } + } else { + tr_info("No SIM pin provided."); + } + + return state == CellularSIM::SimStateReady; +} + +void CellularConnectionFSM::device_ready() +{ + CellularInformation *info = _cellularDevice->open_information(_serial); + char device_info_buf[2048]; // may be up to 2048 according to 3GPP + + if (info->get_manufacturer(device_info_buf, sizeof(device_info_buf)) == NSAPI_ERROR_OK) { + tr_info("Cellular device manufacturer: %s", device_info_buf); + } + if (info->get_model(device_info_buf, sizeof(device_info_buf)) == NSAPI_ERROR_OK) { + tr_info("Cellular device model: %s", device_info_buf); + } + if (info->get_revision(device_info_buf, sizeof(device_info_buf)) == NSAPI_ERROR_OK) { + tr_info("Cellular device revision: %s", device_info_buf); + } +} + +bool CellularConnectionFSM::set_network_registration(char *plmn) +{ + if (_network->set_registration(plmn) != NSAPI_ERROR_OK) { + tr_error("Failed to set network registration."); + return false; + } + return true; +} + +bool CellularConnectionFSM::get_network_registration(CellularNetwork::RegistrationType type, + CellularNetwork::RegistrationStatus &status, bool &is_registered) +{ + is_registered = false; + bool is_roaming = false; + nsapi_error_t err = _network->get_registration_status(type, status); + if (err != NSAPI_ERROR_OK) { + if (err != NSAPI_ERROR_UNSUPPORTED) { + tr_warn("Get network registration failed (type %d)!", type); + } + return false; + } + switch (status) { + case CellularNetwork::RegisteredRoaming: + is_roaming = true; + // fall-through + case CellularNetwork::RegisteredHomeNetwork: + is_registered = true; + break; + case CellularNetwork::RegisteredSMSOnlyRoaming: + is_roaming = true; + // fall-through + case CellularNetwork::RegisteredSMSOnlyHome: + tr_warn("SMS only network registration!"); + break; + case CellularNetwork::RegisteredCSFBNotPreferredRoaming: + is_roaming = true; + // fall-through + case CellularNetwork::RegisteredCSFBNotPreferredHome: + tr_warn("Not preferred network registration!"); + break; + case CellularNetwork::AttachedEmergencyOnly: + tr_warn("Emergency only network registration!"); + break; + case CellularNetwork::RegistrationDenied: + case CellularNetwork::NotRegistered: + case CellularNetwork::Unknown: + case CellularNetwork::SearchingNetwork: + default: + break; + } + + if (is_roaming) { + tr_warn("Roaming cellular network!"); + } + + return true; +} + +bool CellularConnectionFSM::get_attach_network(CellularNetwork::AttachStatus &status) +{ + nsapi_error_t err = _network->get_attach(status); + if (err != NSAPI_ERROR_OK) { + return false; + } + return true; +} + +bool CellularConnectionFSM::set_attach_network() +{ + nsapi_error_t attach_err = _network->set_attach(); + if (attach_err != NSAPI_ERROR_OK) { + return false; + } + return true; +} + +void CellularConnectionFSM::report_failure(const char* msg) +{ + tr_error("Cellular network failed: %s", msg); + if (_status_callback) { + _status_callback(_state, _next_state); + } +} + +nsapi_error_t CellularConnectionFSM::continue_to_state(CellularState state) +{ + if (state < _state) { + _state = state; + } + if (!_queue.call_in(0, callback(this, &CellularConnectionFSM::event))) { + stop(); + return NSAPI_ERROR_NO_MEMORY; + } + + return NSAPI_ERROR_OK; +} + +void CellularConnectionFSM::event() +{ + nsapi_error_t err; + int event_timeout = -1; + + switch (_state) { + case STATE_INIT: + event_timeout = _start_time; + tr_info("INIT state, waiting %d ms before POWER state)", _start_time); + _next_state = STATE_POWER_ON; + break; + case STATE_POWER_ON: + _cellularDevice->set_timeout(TIMEOUT_POWER_ON); + tr_info("Cellular power ON (timeout %d ms)", TIMEOUT_POWER_ON); + if (open_power(_serial)) { + _next_state = STATE_DEVICE_READY; + _retry_count = 0; + } else { + if (++_retry_count <= RETRY_COUNT_DEFAULT) { + tr_warn("Power ON retry %d", _retry_count); + event_timeout = 3 * 1000; + } else { + report_failure("Power"); + return; + } + } + break; + case STATE_DEVICE_READY: + _cellularDevice->set_timeout(TIMEOUT_POWER_ON); + if (_power->set_at_mode() == NSAPI_ERROR_OK) { + tr_info("Cellular device ready"); + _next_state = STATE_SIM_PIN; + _retry_count = 0; + device_ready(); + } else { + tr_info("Waiting for cellular device (retry %d/%d, timeout %d ms)", _retry_count, RETRY_COUNT_DEFAULT, + TIMEOUT_POWER_ON); + if (_retry_count++ <= RETRY_COUNT_DEFAULT) { + event_timeout = 3 * 1000; + } else { + report_failure("Power"); + return; + } + } + break; + case STATE_SIM_PIN: + _cellularDevice->set_timeout(TIMEOUT_SIM_PIN); + tr_info("Start cellular (timeout %d ms)", TIMEOUT_SIM_PIN); + if (open_sim()) { + _next_state = STATE_REGISTERING_NETWORK; + _retry_count = 0; + _state_retry_count = 0; + tr_info("Check for network registration"); + } else { + if (_retry_count++ <= RETRY_COUNT_DEFAULT) { + tr_warn("Waiting for SIM %d/%d", _retry_count, RETRY_COUNT_DEFAULT); + event_timeout = 3 * 1000; + } else { + report_failure("Entering SIM PIN"); + return; + } + } + break; + case STATE_REGISTERING_NETWORK: + _cellularDevice->set_timeout(TIMEOUT_NETWORK); + CellularNetwork::RegistrationStatus status; + bool is_registered; + _next_state = STATE_REGISTER_NETWORK; + for (int type = 0; type < CellularNetwork::C_MAX; type++) { + if (get_network_registration((CellularNetwork::RegistrationType) type, status, is_registered)) { + tr_debug("get_network_registration: type=%d, status=%d", type, status); + if (is_registered) { + tr_info("Registered to cellular network (type %d, status %d)", type, status); + _next_state = STATE_ATTACHING_NETWORK; + _retry_count = 0; + _state_retry_count = 0; + event_timeout = 0; + tr_info("Check cellular network attach state"); + break; + } else { + if (_retry_count < 180) { + event_timeout = 1000; + _next_state = STATE_REGISTERING_NETWORK; + tr_info("Waiting for registration %d/180 (type %d, status %d)", _retry_count, type, status); + } else { + tr_info("Start cellular registration"); + _next_state = STATE_REGISTER_NETWORK; + _retry_count = 0; + break; + } + } + } + } + + if (_next_state == STATE_REGISTERING_NETWORK) { + _retry_count++; + } + break; + case STATE_REGISTER_NETWORK: + _cellularDevice->set_timeout(TIMEOUT_REGISTRATION); + tr_info("Register to cellular network (timeout %d ms)", TIMEOUT_REGISTRATION); + if (set_network_registration()) { + _next_state = STATE_REGISTERING_NETWORK; + _retry_count = 0; + if (_state_retry_count > RETRY_COUNT_DEFAULT) { + report_failure("Registration retry"); + return; + } + _state_retry_count++; + } else { + if (_retry_count < _retry_array_length) { + event_timeout = _retry_timeout_array[_retry_count] * 1000; + _retry_count++; + } else { + report_failure("Registration"); + return; + } + } + break; + case STATE_ATTACHING_NETWORK: + _cellularDevice->set_timeout(TIMEOUT_NETWORK); + CellularNetwork::AttachStatus attach_status; + if (get_attach_network(attach_status)) { + if (attach_status == CellularNetwork::Attached) { + _next_state = STATE_CONNECT_NETWORK; + _retry_count = 0; + } else { + _next_state = STATE_ATTACH_NETWORK; + _retry_count = 0; + } + } else { + if (_retry_count++ <= RETRY_COUNT_DEFAULT) { + event_timeout = 1 * 1000; + } else { + report_failure("Attaching"); + return; + } + } + break; + case STATE_ATTACH_NETWORK: + _cellularDevice->set_timeout(TIMEOUT_NETWORK); + tr_info("Attach to cellular network (timeout %d ms)", TIMEOUT_NETWORK); + if (set_attach_network()) { + _next_state = STATE_ATTACHING_NETWORK; + _retry_count = 0; + if (_state_retry_count >= RETRY_COUNT_DEFAULT) { + report_failure("Attach retry"); + return; + } + _state_retry_count++; + tr_info("Cellular network attaching"); + } else { + if (_retry_count < _retry_array_length) { + event_timeout = _retry_timeout_array[_retry_count] * 1000; + _retry_count++; + } else { + report_failure("Attach"); + return; + } + } + break; + case STATE_CONNECT_NETWORK: + _cellularDevice->set_timeout(TIMEOUT_NETWORK); + tr_info("Connect to cellular network (timeout %d ms)", TIMEOUT_NETWORK); + err = _network->connect(); + if (!err) { + _next_state = STATE_CONNECTED; + } else { + if (_retry_count < _retry_array_length) { + event_timeout = _retry_timeout_array[_retry_count] * 1000; + _retry_count++; + } else { + report_failure("Network Connect"); + return; + } + } + break; + case STATE_CONNECTED: + _cellularDevice->set_timeout(TIMEOUT_NETWORK); + tr_debug("Cellular ready! (timeout %d ms)", TIMEOUT_NETWORK); + if (_status_callback) { + if (!_status_callback(_state, _next_state)) { + return; + } + } + break; + default: + MBED_ASSERT(0); + break; + } + + if (_next_state != _state || event_timeout >= 0) { + if (_next_state != _state) { // state exit condition + tr_info("Cellular state from %d to %d", _state, _next_state); + if (_status_callback) { + if (!_status_callback(_state, _next_state)) { + return; + } + } + } else { + if (event_timeout == 0) { + static int retry_count = 0; + if (++retry_count <= 3) { + tr_info("Cellular event retry %d", retry_count); + } else { + report_failure("Cellular connection failed!"); + return; + } + } else { + tr_info("Cellular event in %d milliseconds", event_timeout); + } + } + _state = _next_state; + if (event_timeout == -1) { + event_timeout = 0; + } + if (!_queue.call_in(event_timeout, callback(this, &CellularConnectionFSM::event))) { + report_failure("Cellular event failure!"); + return; + } + } +} + +nsapi_error_t CellularConnectionFSM::start_dispatch() +{ + tr_info("CellularConnectionUtil::start"); + tr_info("Create cellular thread"); + + MBED_ASSERT(!_queue_thread); + + _queue_thread = new rtos::Thread; + if (!_queue_thread) { + stop(); + return NSAPI_ERROR_NO_MEMORY; + } + if (_queue_thread->start(callback(&_queue, &events::EventQueue::dispatch_forever)) != osOK) { + stop(); + return NSAPI_ERROR_NO_MEMORY; + } + + tr_info("CellularConnectionUtil::started"); + return NSAPI_ERROR_OK; +} + +void CellularConnectionFSM::stop() +{ + tr_info("CellularConnectionUtil::stop"); + _cellularDevice->close_power(); + _cellularDevice->close_network(); + if (_queue_thread) { + _queue_thread->terminate(); + _queue_thread = NULL; + } +} + +void CellularConnectionFSM::set_serial(UARTSerial *serial) +{ + _serial = serial; +} + +void CellularConnectionFSM::set_callback(mbed::Callback status_callback) +{ + _status_callback = status_callback; +} + +events::EventQueue *CellularConnectionFSM::get_queue() +{ + return &_queue; +} + +CellularNetwork* CellularConnectionFSM::get_network() +{ + return _network; +} + +CellularDevice* CellularConnectionFSM::get_device() +{ + return _cellularDevice; +} + +CellularSIM* CellularConnectionFSM::get_sim() +{ + return _sim; +} + +NetworkStack *CellularConnectionFSM::get_stack() +{ + return _cellularDevice->get_stack(); +} + +void CellularConnectionFSM::set_retry_timeout_array(uint16_t timeout[], int array_len) +{ + _retry_array_length = array_len > MAX_RETRY_ARRAY_SIZE ? MAX_RETRY_ARRAY_SIZE : array_len; + + for (int i = 0; i < _retry_array_length; i++) { + _retry_timeout_array[i] = timeout[i]; + } +} + +} // namespace + +#endif // CELLULAR_DEVICE diff --git a/features/cellular/easy_cellular/CellularConnectionFSM.h b/features/cellular/easy_cellular/CellularConnectionFSM.h new file mode 100644 index 0000000000..8df675cb5f --- /dev/null +++ b/features/cellular/easy_cellular/CellularConnectionFSM.h @@ -0,0 +1,176 @@ +/* + * Copyright (c) 2017, 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 _CELLULAR_CONNECTION_UTIL_H +#define _CELLULAR_CONNECTION_UTIL_H + +#include "CellularTargets.h" +#ifdef CELLULAR_DEVICE + +#include "UARTSerial.h" +#include "NetworkInterface.h" +#include "EventQueue.h" +#include "Thread.h" + +#include "CellularNetwork.h" +#include "CellularPower.h" +#include "CellularSIM.h" + +// modem type is defined as CELLULAR_DEVICE macro +#define _CELLULAR_STRINGIFY(a) #a +#define CELLULAR_STRINGIFY(a) _CELLULAR_STRINGIFY(a) +#include CELLULAR_STRINGIFY(CELLULAR_DEVICE.h) + +namespace mbed { + +const int PIN_SIZE = 8; +const int MAX_RETRY_ARRAY_SIZE = 10; + +/** CellularConnectionFSM class + * + * Finite State Machine for connecting to cellular network + */ +class CellularConnectionFSM +{ +public: + CellularConnectionFSM(); + virtual ~CellularConnectionFSM(); + +public: + /** Cellular connection states + */ + enum CellularState { + STATE_INIT = 0, + STATE_POWER_ON, + STATE_DEVICE_READY, + STATE_SIM_PIN, + STATE_REGISTER_NETWORK, + STATE_REGISTERING_NETWORK, + STATE_ATTACH_NETWORK, + STATE_ATTACHING_NETWORK, + STATE_CONNECT_NETWORK, + STATE_CONNECTED, + }; + +public: + /** Initialize cellular device + * @remark Must be called before any other methods + * @return see nsapi_error_t, 0 on success + */ + nsapi_error_t init(); + + /** Set serial connection for cellular device + * @param serial UART driver + */ + void set_serial(UARTSerial *serial); + + /** Set callback for state update + * @param status_callback function to call on state changes + */ + void set_callback(mbed::Callback status_callback); + + /** Get event queue that can be chained to main event queue (or use start_dispatch) + * @return event queue + */ + events::EventQueue* get_queue(); + + /** Start event queue dispatching + * @return see nsapi_error_t, 0 on success + */ + nsapi_error_t start_dispatch(); + + /** Stop event queue dispatching and close cellular interfaces + */ + void stop(); + + /** Get cellular network interface + * @return network interface, NULL on failure + */ + CellularNetwork* get_network(); + + /** Get cellular device interface + * @return device interface, NULL on failure + */ + CellularDevice* get_device(); + + /** Get cellular sim interface + * @return sim interface, NULL on failure + */ + CellularSIM* get_sim(); + + /** Change cellular connection to the target state + * @param state to continue + * @return see nsapi_error_t, 0 on success + */ + nsapi_error_t continue_to_state(CellularState state); + + /** Set cellular device SIM PIN code + * @param sim_pin PIN code + */ + void set_sim_pin(const char *sim_pin); + + /** Sets the timeout array for network rejects. After reject next item is tried and after all items are waited and + * still fails then current network event will fail. + * + * @param timeout timeout array using seconds + * @param array_len length of the array + */ + void set_retry_timeout_array(uint16_t timeout[], int array_len); + +private: + bool open_power(FileHandle *fh); + bool open_sim(); + bool get_network_registration(CellularNetwork::RegistrationType type, CellularNetwork::RegistrationStatus &status, bool &is_registered); + bool set_network_registration(char *plmn = 0); + bool get_attach_network(CellularNetwork::AttachStatus &status); + bool set_attach_network(); + +private: + friend class EasyCellularConnection; + NetworkStack *get_stack(); + +private: + void device_ready(); + void report_failure(const char* msg); + void event(); + + UARTSerial *_serial; + CellularState _state; + CellularState _next_state; + + Callback _status_callback; + + CellularNetwork *_network; + CellularPower *_power; + CellularSIM *_sim; + events::EventQueue _queue; + rtos::Thread *_queue_thread; + CellularDevice *_cellularDevice; + char _sim_pin[PIN_SIZE+1]; + int _retry_count; + int _state_retry_count; + int _start_time; + uint16_t _retry_timeout_array[MAX_RETRY_ARRAY_SIZE]; + int _retry_array_length; + events::EventQueue _at_queue; +}; + +} // namespace + +#endif // CELLULAR_DEVICE + +#endif /* _CELLULAR_CONNECTION_UTIL_H */ diff --git a/features/cellular/easy_cellular/EasyCellularConnection.cpp b/features/cellular/easy_cellular/EasyCellularConnection.cpp new file mode 100644 index 0000000000..733490ee90 --- /dev/null +++ b/features/cellular/easy_cellular/EasyCellularConnection.cpp @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2017, 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 "CellularTargets.h" +#ifdef CELLULAR_DEVICE + +#if NSAPI_PPP_AVAILABLE +#include "nsapi_ppp.h" +#endif + +#include "CellularConnectionFSM.h" +#include "CellularUtil.h" + +#include "EasyCellularConnection.h" +#include "CellularLog.h" +#include "mbed_wait_api.h" + +#if MBED_CONF_CELLULAR_USE_APN_LOOKUP || MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP +#include "APN_db.h" +#endif //MBED_CONF_CELLULAR_USE_APN_LOOKUP || MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP + +namespace mbed { + +bool EasyCellularConnection::cellular_status(int state, int next_state) +{ + tr_info("cellular_status %d=>%d", state, next_state); + if (_target_state == state) { + if (state == CellularConnectionFSM::STATE_CONNECTED) { + _is_connected = true; + } else { + _is_connected = false; + } + tr_info("Target state reached: %d", _target_state); + MBED_ASSERT(_cellularSemaphore.release() == osOK); + return false; + } else { + _is_connected = false; + } + return true; +} + +EasyCellularConnection::EasyCellularConnection(bool debug) : + _is_connected(false), _is_initialized(false), _target_state(CellularConnectionFSM::STATE_POWER_ON), _cellularSerial( + MDMTXD, MDMRXD, MBED_CONF_PLATFORM_DEFAULT_SERIAL_BAUD_RATE), _cellularSemaphore(0), _cellularConnectionFSM(), _credentials_err( + NSAPI_ERROR_OK) +{ + tr_info("EasyCellularConnection()"); +#if MBED_CONF_CELLULAR_USE_APN_LOOKUP || MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP + _credentials_set = false; +#endif // #if MBED_CONF_CELLULAR_USE_APN_LOOKUP || MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP + modem_debug_on(debug); +} + +EasyCellularConnection::~EasyCellularConnection() +{ + _cellularConnectionFSM.stop(); +} + +nsapi_error_t EasyCellularConnection::init() +{ + nsapi_error_t err = NSAPI_ERROR_OK; + if (!_is_initialized) { +#if defined (MDMRTS) && defined (MDMCTS) + _cellularSerial.set_flow_control(SerialBase::RTSCTS, MDMRTS, MDMCTS); +#endif + _cellularConnectionFSM.set_serial(&_cellularSerial); + _cellularConnectionFSM.set_callback(callback(this, &EasyCellularConnection::cellular_status)); + + err = _cellularConnectionFSM.init(); + + if (err == NSAPI_ERROR_OK) { + err = _cellularConnectionFSM.start_dispatch(); + } + _is_initialized = true; + } + + return err; +} + +void EasyCellularConnection::set_credentials(const char *apn, const char *uname, const char *pwd) +{ + if (apn && strlen(apn) > 0) { + _credentials_err = init(); + + if (_credentials_err) { + return; + } + CellularNetwork * network = _cellularConnectionFSM.get_network(); + if (network) { + _credentials_err = network->set_credentials(apn, uname, pwd); +#if MBED_CONF_CELLULAR_USE_APN_LOOKUP || MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP + if (_credentials_err == NSAPI_ERROR_OK) { + _credentials_set = true; + } +#endif // #if MBED_CONF_CELLULAR_USE_APN_LOOKUP || MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP + } else { + tr_error("NO Network..."); + } + } +} + +void EasyCellularConnection::set_sim_pin(const char *sim_pin) +{ + if (sim_pin) { + _cellularConnectionFSM.set_sim_pin(sim_pin); + } +} + +nsapi_error_t EasyCellularConnection::connect(const char *sim_pin, const char *apn, const char *uname, const char *pwd) +{ + if (_is_connected) { + return NSAPI_ERROR_IS_CONNECTED; + } + + set_credentials(apn, uname, pwd); + if (_credentials_err) { + return _credentials_err; + } + + if (sim_pin) { + _cellularConnectionFSM.set_sim_pin(sim_pin); + } + + return connect(); +} + +nsapi_error_t EasyCellularConnection::check_connect() +{ + if (_is_connected) { + return NSAPI_ERROR_IS_CONNECTED; + } + + // there was an error while setting credentials but it's a void function so check error here... + if (_credentials_err) { + return _credentials_err; + } + + nsapi_error_t err = init(); + if (err) { + return err; + } + + return NSAPI_ERROR_OK; +} + +nsapi_error_t EasyCellularConnection::connect() +{ + nsapi_error_t err = check_connect(); + if (err) { + return err; + } +#if MBED_CONF_CELLULAR_USE_APN_LOOKUP || MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP + if (!_credentials_set) { + _target_state = CellularConnectionFSM::STATE_SIM_PIN; + err = _cellularConnectionFSM.continue_to_state(_target_state); + if (err == NSAPI_ERROR_OK) { + int sim_wait = _cellularSemaphore.wait(60*1000); // reserve 60 seconds to access to SIM + if (sim_wait != 1) { + tr_error("NO SIM ACCESS"); + err = NSAPI_ERROR_NO_CONNECTION; + } else { + char imsi[MAX_IMSI_LENGTH+1]; + wait(1); // need to wait to access SIM in some modems + err = _cellularConnectionFSM.get_sim()->get_imsi(imsi); + if (err == NSAPI_ERROR_OK) { + const char *apn_config = apnconfig(imsi); + if (apn_config) { + const char* apn = _APN_GET(apn_config); + const char* uname = _APN_GET(apn_config); + const char* pwd = _APN_GET(apn_config); + tr_info("Looked up APN %s", apn); + err = _cellularConnectionFSM.get_network()->set_credentials(apn, uname, pwd); + } + } + } + } + if (err) { + tr_info("APN lookup failed"); + return err; + } + } +#endif // MBED_CONF_CELLULAR_USE_APN_LOOKUP || MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP + + _target_state = CellularConnectionFSM::STATE_CONNECTED; + err = _cellularConnectionFSM.continue_to_state(_target_state); + if (err == NSAPI_ERROR_OK) { + int ret_wait = _cellularSemaphore.wait(10 * 60 * 1000); // cellular network searching may take several minutes + if (ret_wait != 1) { + tr_info("No cellular connection"); + err = NSAPI_ERROR_NO_CONNECTION; + } + } + + return err; +} + +nsapi_error_t EasyCellularConnection::disconnect() +{ + _credentials_err = NSAPI_ERROR_OK; + _is_connected = false; +#if MBED_CONF_CELLULAR_USE_APN_LOOKUP || MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP + _credentials_set = false; +#endif // #if MBED_CONF_CELLULAR_USE_APN_LOOKUP || MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP + if (!_cellularConnectionFSM.get_network()) { + return NSAPI_ERROR_NO_CONNECTION; + } + return _cellularConnectionFSM.get_network()->disconnect(); +} + +bool EasyCellularConnection::is_connected() +{ + return _is_connected; +} + +const char *EasyCellularConnection::get_ip_address() +{ + CellularNetwork *network = _cellularConnectionFSM.get_network(); + if (!network) { + return NULL; + } + return _cellularConnectionFSM.get_network()->get_ip_address(); +} + +const char *EasyCellularConnection::get_netmask() +{ + CellularNetwork *network = _cellularConnectionFSM.get_network(); + if (!network) { + return NULL; + } + + return network->get_netmask(); +} + +const char *EasyCellularConnection::get_gateway() +{ + CellularNetwork *network = _cellularConnectionFSM.get_network(); + if (!network) { + return NULL; + } + + return network->get_gateway(); +} + +void EasyCellularConnection::attach(mbed::Callback status_cb) +{ + CellularNetwork *network = _cellularConnectionFSM.get_network(); + if (network) { + network->attach(status_cb); + } +} + +void EasyCellularConnection::modem_debug_on(bool on) +{ + CellularDevice *dev = _cellularConnectionFSM.get_device(); + if (dev) { + dev->modem_debug_on(on); + } +} + +NetworkStack *EasyCellularConnection::get_stack() +{ + return _cellularConnectionFSM.get_stack(); +} + +} // namespace + +#endif // CELLULAR_DEVICE diff --git a/features/cellular/easy_cellular/EasyCellularConnection.h b/features/cellular/easy_cellular/EasyCellularConnection.h new file mode 100644 index 0000000000..608858093e --- /dev/null +++ b/features/cellular/easy_cellular/EasyCellularConnection.h @@ -0,0 +1,165 @@ +/* + * Copyright (c) 2017, 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 EASY_CELLULAR_CONNECTION_H + +#define EASY_CELLULAR_CONNECTION_H + +#include "CellularConnectionFSM.h" +#ifdef CELLULAR_DEVICE + +#include "netsocket/CellularBase.h" + +namespace mbed +{ + +/** EasyCellularConnection class + * + * Simplified adapter for cellular connection + */ +class EasyCellularConnection: public CellularBase +{ + +public: + EasyCellularConnection(bool debug = false); + virtual ~EasyCellularConnection(); + +public: + /** Set the Cellular network credentials + * + * Please check documentation of connect() for default behaviour of APN settings. + * + * @param apn Access point name + * @param uname optionally, Username + * @param pwd optionally, password + */ + virtual void set_credentials(const char *apn, const char *uname = 0, + const char *pwd = 0); + + /** Set the pin code for SIM card + * + * @param sim_pin PIN for the SIM card + */ + virtual void set_sim_pin(const char *sim_pin); + + /** Start the interface + * + * Attempts to connect to a Cellular network. + * + * @param sim_pin PIN for the SIM card + * @param apn optionally, access point name + * @param uname optionally, Username + * @param pwd optionally, password + * @return NSAPI_ERROR_OK on success, or negative error code on failure + */ + virtual nsapi_error_t connect(const char *sim_pin, const char *apn = 0, + const char *uname = 0, + const char *pwd = 0); + + /** Start the interface + * + * Attempts to connect to a Cellular network. + * If the SIM requires a PIN, and it is not set/invalid, NSAPI_ERROR_AUTH_ERROR is returned. + * + * @return NSAPI_ERROR_OK on success, or negative error code on failure + */ + virtual nsapi_error_t connect(); + + /** Stop the interface + * + * @return 0 on success, or error code on failure + */ + virtual nsapi_error_t disconnect(); + + /** Check if the connection is currently established or not + * + * @return true/false If the cellular module have successfully acquired a carrier and is + * connected to an external packet data network using PPP, isConnected() + * API returns true and false otherwise. + */ + virtual bool is_connected(); + + /** Get the local IP address + * + * @return Null-terminated representation of the local IP address + * or null if no IP address has been received + */ + virtual const char *get_ip_address(); + + /** Get the local network mask + * + * @return Null-terminated representation of the local network mask + * or null if no network mask has been received + */ + virtual const char *get_netmask(); + + /** Get the local gateways + * + * @return Null-terminated representation of the local gateway + * or null if no network mask has been received + */ + virtual const char *get_gateway(); + + /** Register callback for status reporting + * + * @param status_cb The callback for status changes + */ + virtual void attach(mbed::Callback status_cb); + + /** Turn modem debug traces on + * + * @param on set true to enable debug traces + */ + void modem_debug_on(bool on); + +protected: + + /** Provide access to the NetworkStack object + * + * @return The underlying NetworkStack object + */ + virtual NetworkStack *get_stack(); + +private: + /** Callback for cellular status changes + * + * @return true to continue state machine + */ + bool cellular_status(int state, int next_state); + nsapi_error_t init(); + nsapi_error_t check_connect(); + + bool _is_connected; + bool _is_initialized; +#if MBED_CONF_CELLULAR_USE_APN_LOOKUP || MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP + bool _credentials_set; +#endif // #if MBED_CONF_CELLULAR_USE_APN_LOOKUP || MBED_CONF_PPP_CELL_IFACE_APN_LOOKUP + CellularConnectionFSM::CellularState _target_state; + + UARTSerial _cellularSerial; + rtos::Semaphore _cellularSemaphore; + CellularConnectionFSM _cellularConnectionFSM; + nsapi_error_t _credentials_err; +}; + +} // namespace + +#endif // CELLULAR_DEVICE + +#endif // EASY_CELLULAR_CONNECTION_H + +/** @}*/ diff --git a/features/cellular/framework/API/CellularDevice.h b/features/cellular/framework/API/CellularDevice.h new file mode 100644 index 0000000000..feec489fa7 --- /dev/null +++ b/features/cellular/framework/API/CellularDevice.h @@ -0,0 +1,123 @@ +/* + * Copyright (c) 2017, 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 CELLULAR_DEVICE_H_ +#define CELLULAR_DEVICE_H_ + +#include "FileHandle.h" + +#include "CellularSIM.h" +#include "CellularNetwork.h" +#include "CellularSMS.h" +#include "CellularPower.h" +#include "CellularInformation.h" +#include "NetworkStack.h" + +namespace mbed +{ + +/** + * Class CellularDevice + * + * An abstract interface that defines opening and closing of cellular interfaces. + * Deleting/Closing of opened interfaces can be done only via this class. + */ +class CellularDevice +{ +public: + /** virtual Destructor + */ + virtual ~CellularDevice() {} + +public: + /** Create new CellularNetwork interface. + * + * @param fh file handle used in communication to modem. Can be for example UART handle. + * @return New instance of interface CellularNetwork. + */ + virtual CellularNetwork *open_network(FileHandle *fh) = 0; + + /** Create new CellularSMS interface. + * + * @param fh file handle used in communication to modem. Can be for example UART handle. + * @return New instance of interface CellularSMS. + */ + virtual CellularSMS *open_sms(FileHandle *fh) = 0; + + /** Create new CellularPower interface. + * + * @param fh file handle used in communication to modem. Can be for example UART handle. + * @return New instance of interface CellularPower. + */ + virtual CellularPower *open_power(FileHandle *fh) = 0; + + /** Create new CellularSIM interface. + * + * @param fh file handle used in communication to modem. Can be for example UART handle. + * @return New instance of interface CellularSIM. + */ + virtual CellularSIM *open_sim(FileHandle *fh) = 0; + + /** Create new CellularInformation interface. + * + * @param fh file handle used in communication to modem. Can be for example UART handle. + * @return New instance of interface CellularInformation. + */ + virtual CellularInformation *open_information(FileHandle *fh) = 0; + + /** Closes the opened CellularNetwork by deleting the CellularNetwork instance. + */ + virtual void close_network() = 0; + + /** Closes the opened CellularNetwork by deleting the CellularSMS instance. + */ + virtual void close_sms() = 0; + + /** Closes the opened CellularNetwork by deleting the CellularPower instance. + */ + virtual void close_power() = 0; + + /** Closes the opened CellularNetwork by deleting the CellularSIM instance. + */ + virtual void close_sim() = 0; + + /** Closes the opened CellularNetwork by deleting the CellularInformation instance. + */ + virtual void close_information() = 0; + + /** Set the default response timeout. + * + * @param timeout milliseconds to wait response from modem + */ + virtual void set_timeout(int timeout) = 0; + + /** Turn modem debug traces on + * + * @param on set true to enable debug traces + */ + virtual void modem_debug_on(bool on) = 0; + + /** Get network stack. + * + * @return network stack + */ + virtual NetworkStack *get_stack() = 0; +}; + +} // namespace mbed + +#endif // CELLULAR_DEVICE_H_ diff --git a/features/cellular/framework/API/CellularInformation.h b/features/cellular/framework/API/CellularInformation.h new file mode 100644 index 0000000000..d2be876921 --- /dev/null +++ b/features/cellular/framework/API/CellularInformation.h @@ -0,0 +1,69 @@ +/* + * 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. + */ + +#ifndef CELLULAR_INFORMATION_H_ +#define CELLULAR_INFORMATION_H_ + +#include +#include "nsapi_types.h" + +namespace mbed { + +/** + * Class CellularInformation + * + * An abstract interface that provides information about cellular device. + */ +class CellularInformation +{ +protected: + // friend of CellularDevice so that it's the only way to close/delete this class. + friend class CellularDevice; + + /** virtual Destructor + */ + virtual ~CellularInformation() {}; + +public: + /** Request manufacturer identification of cellular device + * + * @param buf manufacturer identification + * @param buf_size max length of manufacturer identification is 2048 characters + * @return on success read character count, on failure negative error code + */ + virtual nsapi_size_or_error_t get_manufacturer(char *buf, size_t buf_size) = 0; + + /** Request model identification of cellular device + * + * @param buf model identification + * @param buf_size max length of model identification is 2048 characters + * @return on success read character count, on failure negative error code + */ + virtual nsapi_size_or_error_t get_model(char *buf, size_t buf_size) = 0; + + /** Request revision identification of cellular device + * + * @param buf revision identification + * @param buf_size max length of revision identification is 2048 characters + * @return on success read character count, on failure negative error code + */ + virtual nsapi_size_or_error_t get_revision(char *buf, size_t buf_size) = 0; +}; + +} // namespace mbed + +#endif // CELLULAR_INFORMATION_H_ diff --git a/features/cellular/framework/API/CellularNetwork.h b/features/cellular/framework/API/CellularNetwork.h new file mode 100644 index 0000000000..672b08b9f1 --- /dev/null +++ b/features/cellular/framework/API/CellularNetwork.h @@ -0,0 +1,388 @@ +/* + * Copyright (c) 2017, 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 CELLULAR_NETWORK_H_ +#define CELLULAR_NETWORK_H_ + +#include "CellularInterface.h" +#include "NetworkInterface.h" +#include "CellularList.h" + +namespace mbed { + +/* Maximum length of IPV6 address in ipv4-like dotted format. More info in 3gpp 27007.*/ +const int MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT = 63; +/* Maximum length of access point name */ +const int MAX_ACCESSPOINT_NAME_LENGTH = 100; +const int MAX_OPERATOR_NAME_LONG = 16; +const int MAX_OPERATOR_NAME_SHORT = 8; + +/** + * Class CellularNetwork + * + * An abstract interface for connecting to a network and getting information from it. + */ +class CellularNetwork : public NetworkInterface +{ +protected: + // friend of CellularDevice so that it's the only way to close/delete this class. + friend class CellularDevice; + + /** + * virtual Destructor + */ + virtual ~CellularNetwork() {} + +public: + /* Definition for Supported CIoT EPS optimizations type. */ + enum Supported_UE_Opt { + SUPPORTED_UE_OPT_NO_SUPPORT = 0, /* No support. */ + SUPPORTED_UE_OPT_CONTROL_PLANE, /* Support for control plane CIoT EPS optimization. */ + SUPPORTED_UE_OPT_USER_PLANE, /* Support for user plane CIoT EPS optimization. */ + SUPPORTED_UE_OPT_BOTH, /* Support for both control plane CIoT EPS optimization and user plane CIoT EPS + optimization. */ + SUPPORTED_UE_OPT_MAX + }; + + /* Definition for Preferred CIoT EPS optimizations type. */ + enum Preferred_UE_Opt { + PREFERRED_UE_OPT_NO_PREFERENCE = 0, /* No preference. */ + PREFERRED_UE_OPT_CONTROL_PLANE, /* Preference for control plane CIoT EPS optimization. */ + PREFERRED_UE_OPT_USER_PLANE, /* Preference for user plane CIoT EPS optimization. */ + PREFERRED_UE_OPT_MAX + }; + + /* Network registration status */ + enum RegistrationStatus { + NotRegistered = 0, + RegisteredHomeNetwork, + SearchingNetwork, + RegistrationDenied, + Unknown, + RegisteredRoaming, + RegisteredSMSOnlyHome, + RegisteredSMSOnlyRoaming, + AttachedEmergencyOnly, + RegisteredCSFBNotPreferredHome, + RegisteredCSFBNotPreferredRoaming = 10 + }; + + /* Network registration type */ + enum RegistrationType { + C_EREG = 0, + C_GREG, + C_REG, + C_MAX + }; + + /* device attach status to network */ + enum AttachStatus { + Detached = 0, + Attached, + }; + + /* whether the additional exception reports are allowed to be sent when the maximum uplink rate is reached */ + enum RateControlExceptionReports { + NotAllowedToBeSent = 0, + AllowedToBeSent + }; + + /* specifies the time unit to be used for the maximum uplink rate */ + enum RateControlUplinkTimeUnit { + Unrestricted = 0, + Minute, + Hour, + Day, + Week + }; + + /* authentication type when activating or modifying the pdp context */ + enum AuthenticationType { + NOAUTH = 0, + PAP, + CHAP + }; + + // 3GPP TS 27.007 - 7.3 PLMN selection +COPS + struct operator_t { + enum Status { + Unknown, + Available, + Current, + Forbiden + }; + + enum RadioAccessTechnology { + RAT_GSM, + RAT_GSM_COMPACT, + RAT_UTRAN, + RAT_EGPRS, + RAT_HSDPA, + RAT_HSUPA, + RAT_HSDPA_HSUPA, + RAT_E_UTRAN, + RAT_CATM1, + RAT_NB1, + RAT_UNKNOWN + }; + + + Status op_status; + char op_long[MAX_OPERATOR_NAME_LONG+1]; + char op_short[MAX_OPERATOR_NAME_SHORT+1]; + char op_num[MAX_OPERATOR_NAME_SHORT+1]; + RadioAccessTechnology op_rat; + operator_t *next; + + operator_t() { + op_status = Unknown; + op_rat = RAT_UNKNOWN; + next = NULL; + } + }; + + typedef CellularList operList_t; + + /* PDP Context information */ + struct pdpcontext_params_t { + char apn[MAX_ACCESSPOINT_NAME_LENGTH+1]; + char local_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT+1]; + char local_subnet_mask[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT+1]; + char gateway_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT+1]; + char dns_primary_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT+1]; + char dns_secondary_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT+1]; + char p_cscf_prim_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT+1]; + char p_cscf_sec_addr[MAX_IPV6_ADDR_IN_IPV4LIKE_DOTTED_FORMAT+1]; + int cid; + int bearer_id; + int im_signalling_flag; + int lipa_indication; + int ipv4_mtu; + int wlan_offload; + int local_addr_ind; + int non_ip_mtu; + int serving_plmn_rate_control_value; + pdpcontext_params_t* next; + + pdpcontext_params_t() { + apn[0] = '\0'; + local_addr[0] = '\0'; + local_subnet_mask[0] = '\0'; + gateway_addr[0] = '\0'; + dns_primary_addr[0] = '\0'; + dns_secondary_addr[0] = '\0'; + p_cscf_prim_addr[0] = '\0'; + p_cscf_sec_addr[0] = '\0'; + cid = -1; + bearer_id = -1; + im_signalling_flag = -1; + lipa_indication = -1; + ipv4_mtu = -1; + wlan_offload = -1; + local_addr_ind = -1; + non_ip_mtu = -1; + serving_plmn_rate_control_value = -1; + next = NULL; + } + }; + typedef CellularList pdpContextList_t; + + /** Request registering to network. + * + * @param plmn format is in numeric format or 0 for automatic network registration + * @return zero on success + */ + virtual nsapi_error_t set_registration(const char *plmn = 0) = 0; + + /** Gets the network registration status. + * + * @param type see RegistrationType values + * @param status see RegistrationStatus values + * @return zero on success + */ + virtual nsapi_error_t get_registration_status(RegistrationType type, RegistrationStatus &status) = 0; + + /** Set the cellular network APN and credentials + * + * @param apn Optional name of the network to connect to + * @param username Optional username for the APN + * @param password Optional password fot the APN + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t set_credentials(const char *apn, + const char *username = 0, const char *password = 0) = 0; + + /** Set the cellular network APN and credentials + * + * @param apn Name of the network to connect to + * @param type Authentication type to use + * @param username Optional username for the APN + * @param password Optional password fot the APN + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t set_credentials(const char *apn, AuthenticationType type, + const char *username = 0, const char *password = 0) = 0; + + /** Request attach to network. + * + * @param timeout milliseconds to wait for attach response + * @return zero on success + */ + virtual nsapi_error_t set_attach(int timeout = 10*1000) = 0; + + /** Request attach status from network. + * + * @param status see AttachStatus values + * @return zero on success + */ + virtual nsapi_error_t get_attach(AttachStatus &status) = 0; + + /** Get APN rate control. + * + * @remark optional params are not updated if not received from network, so use good defaults + * @param reports Additional exception reports at maximum rate reached are allowed to be sent [optional] + * @param time_unit Uplink time unit with values 0=unrestricted, 1=minute, 2=hour, 3=day, 4=week [optional] + * @param uplink_rate Maximum number of messages per timeUnit [optional] + * @return zero on success + */ + virtual nsapi_error_t get_rate_control(CellularNetwork::RateControlExceptionReports &reports, + CellularNetwork::RateControlUplinkTimeUnit &time_unit, int &uplink_rate) = 0; + + /** Get backoff timer value + * + * @param backoff_timer Backoff timer value associated with PDP APN in seconds + * @return zero on success + */ + virtual nsapi_error_t get_apn_backoff_timer(int &backoff_timer) = 0; + + /** Sets radio access technology. + * + * @param op_rat Radio access technology + * @return zero on success + */ + virtual nsapi_error_t set_access_technology(operator_t::RadioAccessTechnology op_rat) = 0; + + /** Scans for operators module can reach. + * + * @param operators Container of reachable operators and their access technologies + * @param ops_count Number of found operators + * @return zero on success + */ + virtual nsapi_error_t scan_plmn(operList_t &operators, int &ops_count) = 0; + + /** Set CIoT optimizations. + * + * @param supported_opt Supported CIoT EPS optimizations. + * @param preferred_opt Preferred CIoT EPS optimizations. + * @return zero on success + */ + virtual nsapi_error_t set_ciot_optimization_config(Supported_UE_Opt supported_opt, + Preferred_UE_Opt preferred_opt) = 0; + + /** Get CIoT optimizations. + * + * @param supported_opt Supported CIoT EPS optimizations. + * @param preferred_opt Preferred CIoT EPS optimizations. + * @return zero on success + */ + virtual nsapi_error_t get_ciot_optimization_config(Supported_UE_Opt& supported_opt, + Preferred_UE_Opt& preferred_opt) = 0; + + /** Start the interface. Attempts to connect to a cellular network. + * + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t connect() = 0; + + /** Start the interface. Attempts to connect to a cellular network. + * + * @param apn Optional name of the network to connect to + * @param username Optional username for your APN + * @param password Optional password for your APN + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t connect(const char *apn, + const char *username = 0, const char *password = 0) = 0; + + /** + * Set the pdn type to be used + * + * @param stack_type the stack type to be used. + * + * @return NSAPI_ERROR_OK on success + */ + virtual nsapi_error_t set_stack_type(nsapi_ip_stack_t stack_type) = 0; + + /** + * Get the pdn type in use + * + * @return stack type + */ + virtual nsapi_ip_stack_t get_stack_type() = 0; + + /** Get the relevant information for an active non secondary PDP context. + * + * @remark optional params are not updated if not received from network. + * @param params_list reference to linked list which is filled on successful call + * @return 0 on success, negative error code on failure + */ + virtual nsapi_error_t get_pdpcontext_params(pdpContextList_t& params_list) = 0; + + /** Get extended signal quality parameters. + * + * @param rxlev signal strength level + * @param ber bit error rate + * @param rscp signal code power + * @param ecno ratio of the received energy per PN chip to the total received power spectral density + * @param rsrq signal received quality + * @param rsrp signal received power + * @return NSAPI_ERROR_OK on success, negative error code on failure + */ + virtual nsapi_error_t get_extended_signal_quality(int &rxlev, int &ber, int &rscp, int &ecno, int &rsrq, int &rsrp) = 0; + + /** Get signal quality parameters. + * + * @param rssi signal strength level + * @param ber bit error rate + * @return NSAPI_ERROR_OK on success, negative error code on failure + */ + virtual nsapi_error_t get_signal_quality(int &rssi, int &ber) = 0; + + /** Get cell id. + * + * @param cell_id cell id + * @return NSAPI_ERROR_OK on success, negative error code on failure + */ + virtual nsapi_error_t get_cell_id(int &cell_id) = 0; + + /** Get the last 3GPP error code + * @return see 3GPP TS 27.007 error codes + */ + virtual int get_3gpp_error() = 0; + + /** Get the operator parameters. + * + * @param format format of the operator field + * @param operator_params applicable operator param fields filled + * @return NSAPI_ERROR_OK on success, negative error code on failure + */ + virtual nsapi_error_t get_operator_params(int &format, operator_t &operator_params) = 0; +}; + +} // namespace mbed + +#endif // CELLULAR_NETWORK_H_ diff --git a/features/cellular/framework/API/CellularPower.h b/features/cellular/framework/API/CellularPower.h new file mode 100644 index 0000000000..9d15be1f8a --- /dev/null +++ b/features/cellular/framework/API/CellularPower.h @@ -0,0 +1,125 @@ +/* + * Copyright (c) 2017, 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 CELLULAR_API_CELLULARPOWER_H_ +#define CELLULAR_API_CELLULARPOWER_H_ + +#include "nsapi_types.h" + +namespace mbed { + +/** + * Class CellularPower + * + * An interface that provides power handling functions for modem/module. + */ +class CellularPower +{ +protected: + // friend of CellularDevice so that it's the only way to close/delete this class. + friend class CellularDevice; + + /** + * virtual Destructor + */ + virtual ~CellularPower() {} + +public: + /* Access technology used in method opt_receive_period */ + enum EDRXAccessTechnology { + EDRXGSM_EC_GSM_IoT_mode = 1, + EDRXGSM_A_Gb_mode, + EDRXUTRAN_Iu_mode, + EDRXEUTRAN_WB_S1_mode, + EDRXEUTRAN_NB_S1_mode + }; + + /** Set cellular device power on. Default implementation is empty. + * Device power on/off is modem/board specific behavior and must be done on inherited class if needed. + * Power on is done by toggling power pin/button. + * + * @remark set_at_mode must be called to initialise modem + * + * @return zero on success + */ + virtual nsapi_error_t on() = 0; + + /** Set cellular device power off. Default implementation is empty. + * Device power on/off is modem/board specific behavior and must be done on inherited class if needed. + * Power off is done by toggling power pin/button. + * + * + * @return zero on success + */ + virtual nsapi_error_t off() = 0; + + /** Set AT command mode. Blocking until success or failure. + * + * @remark must be called after power on to prepare correct AT mode + * + * @return zero on success + */ + virtual nsapi_error_t set_at_mode() = 0; + + /** Set cellular device power level by enabling/disabling functionality. + * + * @param func_level: + * 0 minimum functionality + * 1 full functionality. Enable (turn on) the transmit and receive RF circuits for all supported radio access technologies. + * For MTs supporting +CSRA, this equals the RATs indicated by the response of +CSRA=?. Current +CSRA setting is ignored. + * It is not required that the MT transmit and receive RF circuits are in a disabled state for this setting to have effect. + * 2 disable (turn off) MT transmit RF circuits only + * 3 disable (turn off) MT receive RF circuits only + * 4 disable (turn off) both MT transmit and receive RF circuits + * + * @remark See 3GPP TS 27.007 CFUN for more details + * + * @return zero on success + */ + virtual nsapi_error_t set_power_level(int func_level) = 0; + + /** Reset and wake-up cellular device. + * + * @return zero on success + */ + virtual nsapi_error_t reset() = 0; + + /** Opt for power save setting on cellular device. If both parameters are zero then disables PSM. + * + * @remark See 3GPP TS 27.007 PSM for details + * + * @param periodic_time Timeout in seconds IoT subsystem is not expecting messaging + * @param active_time Timeout in seconds IoT subsystem waits for response + * @return zero on success + */ + virtual nsapi_error_t opt_power_save_mode(int periodic_time, int active_time) = 0; + + /** Opt for discontinuous reception on cellular device. + * + * @remark See 3GPP TS 27.007 eDRX for details. + * + * @param mode disable or enable the use of eDRX + * @param act_type type of access technology + * @param edrx_value requested edxr value. Extended DRX parameters information element. + * + * @return zero on success + */ + virtual nsapi_error_t opt_receive_period(int mode, EDRXAccessTechnology act_type, uint8_t edrx_value) = 0; +}; + +} // namespace mbed + +#endif /* CELLULAR_API_CELLULARPOWER_H_ */ diff --git a/features/cellular/framework/API/CellularSIM.h b/features/cellular/framework/API/CellularSIM.h new file mode 100644 index 0000000000..8a15218802 --- /dev/null +++ b/features/cellular/framework/API/CellularSIM.h @@ -0,0 +1,92 @@ +/* + * Copyright (c) 2017, 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 CELLULAR_SIM_H_ +#define CELLULAR_SIM_H_ + +#include "nsapi_types.h" + +namespace mbed { + +const int MAX_SIM_READY_WAITING_TIME = 30; +const int MAX_IMSI_LENGTH = 15; +/** + * Class CellularSIM + * + * An abstract interface for SIM card handling. + */ +class CellularSIM +{ +protected: + // friend of CellularDevice so that it's the only way to close/delete this class. + friend class CellularDevice; + + /** + * virtual Destructor + */ + virtual ~CellularSIM() {}; + +public: + /* enumeration for possible SIM states */ + enum SimState { + SimStateReady = 0, + SimStatePinNeeded, + SimStatePukNeeded, + SimStateUnknown + }; + + /** Open the SIM card by setting the pin code for SIM. + * + * @param sim_pin PIN for the SIM card + * @return zero on success + */ + virtual nsapi_error_t set_pin(const char *sim_pin) = 0; + + /**Change sim pin code. + * + * @param sim_pin Current PIN for sim + * @param new_pin New PIN for sim + * @return zero on success + */ + virtual nsapi_error_t change_pin(const char *sim_pin, const char *new_pin) = 0; + + /** Change is pin query needed after boot + * + * @param sim_pin Valid PIN for SIM card + * @param query_pin False is PIN query not needed, True if PIN query needed after boot. + * @return zero on success + */ + virtual nsapi_error_t set_pin_query(const char *sim_pin, bool query_pin) = 0; + + /** Get sim card's state + * + * @param state current state of SIM + * @return zero on success + */ + virtual nsapi_error_t get_sim_state(SimState &state) = 0; + + /** Get IMSI from the sim card + * + * @param imsi preallocated char* which after successful request contains imsi + * @return zero on success + */ + virtual nsapi_error_t get_imsi(char* imsi) = 0; +}; + +} // namespace mbed + +#endif // CELLULAR_SIM_H_ diff --git a/features/cellular/framework/API/CellularSMS.h b/features/cellular/framework/API/CellularSMS.h new file mode 100644 index 0000000000..35dbfc3c9c --- /dev/null +++ b/features/cellular/framework/API/CellularSMS.h @@ -0,0 +1,155 @@ +/* + * Copyright (c) 2017, 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 CELLULAR_SMS_H_ +#define CELLULAR_SMS_H_ + +#include "Callback.h" +#include "nsapi_types.h" + +namespace mbed { + +// including trailing '\0' +const uint16_t SMS_MAX_SIZE_WITH_CONCATENATION = 4096 + 1; +const uint16_t SMS_MAX_PHONE_NUMBER_SIZE = 20 + 1; +const uint16_t SMS_MAX_TIME_STAMP_SIZE = 20 + 1; + +const uint16_t SMS_MAX_SIZE_8BIT_SINGLE_SMS_SIZE = 140; +const uint16_t SMS_MAX_SIZE_GSM7_SINGLE_SMS_SIZE = 160; + +const uint16_t SMS_SIM_WAIT_TIME_MILLISECONDS = 200; + +const int SMS_ERROR_MULTIPART_ALL_PARTS_NOT_READ = -5001; + +/** + * Class CellularSMS + * + * An abstract interface for SMS sending, reading and deleting. + */ +class CellularSMS +{ +protected: + // friend of CellularDevice so that it's the only way to close/delete this class. + friend class CellularDevice; + + /** + * virtual Destructor + */ + virtual ~CellularSMS() {}; +public: + + /* Enumeration for possible SMS modes, PDU and Text */ + enum CellularSMSMmode { + CellularSMSMmodePDU = 0, + CellularSMSMmodeText + }; + + /** Does all the necessary initializations needed for receiving and sending sms. + * + * @param mode enumeration for choosing the correct mode: text/pdu + * @return zero on success + */ + virtual nsapi_error_t initialize(CellularSMSMmode mode) = 0; + + /** Send the SMS with the given parameters + * + * @param phone_number Phone number where to send sms + * @param message SMS message content + * @param msg_len Length of the message + * @return possible error code or length of the sent sms + */ + virtual nsapi_size_or_error_t send_sms(const char* phone_number, const char* message, int msg_len) = 0; + + /** Gets the oldest received sms. + * + * @param buf preallocated buffer for sms message content + * @param buf_len length of allocated buf + * @param phone_num preallocated buffer for phone number where sms was sent + * @param phone_len length of allocated phone_num buffer + * @param time_stamp preallocated buffer for TP-Service Centre Time Stamp (format: yy/MM/dd,hh:mm:ss-+zz). +-zz is timezone. + * The unit of time zone is a quarter of an hour relative to GMT. For example +32 would be GMT+8. + * @param time_len length of allocated time_stamp buffer + * @param buf_size if method return error NSAPI_ERROR_NO_MEMORY because the given buf was not big enough this will + * hold the size which is enough. Otherwise zero. + * @return possible error code or size of buf. Will return SMS_ERROR_MULTIPART_ALL_PARTS_NOT_READ + * if sms was multipart but not all parts are present/failed to read. + */ + virtual nsapi_size_or_error_t get_sms(char* buf, uint16_t buf_len, char* phone_num, uint16_t phone_len, + char* time_stamp, uint16_t time_len, int *buf_size) = 0; + + /** Callback which is called when new sms is received. SMS can be fetched via method get_sms(). + * + * @remark In PDU mode there can be multipart sms and callback is called for every received part. + * + * @param func Callback function which is called when new sms is received. + */ + virtual void set_sms_callback(Callback func) = 0; + + /** CPMS preferred message storage + * + * @param memr memory from which messages are read and deleted + * "SM" - SIM SMS memory storage (default) + * "ME" - NVM SMS storage + * @param memw memory to which writing and sending operations are made + * "SM" - SIM SMS memory storage (default) + * "ME" - NVM SMS storage + * @param mems memory to which received SMs are preferred to be stored + * "SM" - SIM SMS memory storage (default) + * "ME" - NVM SMS storage + * + * @return 1 for success, 0 for failure + */ + virtual nsapi_error_t set_cpms(const char *memr, const char *memw, const char *mems) = 0; + + /** CSCA - set Service Center Address + * + * @param sca Service Center Address to be used for mobile originated SMS transmissions. + * @param type 129 - national numbering scheme, 145 - international numbering scheme (contains the character "+") + * + * @return 1 for success, 0 for failure + */ + virtual nsapi_error_t set_csca(const char *sca, int type) = 0; + + /** Set command sets the current character set used by the device. "GSM", "IRA",.... + * + * @remark Current implementation support only ASCII so choose the correct character set. + * + * @param chr_set preferred character set list (comma separated). Modem might not support the wanted character set + * so chr_set list is looped from start until supported set is found. Used character set index is returned. + * See more from 3GPP TS 27.005. + * @return Used character set index from the given list in case of success. Otherwise negative errorcode. + */ + virtual nsapi_size_or_error_t set_cscs(const char *chr_set) = 0; + + /** Deletes all messages from the currently set memory/SIM + * + * @return possible error code + */ + virtual nsapi_error_t delete_all_messages() = 0; + + /** Some modems need extra time between AT commands and responses or there will be error -314, SIM busy. + * If SIM busy errors are an issue this time should be increased. It can also be set to zero to make + * operations faster and more energy efficient if no errors will follow. By default wait time is zero. + * + * @param sim_wait_time + */ + virtual void set_extra_sim_wait_time(int sim_wait_time) = 0; +}; + +} // namespace mbed + +#endif // CELLULAR_SMS_H_ diff --git a/features/cellular/framework/AT/ATHandler.cpp b/features/cellular/framework/AT/ATHandler.cpp new file mode 100644 index 0000000000..2c3d6006c5 --- /dev/null +++ b/features/cellular/framework/AT/ATHandler.cpp @@ -0,0 +1,1082 @@ +/* + * Copyright (c) 2017, 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 "ATHandler.h" +#include "mbed_poll.h" +#include "FileHandle.h" +#include "Timer.h" +#include "mbed_wait_api.h" +#include "mbed_debug.h" +#ifdef MBED_CONF_RTOS_PRESENT +#include "rtos/Thread.h" +#endif + +using namespace mbed; +using namespace events; + +//#define MBED_TRACE_MAX_LEVEL TRACE_LEVEL_DEBUG +#include "CellularLog.h" + +#if MBED_CONF_MBED_TRACE_ENABLE +#define at_debug(format, ...) do { if (_debug_on) debug(format, ## __VA_ARGS__); } while (0) +#else +#define at_debug(...) +#endif + +const char *mbed::OK = "OK\r\n"; +const uint8_t OK_LENGTH = 4; +const char *mbed::CRLF = "\r\n"; +const uint8_t CRLF_LENGTH = 2; +const char *CME_ERROR = "+CME ERROR:"; +const uint8_t CME_ERROR_LENGTH = 11; +const char *CMS_ERROR = "+CMS ERROR:"; +const uint8_t CMS_ERROR_LENGTH = 11; +const char *ERROR_ = "ERROR\r\n"; +const uint8_t ERROR_LENGTH = 7; +const uint8_t MAX_RESP_LENGTH = CMS_ERROR_LENGTH; +const char DEFAULT_DELIMITER = ','; + +static const uint8_t map_3gpp_errors[][2] = { + { 103, 3 }, { 106, 6 }, { 107, 7 }, { 108, 8 }, { 111, 11 }, { 112, 12 }, { 113, 13 }, { 114, 14 }, + { 115, 15 }, { 122, 22 }, { 125, 25 }, { 172, 95 }, { 173, 96 }, { 174, 97 }, { 175, 99 }, { 176, 111 }, + { 177, 8 }, { 126, 26 }, { 127, 27 }, { 128, 28 }, { 129, 29 }, { 130, 30 }, { 131, 31 }, { 132, 32 }, + { 133, 33 }, { 134, 34 }, { 140, 40 }, { 141, 41 }, { 142, 42 }, { 143, 43 }, { 144, 44 }, { 145, 45 }, + { 146, 46 }, { 178, 65 }, { 179, 66 }, { 180, 48 }, { 181, 83 }, { 171, 49 }, +}; + +ATHandler::ATHandler(FileHandle *fh, EventQueue &queue, int timeout, const char *output_delimiter) : + _nextATHandler(0), + _fileHandle(fh), + _queue(queue), + _last_err(NSAPI_ERROR_OK), + _last_3gpp_error(0), + _oob_string_max_length(0), + _oobs(NULL), + _at_timeout(timeout), + _previous_at_timeout(timeout), + _fh_sigio_set(false), + _processing(false), + _ref_count(1), + _stop_tag(NULL), + _delimiter(DEFAULT_DELIMITER), + _prefix_matched(false), + _urc_matched(false), + _error_found(false), + _max_resp_length(MAX_RESP_LENGTH), + _debug_on(false), + _cmd_start(false) +{ + //enable_debug(true); + + clear_error(); + + if (output_delimiter) { + _output_delimiter_length = strlen(output_delimiter); + _output_delimiter = new char[_output_delimiter_length]; + for (unsigned i=0; i<_output_delimiter_length; i++) { + _output_delimiter[i] = output_delimiter[i]; + } + } else { + _output_delimiter = NULL; + _output_delimiter_length = 0; + } + + reset_buffer(); + memset(_info_resp_prefix, 0, sizeof(_info_resp_prefix)); + + _current_scope = NotSet; + set_tag(&_resp_stop, OK); + set_tag(&_info_stop, CRLF); + set_tag(&_elem_stop, ")"); + + _fileHandle->set_blocking(false); + + set_filehandle_sigio(); +} + +void ATHandler::enable_debug(bool enable) +{ + _debug_on = enable; +} + +ATHandler::~ATHandler() +{ + while (_oobs) { + struct oob_t *oob = _oobs; + _oobs = oob->next; + delete oob; + } + if (_output_delimiter) { + delete [] _output_delimiter; + } +} + +void ATHandler::inc_ref_count() +{ + _ref_count++; +} + +void ATHandler::dec_ref_count() +{ + _ref_count--; +} + +int ATHandler::get_ref_count() +{ + return _ref_count; +} + +FileHandle *ATHandler::get_file_handle() +{ + return _fileHandle; +} + +void ATHandler::set_file_handle(FileHandle *fh) +{ + _fileHandle = fh; +} + +void ATHandler::set_urc_handler(const char *prefix, mbed::Callback callback) +{ + struct oob_t *oob = new struct oob_t; + oob->matching_to_received = true; + size_t prefix_len = strlen(prefix); + if (prefix_len > _oob_string_max_length) { + _oob_string_max_length = prefix_len; + if (_oob_string_max_length > _max_resp_length) { + _max_resp_length = _oob_string_max_length; + } + } + oob->prefix = prefix; + oob->cb = callback; + oob->next = _oobs; + _oobs = oob; +} + +void ATHandler::event() +{ + // _processing must be set before filehandle write/read to avoid repetitive sigio events + if (!_processing) { + _processing = true; + (void) _queue.call(Callback(this, &ATHandler::process_oob)); + } +} + +void ATHandler::lock() +{ +#ifdef AT_HANDLER_MUTEX + _fileHandleMutex.lock(); +#endif + _processing = true; + clear_error(); +} + +void ATHandler::unlock() +{ + _processing = false; +#ifdef AT_HANDLER_MUTEX + _fileHandleMutex.unlock(); +#endif + if (_fileHandle->readable() || (_recv_pos < _recv_len)) { + (void) _queue.call(Callback(this, &ATHandler::process_oob)); + } +} + +nsapi_error_t ATHandler::unlock_return_error() +{ + nsapi_error_t err = _last_err; + unlock(); + return err; +} + +void ATHandler::set_at_timeout(uint32_t timeout_milliseconds, bool default_timeout) +{ + if (default_timeout) { + _previous_at_timeout = timeout_milliseconds; + _at_timeout = timeout_milliseconds; + } else if (timeout_milliseconds != _at_timeout) { + _previous_at_timeout = _at_timeout; + _at_timeout = timeout_milliseconds; + } +} + +void ATHandler::restore_at_timeout() +{ + if (_previous_at_timeout != _at_timeout) { + _at_timeout =_previous_at_timeout; + } +} + +void ATHandler::process_oob() +{ + lock(); + tr_debug("process_oob %d", (_fileHandle->readable() || (_recv_pos < _recv_len))); + if (_fileHandle->readable() || (_recv_pos < _recv_len)) { + _current_scope = NotSet; + Timer timer; + timer.start(); + do { + if (match_urc()) { + if (_fileHandle->readable() || (_recv_pos < _recv_len)) { + continue; + } + break; + } + // If no match found, look for CRLF and consume everything up to CRLF + if (mem_str(_recv_buff, _recv_len, CRLF, CRLF_LENGTH)) { + consume_to_tag(CRLF, true); + } else { + if (_fileHandle->readable()) { + fill_buffer(); + } else { +#ifdef MBED_CONF_RTOS_PRESENT + rtos::Thread::yield(); +#endif + } + } + } while (timer.read_ms() < 20); // URC's are very short so 20ms should be enough + } + tr_debug("process_oob exit"); + + flush(); // consume anything that could not be handled + + unlock(); +} + +void ATHandler::set_filehandle_sigio() +{ + if (_fh_sigio_set) { + return; + } + _fileHandle->sigio(mbed::Callback(this, &ATHandler::event)); + _fh_sigio_set = true; +} + +void ATHandler::reset_buffer() +{ + tr_debug("%s", __func__); + _recv_pos = 0; _recv_len = 0; +} + +void ATHandler::rewind_buffer() +{ + tr_debug("%s", __func__); + if (_recv_pos > 0 && _recv_len >= _recv_pos) { + _recv_len -= _recv_pos; + // move what is not read to beginning of buffer + memmove(_recv_buff, _recv_buff + _recv_pos, _recv_len); + _recv_pos = 0; + } +} + +// we are always expecting to receive something so there is wait timeout +void ATHandler::fill_buffer() +{ + tr_debug("%s", __func__); + // Reset buffer when full + if (sizeof(_recv_buff) == _recv_len) { + reset_buffer(); + } + + Timer timer; + timer.start(); + do { + ssize_t len = _fileHandle->read(_recv_buff + _recv_len, sizeof(_recv_buff) - _recv_len); + if (len > 0) { + _recv_len += len; + at_debug("\n----------readable----------: %d\n", _recv_len); + for (size_t i = _recv_pos; i < _recv_len; i++) { + at_debug("%c", _recv_buff[i]); + } + at_debug("\n----------readable----------\n"); + return; + } else if (len != -EAGAIN && len != 0) { + tr_warn("%s error: %d while reading", __func__, len); + break; + } +#ifdef MBED_CONF_RTOS_PRESENT + rtos::Thread::yield(); +#endif + } while ((uint32_t)timer.read_ms() < _at_timeout); + + set_error(NSAPI_ERROR_DEVICE_ERROR); + tr_error("AT TIMEOUT, scope: %d timeout: %lu", _current_scope, _at_timeout); +} + +int ATHandler::get_char() +{ + if (_recv_pos == _recv_len) { + tr_debug("%s", __func__); + reset_buffer(); // try to read as much as possible + fill_buffer(); + if (get_last_error()) { + tr_debug("%s: -1", __func__); + return -1; // timeout to read + } + } + + tr_debug("%s: %c", __func__, _recv_buff[_recv_pos]); + + return _recv_buff[_recv_pos++]; +} + +void ATHandler::skip_param(uint32_t count) +{ + tr_debug("%s", __func__); + if (_last_err || !_stop_tag || _stop_tag->found) { + return; + } + + for (uint32_t i = 0; (i < count && !_stop_tag->found); i++) { + size_t match_pos = 0; + while (true) { + int c = get_char(); + if (c == -1) { + set_error(NSAPI_ERROR_DEVICE_ERROR); + return; + } else if (c == _delimiter) { + break; + } else if (_stop_tag->len && c == _stop_tag->tag[match_pos]) { + match_pos++; + if (match_pos == _stop_tag->len) { + _stop_tag->found = true; + break; + } + } else if (match_pos) { + match_pos = 0; + } + } + } + return; +} + +void ATHandler::skip_param(ssize_t len, uint32_t count) +{ + tr_debug("%s", __func__); + if (_last_err || !_stop_tag || _stop_tag->found) { + return; + } + + for (uint32_t i = 0; i < count; i++) { + ssize_t read_len = 0; + while (read_len < len) { + int c = get_char(); + if (c == -1) { + set_error(NSAPI_ERROR_DEVICE_ERROR); + return; + } + read_len++; + } + } + return; +} + +ssize_t ATHandler::read_bytes(uint8_t *buf, size_t len) +{ + tr_debug("%s", __func__); + if (_last_err) { + return -1; + } + + size_t read_len = 0; + for (; read_len < len; read_len++) { + int c = get_char(); + if (c == -1) { + set_error(NSAPI_ERROR_DEVICE_ERROR); + return -1; + } + buf[read_len] = c; + } + return read_len; +} + +ssize_t ATHandler::read_string(char *buf, size_t size, bool read_even_stop_tag) +{ + tr_debug("%s", __func__); + at_debug("\n----------read_string buff:----------\n"); + for (size_t i = _recv_pos; i < _recv_len; i++) { + at_debug("%c", _recv_buff[i]); + } + at_debug("\n----------buff----------\n"); + + if (_last_err || !_stop_tag || (_stop_tag->found && read_even_stop_tag == false)) { + return -1; + } + + uint8_t *pbuf = (uint8_t*)buf; + + size_t len = 0; + size_t match_pos = 0; + + consume_char('\"'); + + for (; len < (size + match_pos); len++) { + int c = get_char(); + if (c == -1) { + pbuf[len] = '\0'; + set_error(NSAPI_ERROR_DEVICE_ERROR); + return -1; + } else if (c == _delimiter) { + pbuf[len] = '\0'; + break; + } else if (c == '\"') { + match_pos = 0; + len--; + continue; + } else if (_stop_tag->len && c == _stop_tag->tag[match_pos]) { + match_pos++; + if (match_pos == _stop_tag->len) { + _stop_tag->found = true; + // remove tag from string if it was matched + len -= (_stop_tag->len - 1); + pbuf[len] = '\0'; + break; + } + } else if (match_pos) { + match_pos = 0; + } + + pbuf[len] = c; + } + + // Do we need _stop_found set after reading by size -> is _stop_tag_by_len needed or not? + return len; +} + +int32_t ATHandler::read_int() +{ + tr_debug("%s", __func__); + + if (_last_err || !_stop_tag || _stop_tag->found) { + return -1; + } + + char buff[BUFF_SIZE]; + char *first_no_digit; + + if (read_string(buff, (size_t)sizeof(buff)) == 0) { + return -1; + } + + return std::strtol(buff, &first_no_digit, 10); +} + +void ATHandler::set_delimiter(char delimiter) +{ + _delimiter = delimiter; +} + +void ATHandler::set_default_delimiter() +{ + _delimiter = DEFAULT_DELIMITER; +} + +void ATHandler::set_tag(tag_t* tag_dst, const char *tag_seq) +{ + if (tag_seq) { + size_t tag_len = strlen(tag_seq); + set_string(tag_dst->tag, tag_seq, tag_len); + tag_dst->len = tag_len; + tag_dst->found = false; + } else { + _stop_tag = NULL; + } +} + +void ATHandler::set_stop_tag(const char *stop_tag_seq) +{ + if (_last_err || !_stop_tag) { + return; + } + + set_tag(_stop_tag, stop_tag_seq); +} + +void ATHandler::set_scope(ScopeType scope_type) +{ + tr_debug("%s: %d", __func__, scope_type); + if (_current_scope != scope_type) { + _current_scope = scope_type; + switch (_current_scope) { + case RespType: + _stop_tag = &_resp_stop; + _stop_tag->found = false; + break; + case InfoType: + _stop_tag = &_info_stop; + _stop_tag->found = false; + consume_char(' '); + break; + case ElemType: + _stop_tag = &_elem_stop; + _stop_tag->found = false; + break; + case NotSet: + _stop_tag = NULL; + return; + default: + break; + } + } +} + +// should match from recv_pos? +bool ATHandler::match(const char* str, size_t size) +{ + tr_debug("%s: %s", __func__, str); + rewind_buffer(); + + if ((_recv_len - _recv_pos) < size) { + return false; + } + + if (str && memcmp(_recv_buff + _recv_pos, str, size) == 0) { + // consume matching part + _recv_pos += size; + return true; + } + return false; +} + +bool ATHandler::match_urc() +{ + tr_debug("%s", __func__); + rewind_buffer(); + size_t prefix_len = 0; + for (struct oob_t *oob = _oobs; oob; oob = oob->next) { + prefix_len = strlen(oob->prefix); + if (_recv_len >= prefix_len) { + if (match(oob->prefix, prefix_len)) { + tr_debug("URC! %s", oob->prefix); + set_scope(InfoType); + if (oob->cb) { + oob->cb(); + } + information_response_stop(); + return true; + } + } + } + return false; +} + +bool ATHandler::match_error() +{ + tr_debug("%s", __func__); + + if (match(CME_ERROR, CME_ERROR_LENGTH)) { + at_error(true, DeviceErrorTypeErrorCME); + return true; + } else if (match(CMS_ERROR, CMS_ERROR_LENGTH)) { + at_error(true, DeviceErrorTypeErrorCMS); + return true; + } else if (match(ERROR_, ERROR_LENGTH)) { + at_error(false, DeviceErrorTypeNoError); + return true; + } + + return false; +} + +void ATHandler::clear_error() +{ + _last_err = NSAPI_ERROR_OK; + _last_at_err.errCode = 0; + _last_at_err.errType = DeviceErrorTypeNoError; + _last_3gpp_error = 0; +} + +nsapi_error_t ATHandler::get_last_error() const +{ + return _last_err; +} + +device_err_t ATHandler::get_last_device_error() const +{ + return _last_at_err; +} + +void ATHandler::set_error(nsapi_error_t err) +{ + if (_last_err == NSAPI_ERROR_OK) { + _last_err = err; + } + + if (_last_err != err) { + tr_warn("AT error code changed from %d to %d!", _last_err, err); + } +} + +int ATHandler::get_3gpp_error() +{ + return _last_3gpp_error; +} + +void ATHandler::set_3gpp_error(int err, DeviceErrorType error_type) +{ + if (_last_3gpp_error) { // don't overwrite likely root cause error + return; + } + + if (error_type == DeviceErrorTypeErrorCMS && err < 128) { + // CMS errors 0-127 maps straight to 3GPP errors + _last_3gpp_error = err; + } else { + for (size_t i = 0; ifound = true; + return; + } + + if (match_error()) { + _error_found = true; + return; + } + + if (prefix && match(prefix, strlen(prefix))) { + _prefix_matched = true; + return; + } + + if (check_urc && match_urc()) { + _urc_matched = true; + } + + // If no match found, look for CRLF and consume everything up to and including CRLF + if (mem_str(_recv_buff, _recv_len, CRLF, CRLF_LENGTH)) { + // If no prefix, return on CRLF - means data to read + if (!prefix) { + return; + } + consume_to_tag(CRLF, true); + } else { + // If no prefix, no CRLF and no more chance to match for OK, ERROR or URC(since max resp length is already in buffer) + // return so data could be read + if (!prefix && ((_recv_len-_recv_pos) >= _max_resp_length)) { + return; + } + fill_buffer(); + } + } + + return; + // something went wrong so application need to recover and retry +} + +void ATHandler::resp_start(const char *prefix, bool stop) +{ + tr_debug("%s: %s", __func__, prefix); + + if (_last_err) { + return; + } + + // Try get as much data as possible + rewind_buffer(); + fill_buffer(); + + if (prefix) { + if ((strlen(prefix) < sizeof(_info_resp_prefix))) { + strcpy(_info_resp_prefix, prefix); + } else { + MBED_ASSERT(0); + } + } + + set_scope(RespType); + + resp(prefix, true); + + if (!stop && prefix && _prefix_matched) { + set_scope(InfoType); + } +} + +// check urc because of error as urc +bool ATHandler::info_resp() +{ + tr_debug("%s", __func__); + if (_last_err || _resp_stop.found) { + return false; + } + + if (_prefix_matched) { + _prefix_matched = false; + return true; + } + + // If coming here after another info response was started(looping), stop the previous one. + // Trying to handle stopping in this level instead of doing it in upper level. + if (get_scope() == InfoType) { + information_response_stop(); + } + + resp(_info_resp_prefix, false); + + if (_prefix_matched) { + set_scope(InfoType); + _prefix_matched = false; + return true; + } + + // On mismatch go to response scope + set_scope(RespType); + return false; +} + +bool ATHandler::info_elem(char start_tag) +{ + tr_debug("%s: %c", __func__, start_tag); + if (_last_err) { + return false; + } + + // If coming here after another info response element was started(looping), stop the previous one. + // Trying to handle stopping in this level instead of doing it in upper level. + if (get_scope() == ElemType) { + information_response_element_stop(); + } + + consume_char(_delimiter); + + if (consume_char(start_tag)) { + _prefix_matched = true; + set_scope(ElemType); + return true; + } + + // On mismatch go to information response scope + set_scope(InfoType); + return false; +} + +bool ATHandler::consume_char(char ch) +{ + tr_debug("%s: %c", __func__, ch); + int read_char = get_char(); + // If we read something else than ch, recover it + if (read_char != ch && read_char != -1) { + _recv_pos--; + return false; + } + return true; +} + +bool ATHandler::consume_to_tag(const char *tag, bool consume_tag) +{ + tr_debug("%s: %s", __func__, tag); + size_t match_pos = 0; + + while (true) { + int c = get_char(); + if (c == -1) { + break; + } else if (c == tag[match_pos]) { + match_pos++; + if (match_pos == strlen(tag)) { + if (!consume_tag) { + _recv_pos -= strlen(tag); + } + return true; + } + } else if (match_pos) { + match_pos = 0; + } + } + tr_error("consume_to_tag not found"); + return false; +} + +bool ATHandler::consume_to_stop_tag() +{ + tr_debug("%s", __func__); + + if (!_stop_tag || (_stop_tag && _stop_tag->found) || _error_found) { + return true; + } + + if (consume_to_tag((const char*)_stop_tag->tag, true)) { + return true; + } + + tr_error("consume_to_stop_tag not found"); + set_error(NSAPI_ERROR_DEVICE_ERROR); + return false; +} + +// consume by size needed? + +void ATHandler::resp_stop() +{ + // Do not return on error so that we can consume whatever there is in the buffer + + tr_debug("%s", __func__); + + if (_current_scope == ElemType) { + information_response_element_stop(); + set_scope(InfoType); + } + + if (_current_scope == InfoType) { + information_response_stop(); + } + + // Go for response stop_tag + if (consume_to_stop_tag()) { + set_scope(NotSet); + } + + // Restore stop tag to OK + set_tag(&_resp_stop, OK); + // Reset info resp prefix + memset(_info_resp_prefix, 0, sizeof(_info_resp_prefix)); +} + +void ATHandler::information_response_stop() +{ + tr_debug("%s", __func__); + if (consume_to_stop_tag()) { + set_scope(RespType); + } +} + +void ATHandler::information_response_element_stop() +{ + tr_debug("%s", __func__); + if (consume_to_stop_tag()) { + set_scope(InfoType); + } +} + +ATHandler::ScopeType ATHandler::get_scope() +{ + return _current_scope; +} + +void ATHandler::set_string(char *dest, const char *src, size_t src_len) +{ + memcpy(dest, src, src_len); + dest[src_len] = '\0'; +} + +const char* ATHandler::mem_str(const char* dest, size_t dest_len, const char* src, size_t src_len) +{ + if (dest_len > src_len) { + for(size_t i = 0; i < dest_len-src_len+1; ++i) { + if(memcmp(dest+i, src, src_len) == 0) { + return dest+i; + } + } + } + return NULL; +} + +void ATHandler::cmd_start(const char* cmd) +{ + tr_debug("AT> %s", cmd); + + if (_last_err != NSAPI_ERROR_OK) { + return; + } + + // write command + for (size_t i = 0; i < strlen(cmd); i++) { + if (write_char(cmd[i]) == false) { + // writing failed ---> write_char have set the last error, return... + return; + } + } + + _cmd_start = true; +} + +void ATHandler::write_int(int32_t param) +{ + tr_debug("write_int: %d", param); + // do common checks before sending subparameter + if (check_cmd_send() == false) { + return; + } + + // write the integer subparameter + const int32_t str_len = 12; + char number_string[str_len]; + int32_t result = sprintf(number_string, "%ld", param); + if (result > 0 && result < str_len) { + for (size_t i = 0; number_string[i]; i++) { + if (write_char(number_string[i]) == false) { + // writing failed ---> write_char have set the last error, break out + break; + } + } + } +} + +void ATHandler::write_string(const char* param, bool useQuotations) +{ + tr_debug("write_string: %s, %d", param, useQuotations); + // do common checks before sending subparameter + if (check_cmd_send() == false) { + return; + } + + // we are writing string, surround it with quotes + if (useQuotations && write_char('\"') == false) { + return; + } + + for (size_t i = 0; i < strlen(param); i++) { + if (write_char(param[i]) == false) { + // writing failed ---> write_char have set the last error, return + break; + } + } + + if (useQuotations) { + // we are writing string, surround it with quotes + write_char('\"'); + } +} + +void ATHandler::cmd_stop() +{ + if (_last_err != NSAPI_ERROR_OK) { + return; + } + // Finish with CR + for (size_t i = 0; i < _output_delimiter_length; i++) { + if (write_char(_output_delimiter[i]) == false) { + break; + } + } +} + +size_t ATHandler::write_bytes(const uint8_t *data, size_t len) +{ + if (_last_err != NSAPI_ERROR_OK) { + return 0; + } + + size_t i = 0; + for (; i < len; i++) { + if (write_char(data[i]) == false) { + // writing failed ---> write_char have set the last error, return + break; + } + } + + return i; +} + +bool ATHandler::write_char(char c) +{ + pollfh fhs; + fhs.fh = _fileHandle; + fhs.events = POLLOUT; + bool retVal = true; + + int count = poll(&fhs, 1, _at_timeout); + if (count > 0 && (fhs.revents & POLLOUT)) { + retVal = _fileHandle->write(&c, 1) == 1 ? true : false; + } else { + retVal = false; + } + + if (retVal == false) { + set_error(NSAPI_ERROR_DEVICE_ERROR); + } + + return retVal; +} + +// do common checks before sending subparameters +bool ATHandler::check_cmd_send() +{ + if (_last_err != NSAPI_ERROR_OK) { + return false; + } + + // Don't write delimiter if this is the first subparameter + if (_cmd_start) { + _cmd_start = false; + } else { + if (write_char(_delimiter) == false) { + // writing of delimiter failed, return. write_char already have set the _last_err + return false; + } + } + + return true; +} + +void ATHandler::flush() +{ + while (_fileHandle->readable()) { + reset_buffer(); + fill_buffer(); + } + reset_buffer(); +} diff --git a/features/cellular/framework/AT/ATHandler.h b/features/cellular/framework/AT/ATHandler.h new file mode 100644 index 0000000000..accabe5c79 --- /dev/null +++ b/features/cellular/framework/AT/ATHandler.h @@ -0,0 +1,474 @@ +/* + * Copyright (c) 2017, 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 AT_HANDLER_H_ +#define AT_HANDLER_H_ + +#include "platform/mbed_retarget.h" +#include "stdio.h" + +#include "EventQueue.h" +#include "PlatformMutex.h" +#include "nsapi_types.h" + +#include "PlatformMutex.h" +#include "Callback.h" +#include "EventQueue.h" + +namespace mbed { + +class FileHandle; + +/** + * If application calls associated FileHandle only from single thread context + * then locking between AT command and response is not needed. However, + * note that many cellular functions are called indirectly, for example with the socket API. + * If you are unsure, then AT_HANDLER_MUTEX must be defined. + */ +#define AT_HANDLER_MUTEX + +extern const char *OK; +extern const char *CRLF; + +#define BUFF_SIZE 16 + +/* AT Error types enumeration */ +enum DeviceErrorType { + DeviceErrorTypeNoError = 0, + DeviceErrorTypeError, // AT ERROR + DeviceErrorTypeErrorCMS, // AT ERROR CMS + DeviceErrorTypeErrorCME // AT ERROR CME +}; + +/* struct used when getting at response error. Defines error code and type */ +struct device_err_t { + DeviceErrorType errType; + int errCode; +}; + +/** Class ATHandler + * + * Class for sending AT commands and parsing AT responses. + */ +class ATHandler +{ + +public: + /** Constructor + * + * @param fh file handle used for reading AT responses and writing AT commands + * @param queue Event queue used to transfer sigio events to this thread + * @param timeout Timeout when reading for AT response + * @param output_delimiter delimiter used when parsing at responses, "\r" should be used as output_delimiter + */ + ATHandler(FileHandle *fh, events::EventQueue &queue, int timeout, const char *output_delimiter); + ~ATHandler(); + + /** Return used file handle. + * + * @return used file handle + */ + FileHandle *get_file_handle(); + + /** Set file handle, which is used for reading AT responses and writing AT commands + * + * @param fh file handle used for reading AT responses and writing AT commands + */ + void set_file_handle(FileHandle *fh); + + /** Locks the mutex for file handle if AT_HANDLER_MUTEX is defined. + */ + void lock(); + + /** Unlocks the mutex for file handle if AT_HANDLER_MUTEX is defined. + */ + void unlock(); + + /** Locks the mutex for file handle if AT_HANDLER_MUTEX is defined and returns the last error. + * + * @return last error that happened when parsing AT responses + */ + nsapi_error_t unlock_return_error(); + + /** Set the urc callback for urc. If urc is found when parsing AT responses, then call if called. + * + * @param prefix Register urc prefix for callback. Urc could be for example "+CMTI: " + * @param callback Callback, which is called if urc is found in AT response + */ + void set_urc_handler(const char *prefix, mbed::Callback callback); + + ATHandler *_nextATHandler; // linked list + + /** returns the last error while parsing AT responses. + * + * @return last error + */ + nsapi_error_t get_last_error() const; + + /** returns the last device error while parsing AT responses. Actually AT error (CME/CMS). + * + * @return last error struct device_err_t + */ + device_err_t get_last_device_error() const; + + /** Increase reference count. Used for counting references to this instance. + */ + void inc_ref_count(); + + /** Decrease reference count. Used for counting references to this instance. + */ + void dec_ref_count(); + + /** Get the current reference count. Used for counting references to this instance. + * + * @return current reference count + */ + int get_ref_count(); + + /** Set timeout in milliseconds for AT commands + * + * @param timeout_milliseconds Timeout in milliseconds + * @param default_timeout Store as default timeout + */ + void set_at_timeout(uint32_t timeout_milliseconds, bool default_timeout = false); + + /** Restore timeout to previous timeout. Handy if there is a need to change timeout temporarily. + */ + void restore_at_timeout(); + + /** Clear pending error flag. By default, error is cleared only in lock(). + */ + void clear_error(); + + /** Tries to find oob's from the AT response. Call the urc callback if one is found. + */ + void process_oob(); + + /** Set sigio for the current file handle. Sigio event goes through eventqueue so that it's handled in current thread. + */ + void set_filehandle_sigio(); + + /** + * Flushes the underlying stream + */ + void flush(); + +protected: + void event(); +#ifdef AT_HANDLER_MUTEX + PlatformMutex _fileHandleMutex; +#endif + FileHandle *_fileHandle; +private: + + void set_error(nsapi_error_t err); + + events::EventQueue &_queue; + nsapi_error_t _last_err; + int _last_3gpp_error; + device_err_t _last_at_err; + uint16_t _oob_string_max_length; + char *_output_delimiter; + uint8_t _output_delimiter_length; + + struct oob_t { + bool matching_to_received; + const char *prefix; + mbed::Callback cb; + oob_t *next; + }; + oob_t *_oobs; + bool _response_terminated; + uint32_t _at_timeout; + uint32_t _previous_at_timeout; + + bool _fh_sigio_set; + + bool _processing; + int32_t _ref_count; + + //************************************* +public: + + /** Starts the command writing by clearing the last error and writing the given command. + * In case of failure when writing, the last error is set to NSAPI_ERROR_DEVICE_ERROR. + * + * @param cmd AT command to be written to modem + */ + void cmd_start(const char* cmd); + + /** Writes integer type AT command subparameter. Starts with the delimiter if not the first param after cmd_start. + * In case of failure when writing, the last error is set to NSAPI_ERROR_DEVICE_ERROR. + * + * @param param int to be written to modem as AT command subparameter + */ + void write_int(int32_t param); + + /** Writes string type AT command subparamater. Quotes are added to surround the given string. + * Starts with the delimiter if not the first param after cmd_start. + * In case of failure when writing, the last error is set to NSAPI_ERROR_DEVICE_ERROR. + * + * @param param string to be written to modem as AT command subparameter + * @param useQuotations flag indicating whether the string should be included in quotation marks + */ + void write_string(const char* param, bool useQuotations = true); + + /** Stops the AT command by writing command-line terminator CR to mark command as finished. + */ + void cmd_stop(); + + /** Write bytes without any subparameter delimiters, such as comma. + * In case of failure when writing, the last error is set to NSAPI_ERROR_DEVICE_ERROR. + * + * @param data bytes to be written to modem + * @param len length of data string + * + * @return number of characters successfully written + */ + size_t write_bytes(const uint8_t *data, size_t len); + + /** Sets the stop tag for the current scope (response/information response/element) + * Parameter's reading routines will stop the reading when such tag is found and will set the found flag. + * Consume routines will read everything until such tag is found. + * + * @param stop_tag_seq string to be set as stop tag + */ + void set_stop_tag(const char *stop_tag_seq); + + /** Sets the delimiter between parameters or between elements of the information response. + * Parameter's reading routines will stop when such char is read. + * + * @param delimiter char to be set as _delimiter + */ + void set_delimiter(char delimiter); + + /** Sets the delimiter to default value defined by DEFAULT_DELIMITER. + */ + void set_default_delimiter(); + + /** Consumes the reading buffer up to the delimiter or stop_tag + * + * @param count number of parameters to be skipped + */ + void skip_param(uint32_t count = 1); + + /** Consumes the given length from the reading buffer + * + * @param len length to be consumed from reading buffer + * @param count number of parameters to be skipped + */ + void skip_param(ssize_t len, uint32_t count); + + /** Reads given number of bytes from receiving buffer without checking any subparameter delimiters, such as comma. + * + * @param buf output buffer for the read + * @param len maximum number of bytes to read + * @return number of successfully read bytes or -1 in case of error + */ + ssize_t read_bytes(uint8_t *buf, size_t len); + + /** Reads chars from reading buffer. Terminates with null. Skips the quotation marks. + * Stops on delimiter or stop tag. + * + * @param str output buffer for the read + * @param size maximum number of chars to output + * @param read_even_stop_tag if true then try to read even if the stop tag was found previously + * @return length of output string or -1 in case of read timeout before delimiter or stop tag is found + */ + ssize_t read_string(char *str, size_t size, bool read_even_stop_tag = false); + + /** Reads as string and converts result to integer. Supports only positive integers. + * + * @return the positive integer or -1 in case of error. + */ + int32_t read_int(); + + /** This looks for necessary matches: prefix, OK, ERROR, URCs and sets the correct scope. + * + * @param prefix string to be matched from receiving buffer. If not NULL and match succeeds, then scope + * will be set as information response(info_type) + * @param stop flag to indicate if we go to information response scope or not. + * (needed when nothing is expected to be received anymore after the prefix match: + * sms case: "> ", bc95 reboot case) + */ + void resp_start(const char *prefix = NULL, bool stop = false); + + /** Ends all scopes starting from current scope. + * Consumes everything until the scope's stop tag is found, then + * goes to next scope until response scope is ending. + * Possible sequence: + * element scope -> information response scope -> response scope + */ + void resp_stop(); + + /** Looks for matching the prefix given to resp_start() call. + * If needed, it ends the scope of a previous information response. + * Sets the information response scope if new prefix is found and response scope if prefix is not found. + * + * @return true if new information response is found, false otherwise + */ + bool info_resp(); + + /** Looks for matching the start tag. + * If needed, it ends the scope of a previous element. + * Sets the element scope if start tag is found and information response scope if start tag is not found. + * + * @param start_tag tag to be matched to begin parsing an element of an information response + * @return true if new element is found, false otherwise + */ + bool info_elem(char start_tag); + + /** Consumes the received content until current stop tag is found. + * + * @return true if stop tag is found, false otherwise + */ + bool consume_to_stop_tag(); + + /** Sets _debug_on flag. + * + * @param enable value to be set for _debug_on flag + */ + void enable_debug(bool enable); + + /** Return the last 3GPP error code. + * @return last 3GPP error code + */ + int get_3gpp_error(); + +private: + + // should fit any prefix and int + char _recv_buff[BUFF_SIZE]; + // reading position + size_t _recv_len; + // reading length + size_t _recv_pos; + + // resp_type: the part of the response that doesn't include the information response (+CMD1,+CMD2..) + // ends with OK or (CME)(CMS)ERROR + // info_type: the information response part of the response: starts with +CMD1 and ends with CRLF + // information response contains parameters or subsets of parameters (elements), both separated by comma + // elem_type: subsets of parameters that are part of information response, its parameters are separated by comma + enum ScopeType {RespType, InfoType, ElemType, NotSet}; + void set_scope(ScopeType scope_type); + ScopeType _current_scope; + + struct tag_t { + char tag[7]; + size_t len; + bool found; + }; + + // tag to stop response scope + tag_t _resp_stop; + // tag to stop information response scope + tag_t _info_stop; + // tag to stop element scope + tag_t _elem_stop; + // reference to the stop tag of current scope (resp/info/elem) + tag_t *_stop_tag; + + // delimiter between parameters and also used for delimiting elements of information response + char _delimiter; + // set true on prefix match -> indicates start of an information response or of an element + bool _prefix_matched; + // set true on urc match + bool _urc_matched; + // set true on (CME)(CMS)ERROR + bool _error_found; + // Max length of OK,(CME)(CMS)ERROR and URCs + size_t _max_resp_length; + + // prefix set during resp_start and used to try matching possible information responses + char _info_resp_prefix[BUFF_SIZE]; + bool _debug_on; + bool _cmd_start; + + // Gets char from receiving buffer. + // Resets and fills the buffer if all are already read (receiving position equals receiving length). + int get_char(); + // Sets to 0 the reading position, reading length and the whole buffer content. + void reset_buffer(); + // Reading position set to 0 and buffer's unread content moved to beginning + void rewind_buffer(); + // Reads from serial to receiving buffer. + // Returns on first successful read OR on timeout. + void fill_buffer(); + + void set_tag(tag_t* tag_dest, const char *tag_seq); + + // Rewinds the receiving buffer and compares it against given str. + bool match(const char* str, size_t size); + // Iterates URCs and checks if they match the receiving buffer content. + // If URC match sets the scope to information response and after urc's cb returns + // finishes the information response scope(consumes to CRLF). + bool match_urc(); + // Checks if any of the error strings are matching the receiving buffer content. + bool match_error(); + // Checks if current char in buffer matches ch and consumes it, + // if no match lets the buffer unchanged. + bool consume_char(char ch); + // Consumes the received content until tag is found. + // Consumes the tag only if consume_tag flag is true. + bool consume_to_tag(const char *tag, bool consume_tag); + // Checks if receiving buffer contains OK, ERROR, URC or given prefix. + void resp(const char *prefix, bool check_urc); + + + ScopeType get_scope(); + + // Consumes to information response stop tag which is CRLF. Sets scope to response. + void information_response_stop(); + // Consumes to element stop tag. Sets scope to information response + void information_response_element_stop(); + + // Reads the error code if expected and sets it as last error. + void at_error(bool error_code, DeviceErrorType error_type); + + /** Convert AT error code to 3GPP error codes + * @param err AT error code read from CME/CMS ERROR responses + * @param error_type error type (CMS/CME/ERROR) + */ + void set_3gpp_error(int err, DeviceErrorType error_type); + + bool check_cmd_send(); + bool write_char(char c); + + /** Copy content of one char buffer to another buffer and sets NULL terminator + * + * @param dest destination char buffer + * @param src source char buffer + * @param src_len number of bytes to copy + * + */ + void set_string(char *dest, const char *src, size_t src_len); + + /** Finds occurrence of one char buffer inside another char buffer. + * + * @param dest destination char buffer + * @param dest_len length of dest + * @param src string to be searched for + * @param src_len length of string to be searched for + * + * @return pointer to first occurrence of src in dest + */ + const char* mem_str(const char* dest, size_t dest_len, const char* src, size_t src_len); +}; + +} // namespace mbed + +#endif //AT_HANDLER_H_ diff --git a/features/cellular/framework/AT/AT_CellularBase.cpp b/features/cellular/framework/AT/AT_CellularBase.cpp new file mode 100644 index 0000000000..c4e5183c68 --- /dev/null +++ b/features/cellular/framework/AT/AT_CellularBase.cpp @@ -0,0 +1,36 @@ +/* + * Copyright (c) 2017, 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 "AT_CellularBase.h" + +using namespace mbed; + +AT_CellularBase::AT_CellularBase(ATHandler& at) : _at(at) +{ + +} + +ATHandler& AT_CellularBase::get_at_handler() +{ + return _at; +} + +device_err_t AT_CellularBase::get_device_error() const +{ + return _at.get_last_device_error(); +} + diff --git a/features/cellular/framework/AT/AT_CellularBase.h b/features/cellular/framework/AT/AT_CellularBase.h new file mode 100644 index 0000000000..97416cc7c2 --- /dev/null +++ b/features/cellular/framework/AT/AT_CellularBase.h @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2017, 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 AT_CELLULAR_BASE_H_ +#define AT_CELLULAR_BASE_H_ + +#include "ATHandler.h" + +namespace mbed { + +/** + * Class AT_CellularBase + * + * A base class for AT-classes. + */ +class AT_CellularBase +{ +public: + AT_CellularBase(ATHandler& at); + + /** Getter for at handler. Common method for all AT-classes. + * + * @return reference to ATHandler + */ + ATHandler& get_at_handler(); + + /** Gets the device error that happened when using AT commands/responses. This is at error + * returned by the device. Returned CME/CMS errors can be found from 3gpp documents 27007 and 27005. + * + * @return at error (CME/CMS) while communicating with the device + */ + device_err_t get_device_error() const; + +protected: + ATHandler& _at; +}; + +} // namespace mbed + +#endif /* AT_CELLULAR_BASE_H_ */ diff --git a/features/cellular/framework/AT/AT_CellularDevice.cpp b/features/cellular/framework/AT/AT_CellularDevice.cpp new file mode 100644 index 0000000000..6eb88d9485 --- /dev/null +++ b/features/cellular/framework/AT/AT_CellularDevice.cpp @@ -0,0 +1,245 @@ +/* + * Copyright (c) 2017, 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 "AT_CellularDevice.h" + +using namespace events; +using namespace mbed; + +#define DEFAULT_AT_TIMEOUT 1000 // at default timeout in milliseconds + +AT_CellularDevice::AT_CellularDevice(EventQueue &queue) : + _atHandlers(0), _network(0), _sms(0), _sim(0), _power(0), _information(0), _queue(queue), + _default_timeout(DEFAULT_AT_TIMEOUT), _modem_debug_on(false) +{ +} + +AT_CellularDevice::~AT_CellularDevice() +{ + close_network(); + close_sms(); + close_power(); + close_sim(); + close_information(); + + ATHandler *atHandler = _atHandlers; + while (atHandler) { + ATHandler *old = atHandler; + atHandler = atHandler->_nextATHandler; + delete old; + old = NULL; + } +} + +// each parser is associated with one filehandle (that is UART) +ATHandler* AT_CellularDevice::get_at_handler(FileHandle *fileHandle) +{ + if (!fileHandle) { + return NULL; + } + ATHandler *atHandler = _atHandlers; + while (atHandler) { + if (atHandler->get_file_handle() == fileHandle) { + atHandler->inc_ref_count(); + return atHandler; + } + atHandler = atHandler->_nextATHandler; + } + + atHandler = new ATHandler(fileHandle, _queue, _default_timeout, "\r"); + if (atHandler) { + if (_modem_debug_on) { + atHandler->enable_debug(_modem_debug_on); + } + atHandler->_nextATHandler = _atHandlers; + _atHandlers = atHandler; + } + + return atHandler; +} + +void AT_CellularDevice::release_at_handler(ATHandler* at_handler) +{ + if (!at_handler) { + return; + } + at_handler->dec_ref_count(); + if (at_handler->get_ref_count() == 0) { + // we can delete this at_handler + ATHandler *atHandler = _atHandlers; + ATHandler *prev = NULL; + while (atHandler) { + if (atHandler == at_handler) { + if (prev == NULL) { + _atHandlers = _atHandlers->_nextATHandler; + } else { + prev->_nextATHandler = atHandler->_nextATHandler; + } + delete atHandler; + atHandler = NULL; + break; + } else { + prev = atHandler; + atHandler =atHandler->_nextATHandler; + } + } + } +} + +CellularNetwork *AT_CellularDevice::open_network(FileHandle *fh) +{ + if (!_network) { + ATHandler *atHandler = get_at_handler(fh); + if (atHandler) { + _network = new AT_CellularNetwork(*atHandler); + if (!_network) { + release_at_handler(atHandler); + } + } + } + return _network; +} + +CellularSMS *AT_CellularDevice::open_sms(FileHandle *fh) +{ + if (!_sms) { + ATHandler *atHandler = get_at_handler(fh); + if (atHandler) { + _sms = new AT_CellularSMS(*atHandler); + if (!_sms) { + release_at_handler(atHandler); + } + } + } + return _sms; +} + +CellularSIM *AT_CellularDevice::open_sim(FileHandle *fh) +{ + if (!_sim) { + ATHandler *atHandler = get_at_handler(fh); + if (atHandler) { + _sim = new AT_CellularSIM(*atHandler); + if (!_sim) { + release_at_handler(atHandler); + } + } + } + return _sim; +} + +CellularPower *AT_CellularDevice::open_power(FileHandle *fh) +{ + if (!_power) { + ATHandler *atHandler = get_at_handler(fh); + if (atHandler) { + _power = new AT_CellularPower(*atHandler); + if (!_power) { + release_at_handler(atHandler); + } + } + } + return _power; +} + +CellularInformation *AT_CellularDevice::open_information(FileHandle *fh) +{ + if (!_information) { + ATHandler *atHandler = get_at_handler(fh); + if (atHandler) { + _information = new AT_CellularInformation(*atHandler); + if (!_information) { + release_at_handler(atHandler); + } + } + } + return _information; +} + +void AT_CellularDevice::close_network() +{ + if (_network) { + release_at_handler(&_network->get_at_handler()); + delete _network; + _network = NULL; + } +} + +void AT_CellularDevice::close_sms() +{ + if (_sms) { + release_at_handler(&_sms->get_at_handler()); + delete _sms; + _sms = NULL; + } +} +void AT_CellularDevice::close_power() +{ + if (_power) { + release_at_handler(&_power->get_at_handler()); + delete _power; + _power = NULL; + } +} + +void AT_CellularDevice::close_sim() +{ + if (_sim) { + release_at_handler(&_sim->get_at_handler()); + delete _sim; + _sim = NULL; + } +} + +void AT_CellularDevice::close_information() +{ + if (_information) { + release_at_handler(&_information->get_at_handler()); + delete _information; + _information = NULL; + } +} + +void AT_CellularDevice::set_timeout(int timeout) +{ + _default_timeout = timeout; + + ATHandler *atHandler = _atHandlers; + while (atHandler) { + atHandler->set_at_timeout(_default_timeout, true); // set as default timeout + atHandler = atHandler->_nextATHandler; + } +} + +void AT_CellularDevice::modem_debug_on(bool on) +{ + _modem_debug_on = on; + + ATHandler *atHandler = _atHandlers; + while (atHandler) { + atHandler->enable_debug(_modem_debug_on); + atHandler = atHandler->_nextATHandler; + } +} + +NetworkStack *AT_CellularDevice::get_stack() +{ + if (!_network) { + return NULL; + } + return _network->get_stack(); +} diff --git a/features/cellular/framework/AT/AT_CellularDevice.h b/features/cellular/framework/AT/AT_CellularDevice.h new file mode 100644 index 0000000000..a2d1171469 --- /dev/null +++ b/features/cellular/framework/AT/AT_CellularDevice.h @@ -0,0 +1,98 @@ +/* + * Copyright (c) 2017, 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 AT_CELLULAR_DEVICE_H_ +#define AT_CELLULAR_DEVICE_H_ + +#include "CellularDevice.h" + +#include "AT_CellularNetwork.h" +#include "AT_CellularSIM.h" +#include "AT_CellularSMS.h" +#include "AT_CellularPower.h" +#include "AT_CellularInformation.h" + +#include "ATHandler.h" + +namespace mbed +{ + +/** + * Class AT_CellularDevice + * + * A class defines opening and closing of cellular interfaces. + * Deleting/Closing of opened interfaces can be done only through this class. + */ +class AT_CellularDevice : public CellularDevice +{ +public: + AT_CellularDevice(events::EventQueue &queue); + virtual ~AT_CellularDevice(); + +protected: + ATHandler *_atHandlers; + + ATHandler *get_at_handler(FileHandle *fh); + + /** Releases the given at_handler. If last reference to at_hander then it's deleted. + * + * @param at_handler + */ + void release_at_handler(ATHandler* at_handler); + +public: // CellularDevice + virtual CellularNetwork *open_network(FileHandle *fh); + + virtual CellularSMS *open_sms(FileHandle *fh); + + virtual CellularPower *open_power(FileHandle *fh); + + virtual CellularSIM *open_sim(FileHandle *fh); + + virtual CellularInformation *open_information(FileHandle *fh); + + virtual void close_network(); + + virtual void close_sms(); + + virtual void close_power(); + + virtual void close_sim(); + + virtual void close_information(); + + virtual void set_timeout(int timeout); + + virtual void modem_debug_on(bool on); + + virtual NetworkStack *get_stack(); + +protected: + AT_CellularNetwork *_network; + AT_CellularSMS *_sms; + AT_CellularSIM *_sim; + AT_CellularPower* _power; + AT_CellularInformation* _information; + +protected: + events::EventQueue &_queue; + int _default_timeout; + bool _modem_debug_on; +}; + +} // namespace mbed +#endif // AT_CELLULAR_DEVICE_H_ diff --git a/features/cellular/framework/AT/AT_CellularInformation.cpp b/features/cellular/framework/AT/AT_CellularInformation.cpp new file mode 100644 index 0000000000..b588294798 --- /dev/null +++ b/features/cellular/framework/AT/AT_CellularInformation.cpp @@ -0,0 +1,58 @@ +/* + * 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 "AT_CellularInformation.h" + +using namespace mbed; + +AT_CellularInformation::AT_CellularInformation(ATHandler &at) : AT_CellularBase(at) +{ +} + +AT_CellularInformation::~AT_CellularInformation() +{ +} + +nsapi_error_t AT_CellularInformation::get_manufacturer(char *buf, size_t buf_size) +{ + return get_info("AT+CGMI", buf, buf_size); +} + +nsapi_error_t AT_CellularInformation::get_model(char *buf, size_t buf_size) +{ + return get_info("AT+CGMM", buf, buf_size); +} + +nsapi_error_t AT_CellularInformation::get_revision(char *buf, size_t buf_size) +{ + return get_info("AT+CGMR", buf, buf_size); +} + +nsapi_error_t AT_CellularInformation::get_info(const char *cmd, char *buf, size_t buf_size) +{ + _at.lock(); + + _at.cmd_start(cmd); + _at.cmd_stop(); + _at.set_delimiter(0); + _at.resp_start(); + _at.read_string(buf, buf_size-1); + _at.resp_stop(); + _at.set_default_delimiter(); + + return _at.unlock_return_error(); +} diff --git a/features/cellular/framework/AT/AT_CellularInformation.h b/features/cellular/framework/AT/AT_CellularInformation.h new file mode 100644 index 0000000000..04fe4255df --- /dev/null +++ b/features/cellular/framework/AT/AT_CellularInformation.h @@ -0,0 +1,57 @@ +/* + * 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. + */ + +#ifndef AT_CELLULAR_INFORMATION_H_ +#define AT_CELLULAR_INFORMATION_H_ + +#include "CellularInformation.h" +#include "AT_CellularBase.h" + +namespace mbed { + +/** + * Class AT_CellularInformation + * + * Class that provides information about cellular device. + */ +class AT_CellularInformation : public CellularInformation, public AT_CellularBase +{ +public: + AT_CellularInformation(ATHandler &atHandler); + virtual ~AT_CellularInformation(); + +public: + virtual nsapi_size_or_error_t get_manufacturer(char *buf, size_t buf_size); + + virtual nsapi_size_or_error_t get_model(char *buf, size_t buf_size); + + virtual nsapi_size_or_error_t get_revision(char *buf, size_t buf_size); + +protected: + /** Request information text from cellular device + * + * @param cmd 3gpp command string + * @param buf manufacturer identification + * @param buf_size max length of manufacturer identification is 2048 characters + * @return on success read character count, on failure negative error code + */ + nsapi_error_t get_info(const char *cmd, char *buf, size_t buf_size); +}; + +} // namespace mbed + +#endif // AT_CELLULAR_INFORMATION_H_ diff --git a/features/cellular/framework/AT/AT_CellularNetwork.cpp b/features/cellular/framework/AT/AT_CellularNetwork.cpp new file mode 100644 index 0000000000..5c05d35e1f --- /dev/null +++ b/features/cellular/framework/AT/AT_CellularNetwork.cpp @@ -0,0 +1,1072 @@ +/* + * Copyright (c) 2017, 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 +#include "AT_CellularNetwork.h" +#include "nsapi_ppp.h" +#include "CellularUtil.h" +#include "CellularLog.h" + +using namespace std; +using namespace mbed_cellular_util; +using namespace mbed; + +struct at_reg_t { + const CellularNetwork::RegistrationType type; + const char *const cmd; +}; + +static const at_reg_t at_reg[] = { + { CellularNetwork::C_EREG, "AT+CEREG" }, + { CellularNetwork::C_GREG, "AT+CGREG" }, + { CellularNetwork::C_REG, "AT+CREG" }, +}; + +AT_CellularNetwork::AT_CellularNetwork(ATHandler &atHandler) : AT_CellularBase(atHandler), + _stack(NULL), _apn(NULL), _uname(NULL), _pwd(NULL), _ip_stack_type_requested(DEFAULT_STACK), _ip_stack_type(DEFAULT_STACK), _cid(-1), + _connection_status_cb(NULL), _op_act(operator_t::RAT_UNKNOWN), _authentication_type(CHAP), _last_reg_type(C_REG), + _connect_status(NSAPI_STATUS_DISCONNECTED), _new_context_set(false) +{ + + _at.set_urc_handler("NO CARRIER", callback(this, &AT_CellularNetwork::urc_no_carrier)); +} + +AT_CellularNetwork::~AT_CellularNetwork() +{ + free_credentials(); +} + +void AT_CellularNetwork::free_credentials() +{ + if (_uname) { + free(_uname); + } + + if (_pwd) { + free(_pwd); + } + + if (_apn) { + free(_apn); + } +} + +void AT_CellularNetwork::urc_no_carrier() +{ + _connect_status = NSAPI_STATUS_DISCONNECTED; + if (_connection_status_cb) { + _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED); + } +} + +nsapi_error_t AT_CellularNetwork::set_credentials(const char *apn, + const char *username, const char *password) +{ + size_t len; + if (apn && (len = strlen(apn)) > 0) { + _apn = (char*)malloc(len*sizeof(char)+1); + if (_apn) { + memcpy(_apn, apn, len+1); + } else { + return NSAPI_ERROR_NO_MEMORY; + } + } + + if (username && (len = strlen(username)) > 0) { + _uname = (char*)malloc(len*sizeof(char)+1); + if (_uname) { + memcpy(_uname, username, len+1); + } else { + return NSAPI_ERROR_NO_MEMORY; + } + } + + if (password && (len = strlen(password)) > 0) { + _pwd = (char*)malloc(len*sizeof(char)+1); + if (_pwd) { + memcpy(_pwd, password, len+1); + } else { + return NSAPI_ERROR_NO_MEMORY; + } + } + + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularNetwork::set_credentials(const char *apn, + AuthenticationType type, const char *username, const char *password) +{ + nsapi_error_t err = set_credentials(apn, username, password); + if (err) { + return err; + } + + _authentication_type = type; + + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularNetwork::connect(const char *apn, + const char *username, const char *password) +{ + nsapi_error_t err = set_credentials(apn, username, password); + if (err) { + return err; + } + + return connect(); +} + +nsapi_error_t AT_CellularNetwork::delete_current_context() +{ + _at.clear_error(); + _at.cmd_start("AT+CGDCONT="); + _at.write_int(_cid); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + + if (_at.get_last_error() == NSAPI_ERROR_OK) { + _cid = -1; + _new_context_set = false; + } + + return _at.get_last_error(); +} + +nsapi_error_t AT_CellularNetwork::connect() +{ + _at.lock(); + + _connect_status = NSAPI_STATUS_CONNECTING; + if (_connection_status_cb) { + _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_CONNECTING); + } + + nsapi_error_t err = set_context_to_be_activated(); + if (err != NSAPI_ERROR_OK) { + _at.unlock(); + tr_error("Failed to activate network context!"); + + _connect_status = NSAPI_STATUS_DISCONNECTED; + if (_connection_status_cb) { + _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED); + } + + return err; + } + + err = open_data_channel(); + if (err != NSAPI_ERROR_OK) { + + // If new PDP context was created and failed to activate, delete it + if (_new_context_set) { + delete_current_context(); + } + + _at.unlock(); + + tr_error("Failed to open data channel!"); + + _connect_status = NSAPI_STATUS_DISCONNECTED; + if (_connection_status_cb) { + _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED); + } + + return err; + } + + _at.unlock(); + +#if !NSAPI_PPP_AVAILABLE + _connect_status = NSAPI_STATUS_GLOBAL_UP; + if (_connection_status_cb) { + _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_GLOBAL_UP); + } +#endif + + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularNetwork::open_data_channel() +{ + //old way: _at.send("ATD*99***%d#", _cid) && _at.recv("CONNECT"); + nsapi_error_t err = NSAPI_ERROR_NO_CONNECTION; +#if NSAPI_PPP_AVAILABLE + tr_info("Open data channel in PPP mode"); + _at.cmd_start("AT+CGDATA=\"PPP\","); + _at.write_int(_cid); + _at.cmd_stop(); + + _at.resp_start("CONNECT", true); + if (_at.get_last_error()) { + tr_warn("Failed to CONNECT"); + } + /* Initialize PPP + * mbed_ppp_init() is a blocking call, it will block until + * connected, or timeout after 30 seconds*/ + err = nsapi_ppp_connect(_at.get_file_handle(), callback(this, &AT_CellularNetwork::ppp_status_cb), _uname, _pwd, _ip_stack_type); +#else + // do check for stack to validate that we have support for stack + _stack = get_stack(); + if (!_stack) { + return err; + } + + bool is_context_active = false; + _at.cmd_start("AT+CGACT?"); + _at.cmd_stop(); + _at.resp_start("+CGACT:"); + while (_at.info_resp()) { + int context_id = _at.read_int(); + int context_activation_state = _at.read_int(); + if (context_id == _cid && context_activation_state == 1) { + is_context_active = true; + } + } + _at.resp_stop(); + + if (!is_context_active) { + tr_info("Activate PDP context"); + _at.cmd_start("AT+CGACT=1,"); + _at.write_int(_cid); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + } + + err = (_at.get_last_error() == NSAPI_ERROR_OK) ? NSAPI_ERROR_OK : NSAPI_ERROR_NO_CONNECTION; +#endif + return err; +} + +/** + * User initiated disconnect + * + * Disconnects from PPP connection only and brings down the underlying network + * interface + */ +nsapi_error_t AT_CellularNetwork::disconnect() +{ +#if NSAPI_PPP_AVAILABLE + return nsapi_ppp_disconnect(_at.get_file_handle()); +#else + _at.lock(); + _at.cmd_start("AT+CGACT=0,"); + _at.write_int(_cid); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + _at.restore_at_timeout(); + + _connect_status = NSAPI_STATUS_DISCONNECTED; + if (_connection_status_cb) { + _connection_status_cb(NSAPI_EVENT_CONNECTION_STATUS_CHANGE, NSAPI_STATUS_DISCONNECTED); + } + + return _at.unlock_return_error(); +#endif +} + +void AT_CellularNetwork::attach(Callback status_cb) +{ + _connection_status_cb = status_cb; +} + +nsapi_connection_status_t AT_CellularNetwork::get_connection_status() const +{ + return _connect_status; +} + +nsapi_error_t AT_CellularNetwork::set_blocking(bool blocking) +{ +#if NSAPI_PPP_AVAILABLE + return nsapi_ppp_set_blocking(blocking); +#else + return NSAPI_ERROR_UNSUPPORTED; +#endif +} + + +#if NSAPI_PPP_AVAILABLE +void AT_CellularNetwork::ppp_status_cb(nsapi_event_t event, intptr_t parameter) +{ + _connect_status = (nsapi_connection_status_t)parameter; + + if (_connection_status_cb) { + _connection_status_cb(event, parameter); + } +} +#endif + + + +nsapi_error_t AT_CellularNetwork::set_context_to_be_activated() +{ + // try to find or create context with suitable stack + if (!get_context()) { + return NSAPI_ERROR_NO_CONNECTION; + } + + // if user has defined user name and password we need to call CGAUTH before activating or modifying context + if (_pwd && _uname) { + _at.cmd_start("AT+CGAUTH="); + _at.write_int(_cid); + _at.write_int(_authentication_type); + _at.write_string(_uname); + _at.write_string(_pwd); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + if (_at.get_last_error() != NSAPI_ERROR_OK) { + return NSAPI_ERROR_AUTH_FAILURE; + } + } + + return _at.get_last_error(); +} + +bool AT_CellularNetwork::set_new_context(int cid) +{ + nsapi_ip_stack_t tmp_stack = _ip_stack_type_requested; + + if (tmp_stack == DEFAULT_STACK) { + bool modem_supports_ipv6 = get_modem_stack_type(IPV6_STACK); + bool modem_supports_ipv4 = get_modem_stack_type(IPV4_STACK); + + if (modem_supports_ipv6 && modem_supports_ipv4) { + tmp_stack = IPV4V6_STACK; + } else if (modem_supports_ipv6) { + tmp_stack = IPV6_STACK; + } else if (modem_supports_ipv4) { + tmp_stack = IPV4_STACK; + } + } + + char pdp_type[8+1] = {0}; + + switch (tmp_stack) { + case IPV4_STACK: + strncpy(pdp_type, "IP", sizeof(pdp_type)); + break; + case IPV6_STACK: + strncpy(pdp_type, "IPV6", sizeof(pdp_type)); + break; + case IPV4V6_STACK: + strncpy(pdp_type, "IPV4V6", sizeof(pdp_type)); + break; + default: + break; + } + + //apn: "If the value is null or omitted, then the subscription value will be requested." + bool success = false; + _at.cmd_start("AT+CGDCONT="); + _at.write_int(cid); + _at.write_string(pdp_type); + _at.write_string(_apn); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + success = (_at.get_last_error() == NSAPI_ERROR_OK); + + // Fall back to ipv4 + if (!success && tmp_stack == IPV4V6_STACK) { + tmp_stack = IPV4_STACK; + _at.cmd_start("AT+FCLASS=0;+CGDCONT="); + _at.write_int(cid); + _at.write_string("IP"); + _at.write_string(_apn); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + success = (_at.get_last_error() == NSAPI_ERROR_OK); + } + + if (success) { + _ip_stack_type = tmp_stack; + _cid = cid; + _new_context_set = true; + } + + return success; +} + +bool AT_CellularNetwork::get_context() +{ + _at.cmd_start("AT+CGDCONT?"); + _at.cmd_stop(); + _at.resp_start("+CGDCONT:"); + _cid = -1; + int cid_max = 0; // needed when creating new context + char apn[MAX_ACCESSPOINT_NAME_LENGTH]; + int apn_len = 0; + + bool modem_supports_ipv6 = get_modem_stack_type(IPV6_STACK); + bool modem_supports_ipv4 = get_modem_stack_type(IPV4_STACK); + + while (_at.info_resp()) { + int cid = _at.read_int(); + if (cid > cid_max) { + cid_max = cid; + } + char pdp_type_from_context[10]; + int pdp_type_len = _at.read_string(pdp_type_from_context, sizeof(pdp_type_from_context) - 1); + if (pdp_type_len > 0) { + apn_len = _at.read_string(apn, sizeof(apn) - 1); + if (apn_len >= 0) { + if (_apn && strcmp(apn, _apn) != 0 ) { + continue; + } + nsapi_ip_stack_t pdp_stack = string_to_stack_type(pdp_type_from_context); + // Accept dual PDP context for IPv4/IPv6 only modems + if (pdp_stack != DEFAULT_STACK && (get_modem_stack_type(pdp_stack) || pdp_stack == IPV4V6_STACK)) { + if (_ip_stack_type_requested == IPV4_STACK) { + if (pdp_stack == IPV4_STACK || pdp_stack == IPV4V6_STACK) { + _ip_stack_type = _ip_stack_type_requested; + _cid = cid; + break; + } + } else if (_ip_stack_type_requested == IPV6_STACK) { + if (pdp_stack == IPV6_STACK || pdp_stack == IPV4V6_STACK) { + _ip_stack_type = _ip_stack_type_requested; + _cid = cid; + break; + } + } else { + // If dual PDP need to check for IPV4 or IPV6 modem support. Prefer IPv6. + if (pdp_stack == IPV4V6_STACK) { + if (modem_supports_ipv6) { + _ip_stack_type = IPV6_STACK; + _cid = cid; + break; + } else if (modem_supports_ipv4) { + _ip_stack_type = IPV4_STACK; + _cid = cid; + break; + } + // If PDP is IPV4 or IPV6 they are already checked if supported + } else { + _ip_stack_type = pdp_stack; + _cid = cid; + + if (pdp_stack == IPV6_STACK) { + break; + } + if (pdp_stack == IPV4_STACK && !modem_supports_ipv6) { + break; + } + } + } + } + } + } + } + _at.resp_stop(); + if (_cid == -1) { // no suitable context was found so create a new one + if (!set_new_context(cid_max+1)) { + return false; + } + } + + // save the apn + if (apn_len > 0 && !_apn) { + _apn = (char*)malloc(apn_len*sizeof(char)+1); + if (_apn) { + memcpy(_apn, apn, apn_len+1); + } else { + return false; + } + } + + tr_debug("Context id %d", _cid); + return true; +} + +nsapi_ip_stack_t AT_CellularNetwork::string_to_stack_type(const char* pdp_type) +{ + nsapi_ip_stack_t stack = DEFAULT_STACK; + int len = strlen(pdp_type); + + if (len == 6 && memcmp(pdp_type, "IPV4V6", len) == 0) { + stack = IPV4V6_STACK; + } else if (len == 4 && memcmp(pdp_type, "IPV6", len) == 0) { + stack = IPV6_STACK; + } else if (len == 2 && memcmp(pdp_type, "IP", len) == 0) { + stack = IPV4_STACK; + } + return stack; +} + +nsapi_error_t AT_CellularNetwork::set_registration_urc(bool urc_on) +{ + for (unsigned int i = 0; i < sizeof(at_reg)/sizeof(at_reg[0]); i++) { + if (has_registration(at_reg[i].type)) { + _last_reg_type = at_reg[i].type; + if (urc_on) { + _at.cmd_start(at_reg[i].cmd); + _at.write_string("=2", false); + _at.cmd_stop(); + } else { + _at.cmd_start(at_reg[i].cmd); + _at.write_string("=0", false); + _at.cmd_stop(); + } + + _at.resp_start(); + _at.resp_stop(); + } + } + return _at.get_last_error(); +} + +nsapi_error_t AT_CellularNetwork::set_registration(const char *plmn) +{ + _at.lock(); + + nsapi_error_t ret = set_registration_urc(false); + if (ret) { + tr_error("Setting registration URC failed!"); + _at.clear_error(); // allow temporary failures here + } + + if (!plmn) { + tr_debug("Automatic network registration"); + _at.cmd_start("AT+COPS=0"); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + } else { + tr_debug("Manual network registration to %s", plmn); + _at.cmd_start("AT+COPS=4,2,"); + _at.write_string(plmn); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + } + + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularNetwork::get_registration_status(RegistrationType type, RegistrationStatus &status) +{ + int i = (int)type; + MBED_ASSERT(i >= 0 && i < C_MAX); + + const char *rsp[] = { "+CEREG:", "+CGREG:", "+CREG:"}; + + const int LAC_LENGTH = 5, CELL_ID_LENGTH = 9; + char lac_string[LAC_LENGTH] = {0}, cell_id_string[CELL_ID_LENGTH] = {0}; + bool lac_read = false, cell_id_read = false; + + _cell_id = -1; + _lac = -1; + + _at.lock(); + + if (!has_registration(at_reg[i].type)) { + _at.unlock(); + return NSAPI_ERROR_UNSUPPORTED; + } + + _at.cmd_start(at_reg[i].cmd); + _at.write_string("=2", false); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + + _at.cmd_start(at_reg[i].cmd); + _at.write_string("?", false); + _at.cmd_stop(); + + _at.resp_start(rsp[i]); + _at.read_int(); // ignore urc mode subparam + status = (RegistrationStatus)_at.read_int(); + + int len = _at.read_string(lac_string, LAC_LENGTH); + if (memcmp(lac_string, "ffff", LAC_LENGTH-1) && len >= 0) { + lac_read = true; + } + + len = _at.read_string(cell_id_string, CELL_ID_LENGTH); + if (memcmp(cell_id_string, "ffffffff", CELL_ID_LENGTH-1) && len >= 0) { + cell_id_read = true; + } + + _at.resp_stop(); + + _at.cmd_start(at_reg[i].cmd); + _at.write_string("=0", false); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + nsapi_error_t ret = _at.get_last_error(); + _at.unlock(); + + if (lac_read) { + _lac = hex_str_to_int(lac_string, LAC_LENGTH); + tr_debug("lac %s %d", lac_string, _lac ); + } + + if (cell_id_read) { + _cell_id = hex_str_to_int(cell_id_string, CELL_ID_LENGTH); + tr_debug("cell_id %s %d", cell_id_string, _cell_id ); + } + + return ret; +} + +nsapi_error_t AT_CellularNetwork::get_cell_id(int &cell_id) +{ + RegistrationStatus tmp; + + nsapi_error_t error = get_registration_status(_last_reg_type, tmp); + + cell_id = _cell_id; + + return error; +} + +bool AT_CellularNetwork::has_registration(RegistrationType reg_type) +{ + (void)reg_type; + return true; +} + +nsapi_error_t AT_CellularNetwork::set_attach(int timeout) +{ + _at.lock(); + + _at.cmd_start("AT+CGATT?"); + _at.cmd_stop(); + _at.resp_start("+CGATT:"); + int attached_state = _at.read_int(); + _at.resp_stop(); + if (attached_state != 1) { + tr_debug("Network attach"); + _at.cmd_start("AT+CGATT=1"); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + } + + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularNetwork::get_attach(AttachStatus &status) +{ + _at.lock(); + + _at.cmd_start("AT+CGATT?"); + _at.cmd_stop(); + + _at.resp_start("+CGATT:"); + if (_at.info_resp()) { + int attach_status = _at.read_int(); + status = (attach_status == 1) ? Attached : Detached; + } + _at.resp_stop(); + + return _at.unlock_return_error(); +} + + +nsapi_error_t AT_CellularNetwork::get_apn_backoff_timer(int &backoff_timer) +{ + _at.lock(); + + // If apn is set + if (_apn) { + _at.cmd_start("AT+CABTRDP="); + _at.write_string(_apn); + _at.cmd_stop(); + _at.resp_start("+CABTRDP:"); + if (_at.info_resp()) { + _at.skip_param(); + backoff_timer = _at.read_int(); + } + _at.resp_stop(); + } + + return _at.unlock_return_error(); +} + +NetworkStack *AT_CellularNetwork::get_stack() +{ + // use lwIP/PPP if modem does not have IP stack +#if NSAPI_PPP_AVAILABLE + _stack = nsapi_ppp_get_stack(); +#else + _stack = NULL; +#endif + return _stack; +} + +const char *AT_CellularNetwork::get_ip_address() +{ +#if NSAPI_PPP_AVAILABLE + return nsapi_ppp_get_ip_addr(_at.get_file_handle()); +#else + if (!_stack) { + _stack = get_stack(); + } + if (_stack) { + return _stack->get_ip_address(); + } + return NULL; +#endif +} + +nsapi_error_t AT_CellularNetwork::set_stack_type(nsapi_ip_stack_t stack_type) +{ + + if (get_modem_stack_type(stack_type)) { + _ip_stack_type_requested = stack_type; + return NSAPI_ERROR_OK; + } else { + return NSAPI_ERROR_PARAMETER; + } + +} + +nsapi_ip_stack_t AT_CellularNetwork::get_stack_type() +{ + return _ip_stack_type; +} + +bool AT_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack) +{ + if (requested_stack == _ip_stack_type) { + return true; + } else { + return false; + } +} + +nsapi_error_t AT_CellularNetwork::set_access_technology_impl(operator_t::RadioAccessTechnology opsAct) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t AT_CellularNetwork::set_access_technology(operator_t::RadioAccessTechnology opAct) +{ + if (opAct == operator_t::RAT_UNKNOWN) { + return NSAPI_ERROR_UNSUPPORTED; + } + + _op_act = opAct; + + return set_access_technology_impl(opAct); +} + +nsapi_error_t AT_CellularNetwork::scan_plmn(operList_t &operators, int &opsCount) +{ + int idx = 0; + + _at.lock(); + + _at.cmd_start("AT+COPS=?"); + _at.cmd_stop(); + + _at.resp_start("+COPS:"); + + int ret, error_code = -1; + operator_t *op = NULL; + + while (_at.info_elem('(')) { + + op = operators.add_new(); + + op->op_status = (operator_t::Status)_at.read_int(); + _at.read_string(op->op_long, sizeof(op->op_long)); + _at.read_string(op->op_short, sizeof(op->op_short)); + _at.read_string(op->op_num, sizeof(op->op_num)); + + // Optional - try read an int + ret = _at.read_int(); + op->op_rat = (ret == error_code) ? operator_t::RAT_UNKNOWN:(operator_t::RadioAccessTechnology)ret; + + if ((_op_act == operator_t::RAT_UNKNOWN) || + ((op->op_rat != operator_t::RAT_UNKNOWN) && (op->op_rat == _op_act))) { + idx++; + } else { + operators.delete_last(); + } + } + + _at.resp_stop(); + + opsCount = idx; + + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularNetwork::set_ciot_optimization_config(Supported_UE_Opt supported_opt, + Preferred_UE_Opt preferred_opt) +{ + _at.lock(); + + _at.cmd_start("AT+CCIOTOPT="); + _at.write_int(_cid); + _at.write_int(supported_opt); + _at.write_int(preferred_opt); + _at.cmd_stop(); + + _at.resp_start(); + _at.resp_stop(); + + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularNetwork::get_ciot_optimization_config(Supported_UE_Opt& supported_opt, + Preferred_UE_Opt& preferred_opt) +{ + _at.lock(); + + _at.cmd_start("AT+CCIOTOPT?"); + _at.cmd_stop(); + + _at.resp_start("+CCIOTOPT:"); + _at.read_int(); + if (_at.get_last_error() == NSAPI_ERROR_OK) { + supported_opt = (Supported_UE_Opt)_at.read_int(); + preferred_opt = (Preferred_UE_Opt)_at.read_int(); + } + + _at.resp_stop(); + + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularNetwork::get_rate_control( + CellularNetwork::RateControlExceptionReports &reports, + CellularNetwork::RateControlUplinkTimeUnit &timeUnit, int &uplinkRate) +{ + + _at.lock(); + + _at.cmd_start("AT+CGAPNRC="); + _at.write_int(_cid); + _at.cmd_stop(); + + _at.resp_start("+CGAPNRC:"); + _at.read_int(); + if (_at.get_last_error() == NSAPI_ERROR_OK) { + bool comma_found = true; + int next_element = _at.read_int(); + if (next_element >= 0) { + reports = (RateControlExceptionReports)next_element; + tr_debug("reports %d",reports); + next_element = _at.read_int(); + } else { + comma_found = false; + } + + if (comma_found && next_element >= 0) { + timeUnit = (RateControlUplinkTimeUnit)next_element; + tr_debug("time %d",timeUnit); + next_element = _at.read_int(); + } else { + comma_found = false; + } + + if (comma_found && next_element >= 0) { + uplinkRate = next_element; + tr_debug("rate %d",uplinkRate); + } + } + _at.resp_stop(); + nsapi_error_t ret = _at.get_last_error(); + _at.unlock(); + + return (ret == NSAPI_ERROR_OK) ? NSAPI_ERROR_OK : NSAPI_ERROR_PARAMETER; +} + +nsapi_error_t AT_CellularNetwork::get_pdpcontext_params(pdpContextList_t& params_list) +{ + const int ipv6_subnet_size = 128; + const int max_ipv6_size = 64; + char* ipv6_and_subnetmask = (char*)malloc(ipv6_subnet_size); + if (!ipv6_and_subnetmask) { + return NSAPI_ERROR_NO_MEMORY; + } + + char* temp = (char*)malloc(max_ipv6_size); + if (!temp) { + free(ipv6_and_subnetmask); + return NSAPI_ERROR_NO_MEMORY; + } + + _at.lock(); + + _at.cmd_start("AT+CGCONTRDP="); + _at.write_int(_cid); + _at.cmd_stop(); + + _at.resp_start("+CGCONTRDP:"); + pdpcontext_params_t *params = NULL; + while (_at.info_resp()) { // response can be zero or many +CGDCONT lines + params = params_list.add_new(); + if (!params) { + tr_warn("Could not allocate new pdpcontext_params_t"); + params_list.delete_all(); + _at.resp_stop(); + free(temp); + free(ipv6_and_subnetmask); + return NSAPI_ERROR_NO_MEMORY; + } + + params->cid = _at.read_int(); + params->bearer_id = _at.read_int(); + _at.read_string(params->apn, sizeof(params->apn)); + + // rest are optional params + ipv6_and_subnetmask[0] = '\0'; + temp[0] = '\0'; + _at.read_string(ipv6_and_subnetmask, ipv6_subnet_size); + separate_ip_addresses(ipv6_and_subnetmask, params->local_addr, sizeof(params->local_addr), params->local_subnet_mask, sizeof(params->local_subnet_mask)); + ipv6_and_subnetmask[0] = '\0'; + + _at.read_string(ipv6_and_subnetmask, ipv6_subnet_size); + separate_ip_addresses(ipv6_and_subnetmask, params->gateway_addr, sizeof(params->gateway_addr), temp, max_ipv6_size); + prefer_ipv6(params->gateway_addr, sizeof(params->gateway_addr), temp, max_ipv6_size); + ipv6_and_subnetmask[0] = '\0'; + temp[0] = '\0'; + + _at.read_string(ipv6_and_subnetmask, ipv6_subnet_size); + separate_ip_addresses(ipv6_and_subnetmask, params->dns_primary_addr, sizeof(params->dns_primary_addr), temp, max_ipv6_size); + prefer_ipv6(params->dns_primary_addr, sizeof(params->dns_primary_addr), temp, max_ipv6_size); + ipv6_and_subnetmask[0] = '\0'; + temp[0] = '\0'; + + _at.read_string(ipv6_and_subnetmask, ipv6_subnet_size); + separate_ip_addresses(ipv6_and_subnetmask, params->dns_secondary_addr, sizeof(params->dns_secondary_addr), temp, max_ipv6_size); + prefer_ipv6(params->dns_secondary_addr, sizeof(params->dns_secondary_addr), temp, max_ipv6_size); + ipv6_and_subnetmask[0] = '\0'; + temp[0] = '\0'; + + _at.read_string(ipv6_and_subnetmask, ipv6_subnet_size); + separate_ip_addresses(ipv6_and_subnetmask, params->p_cscf_prim_addr, sizeof(params->p_cscf_prim_addr), temp, max_ipv6_size); + prefer_ipv6(params->p_cscf_prim_addr, sizeof(params->p_cscf_prim_addr), temp, max_ipv6_size); + ipv6_and_subnetmask[0] = '\0'; + temp[0] = '\0'; + + _at.read_string(ipv6_and_subnetmask, ipv6_subnet_size); + separate_ip_addresses(ipv6_and_subnetmask, params->p_cscf_sec_addr, sizeof(params->p_cscf_sec_addr), temp, max_ipv6_size); + prefer_ipv6(params->p_cscf_sec_addr, sizeof(params->p_cscf_sec_addr), temp, max_ipv6_size); + + params->im_signalling_flag = _at.read_int(); + params->lipa_indication = _at.read_int(); + params->ipv4_mtu = _at.read_int(); + params->wlan_offload = _at.read_int(); + params->local_addr_ind = _at.read_int(); + params->non_ip_mtu = _at.read_int(); + params->serving_plmn_rate_control_value = _at.read_int(); + } + _at.resp_stop(); + + free(temp); + free(ipv6_and_subnetmask); + + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularNetwork::get_extended_signal_quality(int &rxlev, int &ber, int &rscp, int &ecno, int &rsrq, int &rsrp) +{ + _at.lock(); + + _at.cmd_start("AT+CESQ"); + _at.cmd_stop(); + + _at.resp_start("+CESQ:"); + rxlev = _at.read_int(); + ber = _at.read_int(); + rscp = _at.read_int(); + ecno = _at.read_int(); + rsrq = _at.read_int(); + rsrp = _at.read_int(); + _at.resp_stop(); + if (rxlev < 0 || ber < 0 || rscp < 0 || ecno < 0 || rsrq < 0 || rsrp < 0) { + _at.unlock(); + return NSAPI_ERROR_DEVICE_ERROR; + } + + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularNetwork::get_signal_quality(int &rssi, int &ber) +{ + _at.lock(); + + _at.cmd_start("AT+CSQ"); + _at.cmd_stop(); + + _at.resp_start("+CSQ:"); + rssi = _at.read_int(); + ber = _at.read_int(); + _at.resp_stop(); + if (rssi < 0 || ber < 0) { + _at.unlock(); + return NSAPI_ERROR_DEVICE_ERROR; + } + + return _at.unlock_return_error(); +} + +/** Get the last 3GPP error code + * @return see 3GPP TS 27.007 error codes + */ +int AT_CellularNetwork::get_3gpp_error() +{ + return _at.get_3gpp_error(); +} + + +nsapi_error_t AT_CellularNetwork::get_operator_params(int &format, operator_t &operator_params) +{ + _at.lock(); + + _at.cmd_start("AT+COPS?"); + _at.cmd_stop(); + + _at.resp_start("+COPS:"); + _at.read_int(); //ignore mode + format = _at.read_int(); + + if (_at.get_last_error() == NSAPI_ERROR_OK) { + + switch (format) { + case 0: + _at.read_string(operator_params.op_long, sizeof(operator_params.op_long)); + break; + + case 1: + _at.read_string(operator_params.op_short, sizeof(operator_params.op_short)); + break; + + default: + _at.read_string(operator_params.op_num, sizeof(operator_params.op_num)); + break; + } + + operator_params.op_rat = (operator_t::RadioAccessTechnology)_at.read_int(); + } + + _at.resp_stop(); + + return _at.unlock_return_error(); +} diff --git a/features/cellular/framework/AT/AT_CellularNetwork.h b/features/cellular/framework/AT/AT_CellularNetwork.h new file mode 100644 index 0000000000..eaf25c7f8d --- /dev/null +++ b/features/cellular/framework/AT/AT_CellularNetwork.h @@ -0,0 +1,171 @@ +/* + * Copyright (c) 2017, 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 AT_CELLULAR_NETWORK_H_ +#define AT_CELLULAR_NETWORK_H_ + +#include "CellularNetwork.h" +#include "AT_CellularBase.h" +#include "NetworkStack.h" + +namespace mbed { + +#define AT_NETWORK_TRIALS 5 + +/** + * Class AT_CellularNetwork + * + * Class for connecting to a network and getting information from it. + */ +class AT_CellularNetwork : public CellularNetwork, public AT_CellularBase +{ + +public: + + AT_CellularNetwork(ATHandler &atHandler); + virtual ~AT_CellularNetwork(); + // declare friend so it can access stack + friend class AT_CellularDevice; + +public: // NetworkInterface + + virtual nsapi_error_t set_credentials(const char *apn, + const char *username = 0, const char *password = 0); + + virtual nsapi_error_t set_credentials(const char *apn, AuthenticationType type, + const char *username = 0, const char *password = 0); + + virtual nsapi_error_t connect(const char *apn, + const char *username = 0, const char *password = 0); + + virtual nsapi_error_t connect(); + + virtual nsapi_error_t disconnect(); + +protected: + virtual NetworkStack *get_stack(); + +public: // CellularNetwork + virtual nsapi_error_t set_registration(const char *plmn = 0); + + virtual nsapi_error_t get_registration_status(RegistrationType type, RegistrationStatus &status); + + virtual nsapi_error_t set_attach(int timeout = 10*1000); + + virtual nsapi_error_t get_attach(AttachStatus &status); + + virtual nsapi_error_t get_rate_control(CellularNetwork::RateControlExceptionReports &reports, + CellularNetwork::RateControlUplinkTimeUnit &time_unit, int &uplink_rate); + + virtual nsapi_error_t get_apn_backoff_timer(int &backoff_timer); + + virtual void attach(Callback status_cb); + + virtual nsapi_connection_status_t get_connection_status() const; + + virtual nsapi_error_t set_blocking(bool blocking); + + virtual const char *get_ip_address(); + + virtual nsapi_error_t set_access_technology(operator_t::RadioAccessTechnology op_rat); + + virtual nsapi_error_t scan_plmn(operList_t &operators, int &ops_count); + + virtual nsapi_error_t set_ciot_optimization_config(Supported_UE_Opt supported_opt, + Preferred_UE_Opt preferred_opt); + + virtual nsapi_error_t get_ciot_optimization_config(Supported_UE_Opt& supported_opt, + Preferred_UE_Opt& preferred_opt); + + virtual nsapi_error_t set_stack_type(nsapi_ip_stack_t stack_type); + + virtual nsapi_ip_stack_t get_stack_type(); + + virtual nsapi_error_t get_pdpcontext_params(pdpContextList_t& params_list); + + virtual nsapi_error_t get_extended_signal_quality(int &rxlev, int &ber, int &rscp, int &ecno, int &rsrq, int &rsrp); + + virtual nsapi_error_t get_signal_quality(int &rssi, int &ber); + + virtual nsapi_error_t get_cell_id(int &cell_id); + + virtual int get_3gpp_error(); + + virtual nsapi_error_t get_operator_params(int &format, operator_t &operator_params); + +protected: + + /** Check if modem supports the given stack type. + * + * @return true if supported + */ + virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack); + + /** Check if modem supports given registration type. + * + * @param reg_type enum RegistrationType + * @return true if given registration type is supported by modem + */ + virtual bool has_registration(RegistrationType reg_type); + + /** Sets access technology to be scanned. Modem specific implementation. + * + * @param op_rat Access technology + * + * @return zero on success + */ + virtual nsapi_error_t set_access_technology_impl(operator_t::RadioAccessTechnology op_rat); + +private: + // "NO CARRIER" urc + void urc_no_carrier(); + nsapi_error_t set_context_to_be_activated(); + nsapi_ip_stack_t string_to_stack_type(const char* pdp_type); + + void free_credentials(); + + nsapi_error_t open_data_channel(); + bool get_context(); + bool set_new_context(int cid); + nsapi_error_t set_registration_urc(bool on); + nsapi_error_t delete_current_context(); + +#if NSAPI_PPP_AVAILABLE + void ppp_status_cb(nsapi_event_t, intptr_t); +#endif + +protected: + NetworkStack *_stack; + char *_apn; + char *_uname; + char *_pwd; + nsapi_ip_stack_t _ip_stack_type_requested; + nsapi_ip_stack_t _ip_stack_type; + int _cid; + Callback _connection_status_cb; + operator_t::RadioAccessTechnology _op_act; + AuthenticationType _authentication_type; + int _lac; + int _cell_id; + RegistrationType _last_reg_type; + nsapi_connection_status_t _connect_status; + bool _new_context_set; +}; + +} // namespace mbed + +#endif // AT_CELLULAR_NETWORK_H_ diff --git a/features/cellular/framework/AT/AT_CellularPower.cpp b/features/cellular/framework/AT/AT_CellularPower.cpp new file mode 100644 index 0000000000..e6d21a39c1 --- /dev/null +++ b/features/cellular/framework/AT/AT_CellularPower.cpp @@ -0,0 +1,233 @@ +/* + * Copyright (c) 2017, 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 "AT_CellularPower.h" +#include "CellularUtil.h" +#include "CellularLog.h" +#include "nsapi_types.h" + +static const int PSMTimerBits = 5; + +using namespace mbed_cellular_util; +using namespace mbed; + +AT_CellularPower::AT_CellularPower(ATHandler &at) : AT_CellularBase(at) +{ +} + +AT_CellularPower::~AT_CellularPower() +{ +} + +nsapi_error_t AT_CellularPower::on() +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t AT_CellularPower::off() +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t AT_CellularPower::set_at_mode() +{ + _at.lock(); + _at.flush(); + _at.cmd_start("ATE0"); // echo off + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + + _at.cmd_start("AT+CMEE=1"); // verbose responses + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularPower::set_power_level(int func_level) +{ + _at.lock(); + _at.cmd_start("AT+CFUN="); + _at.write_int(func_level); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularPower::reset() +{ + _at.lock(); + _at.cmd_start("AT+CFUN=");// reset to full power levels + _at.write_int(1); + _at.write_int(1); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularPower::opt_power_save_mode(int periodic_time, int active_time) +{ + _at.lock(); + + if (periodic_time == 0 && active_time == 0) { + // disable PSM + _at.cmd_start("AT+CPSMS="); + _at.write_int(0); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + } else { + /** + Table 10.5.163a/3GPP TS 24.008: GPRS Timer 3 information element + + Bits 5 to 1 represent the binary coded timer value. + + Bits 6 to 8 defines the timer value unit for the GPRS timer as follows: + 8 7 6 + 0 0 0 value is incremented in multiples of 10 minutes + 0 0 1 value is incremented in multiples of 1 hour + 0 1 0 value is incremented in multiples of 10 hours + 0 1 1 value is incremented in multiples of 2 seconds + 1 0 0 value is incremented in multiples of 30 seconds + 1 0 1 value is incremented in multiples of 1 minute + 1 1 0 value is incremented in multiples of 320 hours (NOTE 1) + 1 1 1 value indicates that the timer is deactivated (NOTE 2). + */ + char pt[8+1];// timer value encoded as 3GPP IE + const int ie_value_max = 0x1f; + uint32_t periodic_timer = 0; + if (periodic_time <= 2*ie_value_max) { // multiples of 2 seconds + periodic_timer = periodic_time/2; + strcpy(pt, "01100000"); + } else { + if (periodic_time <= 30*ie_value_max) { // multiples of 30 seconds + periodic_timer = periodic_time/30; + strcpy(pt, "10000000"); + } else { + if (periodic_time <= 60*ie_value_max) { // multiples of 1 minute + periodic_timer = periodic_time/60; + strcpy(pt, "10100000"); + } else { + if (periodic_time <= 10*60*ie_value_max) { // multiples of 10 minutes + periodic_timer = periodic_time/(10*60); + strcpy(pt, "00000000"); + } else { + if (periodic_time <= 60*60*ie_value_max) { // multiples of 1 hour + periodic_timer = periodic_time/(60*60); + strcpy(pt, "00100000"); + } else { + if (periodic_time <= 10*60*60*ie_value_max) { // multiples of 10 hours + periodic_timer = periodic_time/(10*60*60); + strcpy(pt, "01000000"); + } else { // multiples of 320 hours + int t = periodic_time / (320*60*60); + if (t > ie_value_max) { + t = ie_value_max; + } + periodic_timer = t; + strcpy(pt, "11000000"); + } + } + } + } + } + } + + uint_to_binary_str(periodic_timer, &pt[3], sizeof(pt)-3, PSMTimerBits); + pt[8] = '\0'; + + /** + Table 10.5.172/3GPP TS 24.008: GPRS Timer information element + + Bits 5 to 1 represent the binary coded timer value. + + Bits 6 to 8 defines the timer value unit for the GPRS timer as follows: + + 8 7 6 + 0 0 0 value is incremented in multiples of 2 seconds + 0 0 1 value is incremented in multiples of 1 minute + 0 1 0 value is incremented in multiples of decihours + 1 1 1 value indicates that the timer is deactivated. + + Other values shall be interpreted as multiples of 1 minute in this version of the protocol. + */ + char at[8+1]; + uint32_t active_timer; // timer value encoded as 3GPP IE + if (active_time <= 2*ie_value_max) { // multiples of 2 seconds + active_timer = active_time/2; + strcpy(at, "00000000"); + } else { + if (active_time <= 60*ie_value_max) { // multiples of 1 minute + active_timer = (1<<5) | (active_time/60); + strcpy(at, "00100000"); + } else { // multiples of decihours + int t = active_time / (6*60); + if (t > ie_value_max) { + t = ie_value_max; + } + active_timer = t; + strcpy(at, "01000000"); + } + } + + uint_to_binary_str(active_timer, &at[3], sizeof(at)-3, PSMTimerBits); + pt[8] = '\0'; + + // request for both GPRS and LTE + _at.cmd_start("AT+CPSMS="); + _at.write_int(1); + _at.write_string(pt); + _at.write_string(at); + _at.write_string(pt); + _at.write_string(at); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + + + if (_at.get_last_error() != NSAPI_ERROR_OK) { + tr_warn("Power save mode not enabled!"); + } else { + // network may not agree with power save options but + // that should be fine as timeout is not longer than requested + } + } + + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularPower::opt_receive_period(int mode, EDRXAccessTechnology act_type, uint8_t edrx_value) +{ + char edrx[5]; + uint_to_binary_str(edrx_value, edrx, 5, 4); + edrx[4] = '\0'; + + _at.lock(); + + _at.cmd_start("AT+CEDRXS="); + _at.write_int(mode); + _at.write_int(act_type); + _at.write_string(edrx); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + + return _at.unlock_return_error(); +} diff --git a/features/cellular/framework/AT/AT_CellularPower.h b/features/cellular/framework/AT/AT_CellularPower.h new file mode 100644 index 0000000000..0aaeafcb8d --- /dev/null +++ b/features/cellular/framework/AT/AT_CellularPower.h @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2017, 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 AT_CELLULAR_POWER_H_ +#define AT_CELLULAR_POWER_H_ + +#include "CellularPower.h" +#include "AT_CellularBase.h" + +namespace mbed { + +/** + * Class AT_CellularPower + * + * Class that provides power handling functions for modem/module. + */ +class AT_CellularPower : public CellularPower, public AT_CellularBase +{ +public: + AT_CellularPower(ATHandler &atHandler); + virtual ~AT_CellularPower(); + +public: + virtual nsapi_error_t on(); + + virtual nsapi_error_t off(); + + virtual nsapi_error_t set_at_mode(); + + virtual nsapi_error_t set_power_level(int func_level); + + virtual nsapi_error_t reset(); + + virtual nsapi_error_t opt_power_save_mode(int periodic_time, int active_time); + + virtual nsapi_error_t opt_receive_period(int mode, EDRXAccessTechnology act_type, uint8_t edrx_value); +}; + +} // namespace mbed + +#endif /* AT_CELLULAR_POWER_H_ */ diff --git a/features/cellular/framework/AT/AT_CellularSIM.cpp b/features/cellular/framework/AT/AT_CellularSIM.cpp new file mode 100644 index 0000000000..3f1fb65461 --- /dev/null +++ b/features/cellular/framework/AT/AT_CellularSIM.cpp @@ -0,0 +1,130 @@ +/* + * Copyright (c) 2017, 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 "AT_CellularSIM.h" +#include "CellularLog.h" + +using namespace mbed; + +const int MAX_SIM_RESPONSE_LENGTH = 16; + +AT_CellularSIM::AT_CellularSIM(ATHandler &at) : AT_CellularBase(at) +{ +} + +AT_CellularSIM::~AT_CellularSIM() +{ +} + +nsapi_error_t AT_CellularSIM::get_sim_state(SimState &state) +{ + char simstr[MAX_SIM_RESPONSE_LENGTH]; + _at.lock(); + _at.flush(); + _at.cmd_start("AT+CPIN?"); + _at.cmd_stop(); + _at.resp_start("+CPIN:"); + ssize_t len = _at.read_string(simstr, sizeof (simstr)); + if (len != -1) { + if (len >= 5 && memcmp(simstr, "READY", 5) == 0) { + state = SimStateReady; + } else if (len >= 6 && memcmp(simstr, "SIM PIN", 6) == 0) { + state = SimStatePinNeeded; + } else if (len >= 6 && memcmp(simstr, "SIM PUK", 6) == 0) { + state = SimStatePukNeeded; + } else { + simstr[len] = '\0'; + tr_error("Unknown SIM state %s", simstr); + state = SimStateUnknown; + } + } else { + tr_warn("SIM not readable."); + state = SimStateUnknown; // SIM may not be ready yet or +CPIN may be unsupported command + } + _at.resp_stop(); + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularSIM::set_pin(const char *sim_pin) +{ + // if SIM is already in ready state then settings the PIN + // will return error so let's check the state before settings the pin. + SimState state; + if (get_sim_state(state) == NSAPI_ERROR_OK && state == SimStateReady) { + return NSAPI_ERROR_OK; + } + + _at.lock(); + _at.cmd_start("AT+CPIN="); + _at.write_string(sim_pin); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularSIM::change_pin(const char *sim_pin, const char *new_pin) +{ + _at.lock(); + _at.cmd_start("AT+CPWD="); + _at.write_string("SC"); + _at.write_string(sim_pin); + _at.write_string(new_pin); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularSIM::set_pin_query(const char *sim_pin, bool query_pin) +{ + _at.lock(); + if (query_pin) { + /* use the SIM locked */ + _at.cmd_start("AT+CLCK="); + _at.write_string("SC"); + _at.write_int(1); + _at.write_string(sim_pin); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + } else { + /* use the SIM unlocked */ + _at.cmd_start("AT+CLCK="); + _at.write_string("SC"); + _at.write_int(0); + _at.write_string(sim_pin); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + } + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularSIM::get_imsi(char* imsi) +{ + _at.lock(); + _at.cmd_start("AT+CIMI"); + _at.cmd_stop(); + _at.resp_start(); + int len = _at.read_string(imsi, MAX_IMSI_LENGTH); + if (len > 0) { + imsi[len] = '\0'; + } + _at.resp_stop(); + return _at.unlock_return_error(); +} diff --git a/features/cellular/framework/AT/AT_CellularSIM.h b/features/cellular/framework/AT/AT_CellularSIM.h new file mode 100644 index 0000000000..be53416820 --- /dev/null +++ b/features/cellular/framework/AT/AT_CellularSIM.h @@ -0,0 +1,52 @@ +/* + * Copyright (c) 2017, 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 AT_CELLULAR_SIM_H_ +#define AT_CELLULAR_SIM_H_ + +#include "CellularSIM.h" +#include "AT_CellularBase.h" + +namespace mbed { + +/** + * Class AT_CellularSIM + * + * Class for SIM card handling. + */ +class AT_CellularSIM : public CellularSIM, public AT_CellularBase +{ + +public: + AT_CellularSIM(ATHandler &atHandler); + virtual ~AT_CellularSIM(); + +public: + virtual nsapi_error_t set_pin(const char *sim_pin); + + virtual nsapi_error_t change_pin(const char *sim_pin, const char *new_pin); + + virtual nsapi_error_t set_pin_query(const char *sim_pin, bool query_pin); + + virtual nsapi_error_t get_sim_state(SimState &state); + + virtual nsapi_error_t get_imsi(char* imsi); +}; + +} // namespace mbed + +#endif // AT_CELLULAR_SIM_H_ diff --git a/features/cellular/framework/AT/AT_CellularSMS.cpp b/features/cellular/framework/AT/AT_CellularSMS.cpp new file mode 100644 index 0000000000..faa7a9eb6e --- /dev/null +++ b/features/cellular/framework/AT/AT_CellularSMS.cpp @@ -0,0 +1,1300 @@ +/* + * Copyright (c) 2017, 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 +#include +#include "mbed_wait_api.h" +#include "AT_CellularSMS.h" +#include "CellularUtil.h" +#include "CellularLog.h" + +using namespace mbed_cellular_util; +using namespace mbed; +using namespace std; + +#define CTRL_Z "\x1a" +#define ESC "\x1b" + +const uint8_t SMS_STATUS_SIZE = 12 + 1; +const uint8_t FIRST_OCTET_DELIVER_SUBMIT = 17; +const uint8_t TP_VALIDITY_PERIOD_24_HOURS = 167; +const uint8_t TP_PROTOCOL_IDENTIFIER = 0; +const uint8_t SMS_DATA_CODING_SCHEME = 0; + +const uint8_t SMS_MAX_8BIT_CONCATENATED_SINGLE_SMS_SIZE = 134; +const uint8_t SMS_MAX_GSM7_CONCATENATED_SINGLE_SMS_SIZE = 153; +#define NVAM '?' // Not Valid ascii, ISO-8859-1 mark + +// mapping table from 7-bit GSM to ascii (ISO-8859-1) +static const int gsm_to_ascii[] = { + 64, // 0 + 163, // 1 + 36, // 2 + 165, // 3 + 232, // 4 + 233, // 5 + 249, // 6 + 236, // 7 + 242, // 8 + 199, // 9 + 10, // 10 + 216, // 11 + 248, // 12 + 13, // 13 + 197, // 14 + 229, // 15 + NVAM, // 16 + 95, // 17 + NVAM, // 18 + NVAM, // 19 + NVAM, // 20 + NVAM, // 21 + NVAM, // 22 + NVAM, // 23 + NVAM, // 24 + NVAM, // 25 + NVAM, // 26 + 27, // 27 + 198, // 28 + 230, // 29 + 223, // 30 + 201, // 31 + 32, // 32 + 33, // 33 + 34, // 34 + 35, // 35 + 164, // 36 + 37, // 37 + 38, // 38 + 39, // 39 + 40, // 40 + 41, // 41 + 42, // 42 + 43, // 43 + 44, // 44 + 45, // 45 + 46, // 46 + 47, // 47 + 48, // 48 + 49, // 49 + 50, // 50 + 51, // 51 + 52, // 52 + 53, // 53 + 54, // 54 + 55, // 55 + 56, // 56 + 57, // 57 + 58, // 58 + 59, // 59 + 60, // 60 + 61, // 61 + 62, // 62 + 63, // 63 + 161, // 64 + 65, // 65 + 66, // 66 + 67, // 67 + 68, // 68 + 69, // 69 + 70, // 70 + 71, // 71 + 72, // 72 + 73, // 73 + 74, // 74 + 75, // 75 + 76, // 76 + 77, // 77 + 78, // 78 + 79, // 79 + 80, // 80 + 81, // 81 + 82, // 82 + 83, // 83 + 84, // 84 + 85, // 85 + 86, // 86 + 87, // 87 + 88, // 88 + 89, // 89 + 90, // 90 + 196, // 91 + 214, // 92 + 209, // 93 + 220, // 94 + 167, // 95 + 191, // 96 + 97, // 97 + 98, // 98 + 99, // 99 + 100, // 100 + 101, // 101 + 102, // 102 + 103, // 103 + 104, // 104 + 105, // 105 + 106, // 106 + 107, // 107 + 108, // 108 + 109, // 109 + 110, // 110 + 111, // 111 + 112, // 112 + 113, // 113 + 114, // 114 + 115, // 115 + 116, // 116 + 117, // 117 + 118, // 118 + 119, // 119 + 120, // 120 + 121, // 121 + 122, // 122 + 228, // 123 + 246, // 124 + 241, // 125 + 252, // 126 + 224 // 127 +}; + +const int GSM_TO_ASCII_TABLE_SIZE = sizeof(gsm_to_ascii)/sizeof(gsm_to_ascii[0]); + +AT_CellularSMS::AT_CellularSMS(ATHandler &at) : AT_CellularBase(at), _cb(0), _mode(CellularSMSMmodeText), + _use_8bit_encoding(false), _sim_wait_time(0), _sms_message_ref_number(1), _sms_info(NULL) +{ + /* URCs, handled out of band */ + _at.set_urc_handler("+CMTI:", callback(this, &AT_CellularSMS::cmti_urc)); + _at.set_urc_handler("+CMT:", callback(this, &AT_CellularSMS::cmt_urc)); +} + +AT_CellularSMS::~AT_CellularSMS() +{ +} + +void AT_CellularSMS::cmt_urc() +{ + tr_debug("CMT_URC called"); + //+CMT: ,[],[,,,,,,,] + _at.consume_to_stop_tag(); + // call user defined callback function + if (_cb) { + _cb(); + } else { + tr_warn("cmt_urc, no user defined callback for receiving sms!"); + } +} + +void AT_CellularSMS::cmti_urc() +{ + //+CMTI: ,, + tr_debug("CMTI_URC called"); + // call user defined callback function + if (_cb) { + _cb(); + } else { + tr_warn("cmti_urc, no user defined callback for receiving sms!"); + } +} + +nsapi_error_t AT_CellularSMS::set_cnmi() +{ + _at.lock(); + _at.cmd_start("AT+CNMI=2,1"); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularSMS::set_cmgf(int msg_format) +{ + _at.lock(); + _at.cmd_start("AT+CMGF="); + _at.write_int(msg_format); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularSMS::set_csmp(int fo, int vp, int pid, int dcs) +{ + _at.lock(); + _at.cmd_start("AT+CSMP="); + _at.write_int(fo); + _at.write_int(vp); + _at.write_int(pid); + _at.write_int(dcs); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularSMS::set_csdh(int show_header) +{ + _at.lock(); + _at.cmd_start("AT+CSDH="); + _at.write_int(show_header); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularSMS::initialize(CellularSMSMmode mode) +{ + _at.lock(); + set_cnmi(); //set new SMS indication + set_cmgf(mode); //set message format/PDU + + if (mode == CellularSMSMmodeText) { + set_csmp(FIRST_OCTET_DELIVER_SUBMIT, TP_VALIDITY_PERIOD_24_HOURS, TP_PROTOCOL_IDENTIFIER, + SMS_DATA_CODING_SCHEME); //set Set Text Mode Parameters(default values for SMS-SUBMIT and RECEIVE) + set_csdh(1);//set header extra info as it's needed + } + + _mode = mode; + + return _at.unlock_return_error(); +} + +void AT_CellularSMS::set_extra_sim_wait_time(int sim_wait_time) +{ + _sim_wait_time = sim_wait_time; +} + +char* AT_CellularSMS::create_pdu(const char* phone_number, const char* message, uint8_t message_length, uint8_t msg_parts, + uint8_t msg_part_number, uint8_t& header_size) +{ + int totalPDULength = 0; + int number_len = strlen(phone_number); + + totalPDULength += number_len; + if (number_len&0x01) {// if phone number length is not even length we must pad it and so +1 + totalPDULength += 1; + } + + totalPDULength += 16; // all other than phone number and message length + if (msg_parts > 1) {// add more space for UDH + totalPDULength += 12; + } + // there might be need for padding so some more space + totalPDULength +=2; + + // message 7-bit padded and it will be converted to hex so it will take twice as much space + totalPDULength += (message_length - (message_length/8))*2; + + char* pdu = (char*)calloc(totalPDULength, sizeof(char)); + if (!pdu) { + return NULL; + } + + int x = 0; + // See more how to create PDU from 3GPP specification 23040 + // first two define that we use service center number which is set with +CSCA + pdu[x++] = '0'; + pdu[x++] = '0'; + // First Octet of the TPDU. 41 means SMS SUBMIT, no validity period, no status report, use User Data Header. + // 01 means SMS SUBMIT, no validity period, no status report, NO User Data Header. + if (msg_parts > 1) { // concatenated, must use UDH + pdu[x++] = '4'; + } else { + pdu[x++] = '0'; + } + pdu[x++] = '1'; + // assign a message reference automatically. We have defined TP-RD bit as 0 so duplicates are not rejected. + pdu[x++] = '0'; + pdu[x++] = '0'; + // [6] and [7] Length of the Destination Phone Number + int_to_hex_str(number_len, pdu+x); + x+=2; + // Type of the Destination Phone Number + pdu[x++] = '8'; + pdu[x++] = '1'; + + // phone number as reverse nibble encoded + int i = 0; + for (; i < number_len; i += 2) { + if (i+1 == number_len) { + pdu[x++] = 'f'; + } else { + pdu[x++] = phone_number[i+1]; + } + pdu[x++] = phone_number[i]; + } + + // Protocol Identifier + pdu[x++] = '0'; + pdu[x++] = '0'; + // Data Coding Scheme, GSM 7-bit default alphabet = '00', 8-bit '04' + pdu[x++] = '0'; + + if (_use_8bit_encoding) { + pdu[x++] = '4'; + } else { + pdu[x++] = '0'; + } + + // possible to use 16 bit identifier, can't be defined yet from outside + bool use_16_bit_identifier = false; + uint8_t udhlen = 0; + // Length can be update after we have created PDU, store position for later use. + int lengthPos = x; + x +=2; + + int paddingBits = 0; + if (msg_parts > 1) { // concatenated, must use UDH + // user data header length in chars + pdu[x++] = '0'; + if (use_16_bit_identifier) { + udhlen = 7; // udh length in chars (6) + udhl length in chars + pdu[x++] = '6'; + } else { + udhlen = 6; // udh length in chars (5) + udhl length in chars + pdu[x++] = '5'; + } + // Information element identifier + pdu[x++] = '0'; + if (use_16_bit_identifier) { + pdu[x++] = '8'; + } else { + pdu[x++] = '0'; + } + // Information element data length + pdu[x++] = '0'; + if (use_16_bit_identifier) { + pdu[x++] = '4'; + } else { + pdu[x++] = '3'; + } + // A reference number (must be the same for all parts of the same larger messages) + int_to_hex_str(_sms_message_ref_number&0xFF, pdu+x); + x +=2; + if (use_16_bit_identifier) { + int_to_hex_str((_sms_message_ref_number>>16)&0xFF, pdu+x); + x +=2; + } + // How many parts does this message have? + int_to_hex_str(msg_parts, pdu+x); + x +=2; + // this is a part number + int_to_hex_str(msg_part_number, pdu+x); + x +=2; + + // if there is padding bits then udhlen is octet bigger as we need to keep septet boundary + paddingBits = (udhlen * 8 ) % 7; + if (paddingBits) { + paddingBits = 7 - paddingBits; + udhlen += 1; + } + } + + if (_use_8bit_encoding) { + char_str_to_hex_str(message, message_length, pdu+x); + } else { + // we might need to send zero length sms + if (message_length) { + if (pack_7_bit_gsm_and_hex(message, message_length, pdu+x, paddingBits) == 0) { + free(pdu); + return NULL; + } + } + } + + // now we know the correct length of the UDL (User Data Length) + int_to_hex_str(message_length + udhlen, pdu+lengthPos); + header_size = x; + + return pdu; +} + +nsapi_size_or_error_t AT_CellularSMS::send_sms(const char* phone_number, const char* message, int msg_len) +{ + int single_sms_max_length = _use_8bit_encoding ? SMS_MAX_SIZE_8BIT_SINGLE_SMS_SIZE : + SMS_MAX_SIZE_GSM7_SINGLE_SMS_SIZE; + if ((_mode == CellularSMSMmodeText && msg_len > single_sms_max_length) || !phone_number) { + return NSAPI_ERROR_PARAMETER; + } + + _at.lock(); + + int write_size = 0; + int remove_plus_sign = (phone_number[0] == '+') ? 1 : 0; + + wait_ms(_sim_wait_time); + + if (_mode == CellularSMSMmodeText) { + _at.cmd_start("AT+CMGS="); + _at.write_string(phone_number+remove_plus_sign); + _at.cmd_stop(); + + wait_ms(_sim_wait_time); + _at.resp_start("> ", true); + + if (_at.get_last_error() == NSAPI_ERROR_OK) { + write_size = _at.write_bytes((uint8_t*)message, msg_len); + if (write_size < msg_len) { + // sending can be cancelled by giving character (IRA 27). + _at.cmd_start(ESC); + _at.cmd_stop(); + _at.unlock(); + return write_size; + } + // (IRA 26) must be used to indicate the ending of the message body. + _at.cmd_start(CTRL_Z); + _at.cmd_stop(); + _at.resp_start("+CMGS:"); + _at.resp_stop(); + } + } else { + // supports uncompressed 8 bit data and GSM 7 bit default alphabet data. Current implementation uses only + // GSM 7 bit default but support is done for 8 bit data. + int sms_count; + int concatenated_sms_length = _use_8bit_encoding ? SMS_MAX_8BIT_CONCATENATED_SINGLE_SMS_SIZE : + SMS_MAX_GSM7_CONCATENATED_SINGLE_SMS_SIZE; + + if (msg_len <= single_sms_max_length) { + // single message + sms_count = 1; + } else { + // concatenated message + sms_count = msg_len/concatenated_sms_length; + if (msg_len%concatenated_sms_length != 0) { + sms_count++; + } + } + + int remaining_len = msg_len; + int pdu_len; + int msg_write_len = 0; + uint8_t header_len; + char *pdu_str; + for (int i = 0; i < sms_count; i++) { + + header_len = 0; + if (sms_count == 1) { + pdu_len = msg_len; + } else { + pdu_len = remaining_len > concatenated_sms_length ? concatenated_sms_length : remaining_len; + } + + pdu_str = create_pdu(phone_number+remove_plus_sign, message + i*concatenated_sms_length, pdu_len, + sms_count, i+1, header_len); + if (!pdu_str) { + _at.unlock(); + return NSAPI_ERROR_NO_MEMORY; + } + pdu_len = strlen(pdu_str); + + // specification says that service center number should not be included so we subtract -2 from pdu_len as we use '00' for automatic service center number + _at.cmd_start("AT+CMGS="); + _at.write_int((pdu_len-2)/2); + _at.cmd_stop(); + + wait_ms(_sim_wait_time); + _at.resp_start("> ", true); + + if (_at.get_last_error() == NSAPI_ERROR_OK) { + write_size = _at.write_bytes((uint8_t*)pdu_str, pdu_len); + if (write_size < pdu_len) { + // calculate exact size of what we have send + if (write_size <= header_len) { + // managed only to write header or some of it so actual msg write size in this iteration is 0 + write_size = 0; + } else { + write_size = (write_size - header_len)/2; // as hex encoded so divide by two + } + msg_write_len += write_size; + + // sending can be cancelled by giving character (IRA 27). + _at.cmd_start(ESC); + _at.cmd_stop(); + _at.unlock(); + free(pdu_str); + return msg_write_len; + } + + // (IRA 26) must be used to indicate the ending of the message body. + _at.cmd_start(CTRL_Z); + _at.cmd_stop(); + _at.resp_start("+CMGS:"); + _at.resp_stop(); + } + free(pdu_str); + remaining_len -= concatenated_sms_length; + if (_at.get_last_error() != NSAPI_ERROR_OK) { + return _at.unlock_return_error(); + } + } + } + + _sms_message_ref_number++; + nsapi_error_t ret = _at.get_last_error(); + _at.unlock(); + + return (ret == NSAPI_ERROR_OK) ? msg_len : ret; +} + +void AT_CellularSMS::set_sms_callback(Callback func) +{ + _cb = func; +} + +nsapi_error_t AT_CellularSMS::set_cpms(const char *memr, const char *memw, const char *mems) +{ + _at.lock(); + _at.cmd_start("AT+CPMS="); + _at.write_string(memr); + _at.write_string(memw); + _at.write_string(mems); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularSMS::set_csca(const char *sca, int type) +{ + _at.lock(); + _at.cmd_start("AT+CSCA="); + _at.write_string(sca); + _at.write_int(type); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + + return _at.unlock_return_error(); +} + +nsapi_size_or_error_t AT_CellularSMS::set_cscs(const char *chr_set) +{ + _at.lock(); + _at.cmd_start("AT+CSCS="); + _at.write_string(chr_set); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularSMS::delete_sms(sms_info_t* sms) +{ + _at.lock(); + for (int i = 0; i < sms->parts; i++) { + _at.cmd_start("AT+CMGD="); + _at.write_int(sms->msg_index[i]); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + } + + return _at.unlock_return_error(); +} + +// we need this as for example concatenated sms can get different sms reference numbers +// if for example last part take much more time to arrive. This situation happened while testing. +// What this means that after this we can't read another sms because we always read the oldest sms +// that was corrupted. So we need to have delete all messages. +nsapi_error_t AT_CellularSMS::delete_all_messages() +{ + _at.lock(); + _at.cmd_start("AT+CMGD=1,4"); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + return _at.unlock_return_error(); +} + +// read msg in text mode +nsapi_size_or_error_t AT_CellularSMS::read_sms_from_index(int msg_index, char* buf, uint16_t len, char* phone_num, + char* time_stamp) +{ + /* + * +CMGR: ,,,[,,,,,,,]OK + */ + wait_ms(_sim_wait_time); + _at.cmd_start("AT+CMGR="); + _at.write_int(msg_index); + _at.cmd_stop(); + + // TODO: NOTE: If the selected can contain different types of SMs (e.g. SMS-DELIVERs, SMS-SUBMITs, SMS-STATUS-REPORTs and SMS-COMMANDs), + // the response may be a mix of the responses of different SM types. TE application can recognize the response format by examining the third response parameter. + // for now we support sms reading of received messages + int buf_len = 0; + if (_at.get_last_error() == NSAPI_ERROR_OK) { + char status[SMS_STATUS_SIZE]; + // first we read msg status and with that we can decide how the rest of message format + _at.resp_start("+CMGR:"); + + if (_at.info_resp()) { + _at.read_string(status, SMS_STATUS_SIZE); + uint16_t status_len = strlen(status); + if (((status_len == sizeof("REC READ") - 1) && memcmp("REC READ", status, status_len) == 0) + || ((status_len == sizeof("REC UNREAD") - 1) && memcmp("REC UNREAD", status, status_len) == 0)) { + // Received message + if (phone_num) { + _at.read_string(phone_num, SMS_MAX_PHONE_NUMBER_SIZE); + } + else { + _at.skip_param(); // , + } + _at.skip_param(); // + if (time_stamp) { + _at.read_string(time_stamp, SMS_MAX_TIME_STAMP_SIZE); + } + (void)_at.consume_to_stop_tag(); // consume until + if (buf) { + _at.read_string(buf, len); + buf_len = strlen(buf); + } + } + } + _at.resp_stop(); + } + + return (_at.get_last_error() == NSAPI_ERROR_OK) ? buf_len : _at.get_last_error(); +} + +// read msg in PDU mode +nsapi_size_or_error_t AT_CellularSMS::read_sms(sms_info_t* sms, char* buf, char* phone_num, char* time_stamp) +{ + // +CMGR: ,[], + int index = -1; + if (sms->parts == sms->parts_added) { + char *pdu; // we need a temp buffer as payload is hexencoded ---> can't use buf as it might be enough for message but not hexenconded pdu. + int status = -1; + int msg_len = 0; + index = 0; + int pduSize = 0; + + for (int i = 0; i < sms->parts; i++) { + wait_ms(_sim_wait_time); + _at.cmd_start("AT+CMGR="); + _at.write_int(sms->msg_index[i]); + _at.cmd_stop(); + _at.resp_start("+CMGR:"); + + if (_at.info_resp()) { + status = _at.read_int(); + _at.skip_param(); // + if ((_at.get_last_error() == NSAPI_ERROR_OK) && (status == 0 || status == 1)) { + msg_len = _at.read_int(); + if (msg_len > 0) { + pduSize = msg_len*2 + 20;// *2 as it's hex encoded and +20 as service center number is not included in size given by CMGR + pdu = (char*)calloc(pduSize, sizeof(char)); + if (!pdu) { + _at.resp_stop(); + return NSAPI_ERROR_NO_MEMORY; + } + _at.read_string(pdu, pduSize, true); + if (_at.get_last_error() == NSAPI_ERROR_OK) { + msg_len = get_data_from_pdu(pdu, NULL, NULL, phone_num, buf+index); + if (msg_len >= 0) { // we need to allow zero length messages + index += msg_len; + } else { + free(pdu); + _at.resp_stop(); + return -1; + } + } + free(pdu); + } + } + } + _at.resp_stop(); + } + + if (_at.get_last_error() == NSAPI_ERROR_OK) { + if (time_stamp) { + strcpy(time_stamp, sms->date); + } + buf[index] = '\0'; + } + } + else { + tr_warn("NOT all concatenated parts were received..."); + index = SMS_ERROR_MULTIPART_ALL_PARTS_NOT_READ; + } + + return index; +} + +nsapi_size_or_error_t AT_CellularSMS::get_sms(char* buf, uint16_t len, char* phone_num, uint16_t phone_len, + char* time_stamp, uint16_t time_len, int *buf_size) +{ + // validate buffer sizes already here to avoid any necessary function calls and locking of _at + if ((phone_num && phone_len < SMS_MAX_PHONE_NUMBER_SIZE) || (time_stamp && time_len < SMS_MAX_TIME_STAMP_SIZE) || + buf == NULL) { + return NSAPI_ERROR_PARAMETER; + } + + _at.lock(); + + nsapi_size_or_error_t err = list_messages(); + if (err == NSAPI_ERROR_OK) { + // we return the oldest sms and delete it after successful read + sms_info_t* info = get_oldest_sms_index(); + + if (info) { + if (info->msg_size+1 > len) { // +1 for '\0' + tr_warn("Given buf too small, len is: %d but is must be: %d", len, info->msg_size); + if (buf_size) { + *buf_size = info->msg_size; + } + free_linked_list(); + _at.unlock(); + return NSAPI_ERROR_PARAMETER; + } + + if (_mode == CellularSMSMmodePDU) { + err = read_sms(info, buf, phone_num, time_stamp); + } else { + err = read_sms_from_index(info->msg_index[0], buf, len, phone_num, time_stamp); + } + + if (err > 0) { + int delerr = delete_sms(info); + if (delerr) { + err = delerr; + } + } + } else { + // No messages were found, return -1 + err = -1; + } + } + + free_linked_list(); + + _at.unlock(); + + // update error only when there really was an error, otherwise we return the length + if (_at.get_last_error()) { + err = _at.get_last_error(); + } + return err; +} + + nsapi_size_or_error_t AT_CellularSMS::get_data_from_pdu(const char* pdu, sms_info_t *info, int *part_number, + char *phone_number, char *msg) +{ + int index = 0; + int tmp; + bool userDataHeader; + int oaLength; + int dataScheme; + nsapi_size_or_error_t err = NSAPI_ERROR_OK; + + // read Length of the SMSC information + oaLength = hex_str_to_int(pdu, 2); + index += 2; // length we just read + index += oaLength*2; // skip service center number + + // read first the lower part of first octet as there is message type + index++; + tmp = hex_str_to_int(pdu+index, 1); + //wait_ms(200); + if ((tmp & 0x03) == 0) {// SMS-DELIVER type, last two bits should be zero + // UDH present? Check from first octets higher part + tmp = hex_str_to_int(pdu + (--index), 1); + userDataHeader = ((tmp & 0x04) == 0) ? false : true; + + index +=2; // we just read the high bits of first octet so move +2 + // originating address length + oaLength = hex_str_to_int(pdu+index, 2); + index +=2; // add index over address length + index +=2; // skip number type + if (phone_number) { + // phone number as reverse nibble encoded + int a = 0; + for (; a < oaLength; a +=2) { + if (a+1 == oaLength) { + phone_number[a] = pdu[index+a+1]; + } else { + phone_number[a] = pdu[index+a+1]; + phone_number[a+1] = pdu[index+a]; + } + } + phone_number[oaLength] = '\0'; + } + + index += oaLength; + if (oaLength&0x01) { // if phone number length is odd then it has padded F so skip that + index++; + } + index +=2; // skip TP-Protocol identifier + + dataScheme = hex_str_to_int(pdu+index, 2); + index +=2; // skip TP-Data-Coding-Scheme + + // next one is date, it's length is 7 octets according to 3GPP TS 23.040 + // create time string + if (info) { + int i = 0; + // year + info->date[i++] = pdu[index+1]; + info->date[i++] = pdu[index]; + index+=2; + info->date[i++] = '/'; + // month + info->date[i++] = pdu[index+1]; + info->date[i++] = pdu[index]; + index+=2; + info->date[i++] = '/'; + // Day + info->date[i++] = pdu[index+1]; + info->date[i++] = pdu[index]; + index+=2; + info->date[i++] = ','; + // Hour + info->date[i++] = pdu[index+1]; + info->date[i++] = pdu[index]; + index+=2; + info->date[i++] = ':'; + // Minute + info->date[i++] = pdu[index+1]; + info->date[i++] = pdu[index]; + index+=2; + info->date[i++] = ':'; + // Second + info->date[i++] = pdu[index+1]; + info->date[i++] = pdu[index]; + index+=2; + // timezone related to GMT. pdu[index+1] most significant bit indicates the sign related to gmt + tmp = hex_str_to_int(pdu+index+1, 1); + if (tmp&0x08) { + info->date[i++] = '-'; + } else { + info->date[i++] = '+'; + } + + // pdu[index+1 & 0x07 is the most significant bits of the timezone + // pdu [index] is the least significant bits + info->date[i++] = '0' + (tmp & 0x07); + info->date[i++] = pdu[index]; + info->date[i] = '\0'; + index+=2; + } else { + index+=14; + } + + int udl = hex_str_to_int(pdu+index, 2); + index +=2; + + int paddingBits = 0; + int partnro = 1; + if (userDataHeader) { + // we need to read User Defined Header to know what part number this message is. + index += read_udh_from_pdu(pdu+index, info, partnro, paddingBits); + } + + if (part_number) { + *part_number = partnro; + } + + if (msg) { + // we are reading the message + err = read_pdu_payload(pdu+index, udl, dataScheme, msg, paddingBits); + } + else { + if (dataScheme == 0x00) { + // when listing messages we need to calculated length. Other way would be unpacking the whole message. + err = strlen(pdu+index) >> 1; + err *= 8; + err /= 7; + } else if (dataScheme == 0x04) { + err = strlen(pdu+index) >> 1; + } else { + return NSAPI_ERROR_UNSUPPORTED; + } + } + + return err; + } + else { + // message was not DELIVER so discard it + return NSAPI_ERROR_UNSUPPORTED; + } +} + + // read params from User Defined Header +int AT_CellularSMS::read_udh_from_pdu(const char* pdu, sms_info_t *info, int &part_number, int &padding_bits) { + + int index = 0; + int udhLength = hex_str_to_int(pdu, 2); + index +=2; + + // if there is padding bits then udhlen is octet bigger as we need to keep septet boundary + padding_bits = ((udhLength+1) * 8 ) % 7; // +1 is for udhLength itself + + if (padding_bits) { + padding_bits = 7 - padding_bits; + } else { + padding_bits = 0; + } + + int tmp = hex_str_to_int(pdu+index, 2); + index +=4; + + if (tmp == 0) { // 8-bit reference number + if (info) { + info->msg_ref_number = (uint16_t)hex_str_to_int(pdu+index, 2); + } + index +=2; + } else { // 16-bit reference number + if (info) { + info->msg_ref_number = (uint16_t)hex_str_to_int(pdu+index+2, 2); + tmp = hex_str_to_int(pdu+index, 2); + info->msg_ref_number |= (tmp << 8); + } + index +=4; + } + + if (info) { + info->parts = hex_str_to_int(pdu+index, 2); + } + index +=2; + + part_number = hex_str_to_int(pdu+index, 2); + index +=2; + + return (udhLength*2 + 2); // udh in hex and udhl +} + +nsapi_size_or_error_t AT_CellularSMS::read_pdu_payload(const char* pdu, int msg_len, int scheme, char *msg, int padding_bits) +{ + if (scheme == 0x00) { + // 7 bit gsm encoding, must do the conversions from hex to 7-bit encoding and to ascii + return unpack_7_bit_gsm_to_str(pdu, strlen(pdu)/2, msg, padding_bits, msg_len); + } else if (scheme == 0x04) { + // 8bit scheme so just convert hexstring to charstring + return hex_str_to_char_str(pdu, strlen(pdu), msg); + } else { + tr_error("Received unsupported data coding scheme: 0x%02x", scheme); + return NSAPI_ERROR_UNSUPPORTED; + } +} + +void AT_CellularSMS::free_linked_list() +{ + sms_info_t* info = _sms_info; + sms_info_t* old; + while (info) { + old = info; + info = info->next_info; + delete old; + } + _sms_info = NULL; +} + +void AT_CellularSMS::add_info(sms_info_t* info, int index, int part_number) { + // check for same message reference id. If found, update it and delete the given info. + // if NOT found then add to the end of the list. + + if (!_sms_info) { + info->msg_index[part_number-1] = index; // part numbering starts from 1 so -1 to put to right index + _sms_info = info; + return; + } + sms_info_t* current = _sms_info; + sms_info_t* prev; + bool found_msg = false; + while (current) { + prev = current; + // sms messages can have same reference number so additional checks are needed. + // TODO: should we include phone number also? + if (current->msg_ref_number == info->msg_ref_number && current->parts > current->parts_added && + info->parts > info->parts_added) { + // multipart sms, update msg size and index + current->msg_size += info->msg_size; + current->msg_index[part_number-1] = index; // part numbering starts from 1 so -1 to put to right index + current->parts_added++; + // update oldest part as date + if (compare_time_strings(info->date, current->date) == -1) { + strcpy(current->date, info->date); + } + found_msg = true; + break; + } + current = current->next_info; + } + + if (found_msg) { + // info was added to existing item in linked list, must be deleted + delete info; + } else { + // message not found, add to linked list + info->msg_index[part_number-1] = index; + prev->next_info = info; + } +} + +// reads all the messages to the linked list AT_CellularSMS::_sms_info +nsapi_error_t AT_CellularSMS::list_messages() +{ + // TODO: NOTE: If the selected can contain different types of SMs (e.g. SMS-DELIVERs, SMS-SUBMITs, SMS-STATUS-REPORTs and SMS-COMMANDs), + // the response may be a mix of the responses of different SM types. TE application can recognize the response format by examining the third response parameter. + // for now we assume that only SMS-DELIVER messages are read. + if (_mode == CellularSMSMmodePDU) { + _at.cmd_start("AT+CMGL=4"); + } else { + _at.cmd_start("AT+CMGL=\"ALL\""); + } + _at.cmd_stop(); + + sms_info_t* info = NULL; + // init for 1 so that in text mode we will add to the correct place without any additional logic in addInfo() in text mode + int part_number = 1; + int index = 0; + int length = 0; + char *pdu = NULL; + + _at.resp_start("+CMGL:"); + while (_at.info_resp()) { + info = new sms_info_t(); + if (!info) { + _at.resp_stop(); + return NSAPI_ERROR_NO_MEMORY; + } + + if (_mode == CellularSMSMmodePDU) { + //+CMGL: ,,[],[ + // +CMGL:,,[], + //[...]] + index = _at.read_int(); + _at.skip_param(2); // ,[] + length = _at.read_int(); + length = length*2 + 20;// *2 as it's hex encoded and +20 as service center number is not included in size given by CMGL + pdu = (char*)calloc(length, sizeof(char)); + if (!pdu) { + delete info; + _at.resp_stop(); + return NSAPI_ERROR_NO_MEMORY; + } + _at.read_string(pdu, length, true); + if (_at.get_last_error() == NSAPI_ERROR_OK) { + info->msg_size = get_data_from_pdu(pdu, info, &part_number); + } + } else { + // +CMGL: ,,,[],[][,,][ + // +CMGL: ,,,[],[][,,][...]] + index = _at.read_int(); + (void)_at.consume_to_stop_tag(); // consume until + (void)_at.consume_to_stop_tag(); // consume until + } + + if (index > 0) { + add_info(info, index, part_number); + } else { + delete info; + info = NULL; + } + free(pdu); + pdu = NULL; + } + + + _at.resp_stop(); + + return _at.get_last_error(); +} + +AT_CellularSMS::sms_info_t* AT_CellularSMS::get_oldest_sms_index() +{ + /* + * Different scenarios when finding the oldest concatenated sms + * + * 1. Find first parts first and it was received first + * 2. Find first parts first and it was NOT received first -> older timestamp might exist in some other part + * 3. Find other than first part first and it was received first + * 4. Find other than first part first and it was NOT received first -> older timestamp might exist in some other part + * + * So must take all message to a linked list and loop that for the oldest + */ + + // if text mode we need to read sms with +CMGR because time stamp is optional while looping with +CMGL + sms_info_t* retVal = NULL; + sms_info_t* current = _sms_info; + nsapi_size_or_error_t err = 0; + while (current) { + if (_mode == CellularSMSMmodeText) { + wait_ms(_sim_wait_time); + err = read_sms_from_index(current->msg_index[0], NULL, 0, NULL, current->date); + if (err != 0) { + return NULL; + } + } + + if (retVal == NULL) { + retVal = current; + } else if (compare_time_strings(current->date, retVal->date) == -1) { + // found older sms, update return value to oldest + retVal = current; + } + current = current->next_info; + } + + return retVal; +} + +// if time_string_1 is greater (more fresh date) then return 1, same 0, smaller -1. Error -2 +int AT_CellularSMS::compare_time_strings(const char* time_string_1, const char* time_string_2) +{ + time_t t1; + time_t t2; + + bool success = create_time(time_string_1, &t1) && create_time(time_string_2, &t2); + int retVal = -2; + + if (success) { + double diff = difftime(t1, t2); + + if (diff > 0) { + retVal = 1; + } else if (diff == 0) { + retVal = 0; + } else { + retVal = -1; + } + } + + return retVal; +} + +bool AT_CellularSMS::create_time(const char* time_string, time_t* time) +{ + const int kNumberOfElements = 8; + tm time_struct = { 0 }; + int gmt = 0; + char sign; + bool retVal = false; + + if (sscanf(time_string, "%d/%d/%d,%d:%d:%d%c%d", &time_struct.tm_year, &time_struct.tm_mon, &time_struct.tm_mday, + &time_struct.tm_hour, &time_struct.tm_min, &time_struct.tm_sec, &sign, &gmt) == kNumberOfElements) { + *time = mktime(&time_struct); + // add timezone as seconds. gmt is in quarter of hours. + int x = 60 * 60 * gmt * 0.25; + if (sign == '+') { + *time += x; + } else { + *time -= x; + } + retVal = true; + } + + return retVal; +} + +uint16_t AT_CellularSMS::pack_7_bit_gsm_and_hex(const char* str, uint16_t len, char *buf, + int number_of_padding_bit) +{ + uint16_t strCnt = 0; + uint16_t i = 0; + uint8_t shift; + char tmp; + + // convert to 7bit gsm first + char* gsm_str = (char*)malloc(len); + if (!gsm_str) { + return 0; + } + for (uint16_t y = 0; y < len; y++) { + for (int x=0; x < GSM_TO_ASCII_TABLE_SIZE; x++) { + if (gsm_to_ascii[x] == str[y]) { + gsm_str[y] = x; + } + } + } + + // then packing and converting to hex + if (number_of_padding_bit) { + tmp = gsm_str[strCnt]<>shift); + } else { + tmp = (gsm_str[strCnt]>>shift) | (gsm_str[strCnt+1] <<(7-shift)); + } + + char_str_to_hex_str(&tmp, 1, buf+(i*2)); + + if (shift == 6) { + strCnt++; + } + strCnt++; + i++; + } + + free(gsm_str); + + return i; +} + + uint16_t AT_CellularSMS::unpack_7_bit_gsm_to_str(const char* str, int len, char *buf, int padding_bits, + int msg_len) +{ + int strCount = 0; + uint16_t decodedCount = 0; + uint8_t shift; + char tmp; + char tmp1; + + if (padding_bits) { + hex_str_to_char_str(str, 2, &tmp); + buf[decodedCount] = gsm_to_ascii[(tmp>>padding_bits) & 0x7F]; + strCount++; + decodedCount++; + } + + while (strCount < len) { + shift = (strCount-padding_bits)%7; + hex_str_to_char_str(str + strCount*2, 2, &tmp); + if (shift == 0) { + buf[decodedCount] = gsm_to_ascii[tmp & 0x7F]; + } else if (shift == 6) { + hex_str_to_char_str(str + (strCount-1)*2, 2, &tmp1); + buf[decodedCount] = gsm_to_ascii[(((tmp1>>2)) | (tmp << 6)) & 0x7F]; + if (decodedCount+1 < msg_len) { + hex_str_to_char_str(str + strCount*2, 2, &tmp); + decodedCount++; + buf[decodedCount] = gsm_to_ascii[(tmp>>1) & 0x7F]; + } + } else { + hex_str_to_char_str(str + (strCount-1)*2, 2, &tmp1); + buf[decodedCount] = gsm_to_ascii[(((tmp1>>(8- shift))) | ((tmp << shift))) & 0x7F]; + } + + strCount++; + decodedCount++; + } + + return decodedCount; +} diff --git a/features/cellular/framework/AT/AT_CellularSMS.h b/features/cellular/framework/AT/AT_CellularSMS.h new file mode 100644 index 0000000000..46080518e8 --- /dev/null +++ b/features/cellular/framework/AT/AT_CellularSMS.h @@ -0,0 +1,170 @@ +/* + * Copyright (c) 2017, 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 AT_CELLULAR_SMS_H_ +#define AT_CELLULAR_SMS_H_ + +#include "CellularSMS.h" +#include "AT_CellularBase.h" +#include "Callback.h" +#include + +namespace mbed { + +/** + * Class AT_CellularSMS + * + * Class for SMS sending, reading and deleting. + */ +class AT_CellularSMS: public CellularSMS, public AT_CellularBase +{ + +public: + AT_CellularSMS(ATHandler &atHandler); + virtual ~AT_CellularSMS(); + +public: + // from CellularSMS + + virtual nsapi_error_t initialize(CellularSMSMmode mode); + + virtual nsapi_size_or_error_t send_sms(const char* phone_number, const char* message, int msg_len); + + virtual nsapi_size_or_error_t get_sms(char* buf, uint16_t buf_len, char* phone_num, uint16_t phone_len, + char* time_stamp, uint16_t time_len, int *buf_size); + + virtual void set_sms_callback(Callback func); + + virtual nsapi_error_t set_cpms(const char *memr, const char *memw, const char *mems); + + virtual nsapi_error_t set_csca(const char *sca, int type); + + virtual nsapi_size_or_error_t set_cscs(const char *chr_set); + + virtual nsapi_error_t delete_all_messages(); + + virtual void set_extra_sim_wait_time(int sim_wait_time); + +private: + + struct sms_info_t { + char date[SMS_MAX_TIME_STAMP_SIZE]; + uint16_t msg_index[50]; // can hold up to 50 concatenated msg parts, indexes are in correct order. So max sms size is 50*140 = 7kb + uint16_t msg_size; + uint8_t parts; + uint8_t parts_added; + uint16_t msg_ref_number; + struct sms_info_t *next_info; + sms_info_t() : msg_size(0), parts(1), parts_added(1), msg_ref_number(0), next_info(0){}; + }; + + // application callback function for received sms + Callback _cb; + CellularSMSMmode _mode; + bool _use_8bit_encoding; + uint32_t _sim_wait_time; + uint16_t _sms_message_ref_number; + sms_info_t *_sms_info; + + // SMS urc's + void cmt_urc(); + void cmti_urc(); + + /** Set command selects the format of messages used with send, list, read and write commands. + * + * @param msg_format 0 PDU mode, 1 text mode + * @return zero for success + */ + nsapi_error_t set_cmgf(int msg_format); + + /** Set how receiving of new messages from the network is indicated to the TE. + * + * @return zero for success + */ + nsapi_error_t set_cnmi(); + + /** Set Text Mode Parameters + * + * @param fo See more from 3GPP TS 27.005 for all params. + * @param vp + * @param pid + * @param dcs + * @return zero for success + */ + nsapi_error_t set_csmp(int fo, int vp, int pid, int dcs); + + /** CSDH - Set command controls whether detailed header information is shown in text mode (AT+CMGF=1) result codes. + * + * @param show_header 1 to show detailed header in text mode, 0 for not showing. + * @return zero for success + */ + nsapi_error_t set_csdh(int show_header); + + /** Delete SMS in the given message position(s) in the storage + * + * @param sms struct containing index array to delete + * @return zero for success + */ + nsapi_error_t delete_sms(sms_info_t* sms); + + /** + * Internal helper methods + */ + nsapi_error_t list_messages(); + int read_sms_params(char *, char *); + void free_linked_list(); + void add_info(sms_info_t* info, int index, int part_number); + int read_udh_from_pdu(const char* pdu, sms_info_t *info, int &part_number, int &padding_bits); + nsapi_size_or_error_t get_data_from_pdu(const char* pdu, sms_info_t *info, int *part_number, + char *phone_number = NULL, char *msg = NULL); + nsapi_size_or_error_t read_pdu_payload(const char* pdu, int msg_len, int scheme, char *msg, int padding_bits); + sms_info_t* get_oldest_sms_index(); + bool create_time(const char* time_string, time_t* time); + int compare_time_strings(const char* time_string_1, const char* time_string_2); + char* create_pdu(const char* phone_number, const char* message, uint8_t message_length, uint8_t msg_parts, + uint8_t msg_part_number, uint8_t& header_size); + nsapi_size_or_error_t read_sms_from_index(int msg_index, char* buf, uint16_t len, char* phone_num, + char* time_stamp); + nsapi_size_or_error_t read_sms(sms_info_t* sms, char* buf, char* phone_num, char* time_stamp); + + /** Packs the given str from ascii to 7bit gsm format and converts it to hex to the given buf. + * + * @param str string that is to be converted + * @param len length of the str buffer + * @param buf preallocated buffer that holds the converted string in hex format after successful call + * @param number_of_padding_bit padding bits needed to keep the octet boundary + * @return length of buffer buf or zero on failure + */ + uint16_t pack_7_bit_gsm_and_hex(const char* str, uint16_t len, char *buf, int number_of_padding_bit); + + /** Unpacks the given hex- and 7-bit gsm encoded str to ascii string + * + * @param str string to convert to ascii string and write to buf + * @param len length of the str divided by two as str is hexencoded + * @param buf preallocated destination buffer + * @param padding_bits number of padding bits needed to hold the octet boundary + * @param msg_len Length of the received message, which is coded in str + * @return length of the destination buffer buf + * + */ + uint16_t unpack_7_bit_gsm_to_str(const char* str, int len, char *buf, int padding_bits, + int msg_len); +}; + +} // namespace mbed + +#endif // AT_CELLULAR_SMS_H_ diff --git a/features/cellular/framework/AT/AT_CellularStack.cpp b/features/cellular/framework/AT/AT_CellularStack.cpp new file mode 100644 index 0000000000..5abd1fffdb --- /dev/null +++ b/features/cellular/framework/AT/AT_CellularStack.cpp @@ -0,0 +1,300 @@ +/* + * Copyright (c) 2017, 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 "AT_CellularStack.h" +#include "CellularUtil.h" +#include "CellularLog.h" + +using namespace mbed_cellular_util; +using namespace mbed; + +AT_CellularStack::AT_CellularStack(ATHandler &at, int cid, nsapi_ip_stack_t stack_type) : AT_CellularBase(at), _socket(NULL),_socket_count(0),_cid(cid), _stack_type(stack_type) +{ + memset(_ip,0, PDP_IPV6_SIZE); +} + +AT_CellularStack::~AT_CellularStack() +{ + for (int i = 0; i < _socket_count; i++) { + if (_socket[i]) { + delete _socket[i]; + _socket[i] = NULL; + } + } + _socket_count = 0; + + delete [] _socket; + _socket = NULL; +} + +/** NetworkStack + */ + +const char * AT_CellularStack::get_ip_address() +{ + _at.lock(); + + _at.cmd_start("AT+CGPADDR="); + _at.write_int(_cid); + _at.cmd_stop(); + + _at.resp_start("+CGPADDR:"); + + if (_at.info_resp()) { + + _at.skip_param(); + + int len = _at.read_string(_ip, NSAPI_IPv4_SIZE-1); + if (len == -1) { + _ip[0] = '\0'; + _at.unlock(); + // no IPV4 address, return + return NULL; + } + + // in case stack type is not IPV4 only, try to look also for IPV6 address + if (_stack_type != IPV4_STACK) { + len = _at.read_string(_ip, PDP_IPV6_SIZE-1); + } + } + + _at.resp_stop(); + _at.unlock(); + + // we have at least IPV4 address + convert_ipv6(_ip); + + return _ip; +} + +nsapi_error_t AT_CellularStack::socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto) +{ + if (!is_protocol_supported(proto) || !handle) { + return NSAPI_ERROR_UNSUPPORTED; + } + + int max_socket_count = get_max_socket_count(); + + if (!_socket) { + _socket = new CellularSocket*[max_socket_count]; + if (!_socket) { + return NSAPI_ERROR_NO_SOCKET; + } + _socket_count = max_socket_count; + for (int i = 0; i < max_socket_count; i++) { + _socket[i] = 0; + } + } + + int index = -1; + for (int i = 0; i < max_socket_count; i++) { + if (!_socket[i]) { + index = i; + break; + } + } + + if (index == -1) { + return NSAPI_ERROR_NO_SOCKET; + } + + // create local socket structure, socket on modem is created when app calls sendto/recvfrom + _socket[index] = new CellularSocket; + CellularSocket *psock; + psock = _socket[index]; + memset(psock, 0, sizeof(CellularSocket)); + SocketAddress addr(0, get_dynamic_ip_port()); + psock->id = index; + psock->localAddress = addr; + psock->proto = proto; + *handle = psock; + + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularStack::socket_close(nsapi_socket_t handle) +{ + int err = NSAPI_ERROR_DEVICE_ERROR; + + struct CellularSocket *socket = (struct CellularSocket *)handle; + if (!socket){ + return err; + } + int sock_id = socket->id; + int max_socket_count = get_max_socket_count(); + + int index = -1; + for (int i = 0; i < max_socket_count; i++) { + if (_socket[i] && _socket[i]->id == sock_id) { + index = i; + break; + } + } + + if (index == -1) { + return err; + } + _socket[index] = NULL; + err = NSAPI_ERROR_OK; + + _at.lock(); + + err = socket_close_impl(sock_id); + + _at.unlock(); + + delete socket; + socket = NULL; + + return err; +} + +nsapi_error_t AT_CellularStack::socket_bind(nsapi_socket_t handle, const SocketAddress &addr) +{ + struct CellularSocket *socket = (CellularSocket *)handle; + if (!socket) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + if (addr) { + socket->localAddress.set_addr(addr.get_addr()); + } + + if (addr.get_port()) { + socket->localAddress.set_port(addr.get_port()); + } + + _at.lock(); + + if (!socket->created) { + create_socket_impl(socket); + } + + return _at.unlock_return_error(); +} + +nsapi_error_t AT_CellularStack::socket_listen(nsapi_socket_t handle, int backlog) +{ + return NSAPI_ERROR_UNSUPPORTED;; +} + +nsapi_error_t AT_CellularStack::socket_connect(nsapi_socket_t handle, const SocketAddress &addr) +{ + CellularSocket *socket = (CellularSocket *)handle; + if (!socket) { + return NSAPI_ERROR_DEVICE_ERROR; + } + socket->remoteAddress = addr; + socket->connected = true; + + return NSAPI_ERROR_OK; +} + +nsapi_error_t AT_CellularStack::socket_accept(void *server, void **socket, SocketAddress *addr) +{ + return NSAPI_ERROR_UNSUPPORTED;; +} + +nsapi_size_or_error_t AT_CellularStack::socket_send(nsapi_socket_t handle, const void *data, unsigned size) +{ + CellularSocket *socket = (CellularSocket *)handle; + if (!socket || !socket->connected) { + return NSAPI_ERROR_DEVICE_ERROR; + } + return socket_sendto(handle, socket->remoteAddress, data, size); +} + +nsapi_size_or_error_t AT_CellularStack::socket_sendto(nsapi_socket_t handle, const SocketAddress &addr, const void *data, unsigned size) +{ + CellularSocket *socket = (CellularSocket *)handle; + if (!socket) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + nsapi_size_or_error_t ret_val = NSAPI_ERROR_OK; + + if (!socket->created) { + _at.lock(); + + ret_val = create_socket_impl(socket); + + _at.unlock(); + if (ret_val != NSAPI_ERROR_OK) { + return ret_val; + } + } + + unsigned max_packet_size = get_max_packet_size(); + + /* Check parameters */ + if (addr.get_ip_version() == NSAPI_UNSPEC || + size > max_packet_size) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + _at.lock(); + + ret_val = socket_sendto_impl(socket, addr, data, size); + + _at.unlock(); + + return ret_val; +} + +nsapi_size_or_error_t AT_CellularStack::socket_recv(nsapi_socket_t handle, void *data, unsigned size) +{ + return socket_recvfrom(handle, NULL, data, size); +} + +nsapi_size_or_error_t AT_CellularStack::socket_recvfrom(nsapi_socket_t handle, SocketAddress *addr, void *buffer, unsigned size) +{ + CellularSocket *socket = (CellularSocket *)handle; + if (!socket) { + return NSAPI_ERROR_DEVICE_ERROR; + } + + nsapi_size_or_error_t ret_val = NSAPI_ERROR_OK; + + if (!socket->created) { + _at.lock(); + + ret_val = create_socket_impl(socket); + + _at.unlock(); + if (ret_val != NSAPI_ERROR_OK) { + return ret_val; + } + } + + _at.lock(); + + ret_val = socket_recvfrom_impl(socket, addr, buffer, size); + + _at.unlock(); + + return ret_val; +} + +void AT_CellularStack::socket_attach(nsapi_socket_t handle, void (*callback)(void *), void *data) +{ + CellularSocket *socket = (CellularSocket *)handle; + if (!socket) { + return; + } + socket->_cb = callback; + socket->_data = data; +} diff --git a/features/cellular/framework/AT/AT_CellularStack.h b/features/cellular/framework/AT/AT_CellularStack.h new file mode 100644 index 0000000000..fe6ee44095 --- /dev/null +++ b/features/cellular/framework/AT/AT_CellularStack.h @@ -0,0 +1,169 @@ +/* + * Copyright (c) 2017, 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 AT_CELLULAR_STACK_H_ +#define AT_CELLULAR_STACK_H_ + +#include "AT_CellularBase.h" +#include "NetworkStack.h" + +namespace mbed { + +// and : each is a string type that identifies the MT in the address space applicable to the PDP. +// The string is given as dot-separated numeric (0-255) parameter of the form: +// a1.a2.a3.a4 for IPv4 and +// a1.a2.a3.a4.a5.a6.a7.a8.a9.a10.a11.a12.a13.a14.a15.a16 for IPv6. +#define PDP_IPV6_SIZE 63+1 + +/** + * Class AT_CellularStack. + * + * Implements NetworkStack and introduces interface for modem specific stack implementations. + */ +class AT_CellularStack : public NetworkStack, public AT_CellularBase +{ + +public: + AT_CellularStack(ATHandler &at, int cid, nsapi_ip_stack_t stack_type); + virtual ~AT_CellularStack(); + +public: // NetworkStack + + virtual const char *get_ip_address(); +protected: // NetworkStack + + virtual nsapi_error_t socket_open(nsapi_socket_t *handle, nsapi_protocol_t proto); + + virtual nsapi_error_t socket_close(nsapi_socket_t handle); + + virtual nsapi_error_t socket_bind(nsapi_socket_t handle, const SocketAddress &address); + + virtual nsapi_error_t socket_listen(nsapi_socket_t handle, int backlog); + + virtual nsapi_error_t socket_connect(nsapi_socket_t handle, const SocketAddress &address); + + virtual nsapi_error_t socket_accept(nsapi_socket_t server, + nsapi_socket_t *handle, SocketAddress *address=0); + + virtual nsapi_size_or_error_t socket_send(nsapi_socket_t handle, + const void *data, nsapi_size_t size); + + virtual nsapi_size_or_error_t socket_recv(nsapi_socket_t handle, + void *data, nsapi_size_t size); + + virtual nsapi_size_or_error_t socket_sendto(nsapi_socket_t handle, const SocketAddress &address, + const void *data, nsapi_size_t size); + + virtual nsapi_size_or_error_t socket_recvfrom(nsapi_socket_t handle, SocketAddress *address, + void *buffer, nsapi_size_t size); + + virtual void socket_attach(nsapi_socket_t handle, void (*callback)(void *), void *data); + +protected: + + class CellularSocket + { + public: + // Socket id from cellular device + int id; + // Being connected means remote ip address and port are set + bool connected; + nsapi_protocol_t proto; + SocketAddress remoteAddress; + SocketAddress localAddress; + void (*_cb)(void *); + void *_data; + bool created; + bool rx_avail; // used to synchronize reading from modem + }; + + /** + * Gets maximum number of sockets modem supports + */ + virtual int get_max_socket_count() = 0; + + /** + * Gets maximum packet size + */ + virtual int get_max_packet_size() = 0; + + /** + * Checks if modem supports the given protocol + * + * @param protocol Protocol type + */ + virtual bool is_protocol_supported(nsapi_protocol_t protocol) = 0; + + /** + * Implements modem specific AT command set for socket closing + * + * @param sock_id Socket id + */ + virtual nsapi_error_t socket_close_impl(int sock_id) = 0; + + /** + * Implements modem specific AT command set for creating socket + * + * @param socket Cellular socket handle + */ + virtual nsapi_error_t create_socket_impl(CellularSocket *socket) = 0; + + /** + * Implements modem specific AT command set for sending data + * + * @param socket Cellular socket handle + * @param address The SocketAddress of the remote host + * @param data Buffer of data to send to the host + * @param size Size of the buffer in bytes + * @return Number of sent bytes on success, negative error + * code on failure + */ + virtual nsapi_size_or_error_t socket_sendto_impl(CellularSocket *socket, const SocketAddress &address, + const void *data, nsapi_size_t size) = 0; + + /** + * Implements modem specific AT command set for receiving data + * + * @param socket Socket handle + * @param address Destination for the source address or NULL + * @param buffer Destination buffer for data received from the host + * @param size Size of the buffer in bytes + * @return Number of received bytes on success, negative error + * code on failure + */ + virtual nsapi_size_or_error_t socket_recvfrom_impl(CellularSocket *socket, SocketAddress *address, + void *buffer, nsapi_size_t size) = 0; + + // socket container + CellularSocket **_socket; + + // number of socket slots allocated in socket container + int _socket_count; + + // IP address + char _ip[PDP_IPV6_SIZE]; + + // PDP context id + int _cid; + + // stack type from PDP context + nsapi_ip_stack_t _stack_type; +}; + +} // namespace mbed + +#endif // AT_CELLULAR_STACK_H_ diff --git a/features/cellular/framework/common/CellularList.h b/features/cellular/framework/common/CellularList.h new file mode 100644 index 0000000000..50f9ab7fc4 --- /dev/null +++ b/features/cellular/framework/common/CellularList.h @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2017, 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 CELLULAR_LIST_H_ +#define CELLULAR_LIST_H_ + +#include + +namespace mbed { + +/** Class CellularList + * + * Templated linked list class for common usage. + * + */ +template class CellularList +{ +private: + T *_head, *_tail; +public: + CellularList() + { + _head=NULL; + _tail=NULL; + } + + T* add_new() + { + T *temp=new T; + if (!temp) { + return NULL; + } + temp->next = NULL; + if (_head == NULL) { + _head = temp; + } else { + _tail->next=temp; + } + _tail = temp; + + return _tail; + } + + void delete_last() + { + T* previous = NULL; + T *current=_head; + + if (!current) { + return; + } + + while (current->next != NULL) { + previous=current; + current=current->next; + } + + if (previous) { + _tail=previous; + previous->next=NULL; + } else { + _head = NULL; + _tail = NULL; + } + + delete current; + } + + void delete_all() + { + T *temp = _head; + while (temp) { + _head = _head->next; + delete temp; + temp = _head; + } + } + + + T *get_head() + { + return _head; + } +}; + +} // namespace mbed + +#endif // CELLULAR_LIST_H_ diff --git a/features/cellular/framework/common/CellularLog.h b/features/cellular/framework/common/CellularLog.h new file mode 100644 index 0000000000..1cba633fa7 --- /dev/null +++ b/features/cellular/framework/common/CellularLog.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017, 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 CELLULAR_LOG_H_ +#define CELLULAR_LOG_H_ + +#if defined(HAVE_DEBUG) && !defined(FEA_TRACE_SUPPORT) +#define FEA_TRACE_SUPPORT +#endif + +#if defined(FEATURE_COMMON_PAL) + +#include "mbed-trace/mbed_trace.h" +#ifndef TRACE_GROUP +#define TRACE_GROUP "cellular" +#endif // TRACE_GROUP + +#else + +#define tr_debug(...) (void(0)) +#define tr_info(...) (void(0)) +#define tr_error(...) (void(0)) +#define tr_warn(...) (void(0)) + +#endif // FEATURE_COMMON_PAL + +#endif // CELLULAR_LOG_H_ diff --git a/features/cellular/framework/common/CellularTargets.h b/features/cellular/framework/common/CellularTargets.h new file mode 100644 index 0000000000..f683bd4301 --- /dev/null +++ b/features/cellular/framework/common/CellularTargets.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017, 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 CELLULAR_TARGETS_H_ +#define CELLULAR_TARGETS_H_ + +namespace mbed { + +#ifndef CELLULAR_DEVICE +#if defined(TARGET_ADV_WISE_1570) || defined(TARGET_MTB_ADV_WISE_1570) +#define CELLULAR_DEVICE QUECTEL_BC95 +#elif TARGET_MTS_DRAGONFLY_F411RE +#define CELLULAR_DEVICE TELIT_HE910 +#elif TARGET_MTB_MTS_DRAGONFLY +#define CELLULAR_DEVICE TELIT_HE910 +#elif TARGET_UBLOX_C030 +#define CELLULAR_DEVICE UBLOX_LISA_U +#elif TARGET_UBLOX_C027 +#define CELLULAR_DEVICE UBLOX_LISA_U +#else +//#error Cellular target not defined, see cellular/targets.h +//#define CELLULAR_TARGET +//#define MDMTXD +//#define MDMRXD +#endif +#endif + +} // namespace mbed +#endif // CELLULAR_TARGETS_H_ diff --git a/features/cellular/framework/common/CellularUtil.cpp b/features/cellular/framework/common/CellularUtil.cpp new file mode 100644 index 0000000000..406563951a --- /dev/null +++ b/features/cellular/framework/common/CellularUtil.cpp @@ -0,0 +1,326 @@ +/* + * Copyright (c) , Arm Limited and affiliates. + * SPDX-License-Identifier: Apache-2.0 + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +#include "CellularUtil.h" +#include +#include + +namespace mbed_cellular_util { + +void convert_ipv6(char* ip) +{ + if (!ip) { + return; + } + + int len = strlen(ip); + int pos = 0; + int i; + + for (i = 0; i < len; i++) { + if (ip[i] == '.') { + pos++; + } + if (pos > 3) { + break; + } + } + + // more that 3 periods mean that it was ipv6 but in format of a1.a2.a3.a4.a5.a6.a7.a8.a9.a10.a11.a12.a13.a14.a15.a16 + // we need to convert it to hexadecimal format separated with colons + if (pos > 3) { + pos = 0; + int ip_pos = 0; + char b; + bool set_colon = false; + for (i = 0; i < len; i++) { + if (ip[i] == '.') { + b = (char)strtol (ip+ip_pos, NULL, 10); // convert to char to int so we can change it to hex string + pos += char_str_to_hex_str(&b, 1, ip+pos, !set_colon); // omit leading zeroes with using set_colon flag + if (set_colon) { + ip[pos++] = ':'; + set_colon = false; + } else { + set_colon = true; + } + ip_pos = i+1; // skip the '.' + } + + // handle the last part which does not end with '.' but '\0' + if (i == len -1) { + b = (char)strtol(ip+ip_pos, NULL, 10); + pos += char_str_to_hex_str(&b, 1, ip+pos, !set_colon); + ip[pos] = '\0'; + } + } + } +} + +// For example "32.1.13.184.0.0.205.48.0.0.0.0.0.0.0.0" +void separate_ip4like_addresses(char* orig, char* ip, size_t ip_size, char* ip2, size_t ip2_size) +{ + // ipv4-like notation + int len = strlen(orig); + int count = 0, i = 0, pos = 0; + char *temp; + + for (; i < len; i++) { + if (orig[i] == '.') { + count++; + if (count == 4) { + pos = i; + } else if (count == 16) { + pos = i; + } + } + } + + if (count == 3) { // normal ipv4, copy to ip + if (ip_size > strlen(orig)) { + memcpy(ip, orig, strlen(orig)); + ip[strlen(orig)] = '\0'; + } else { + ip[0] = '\0'; + } + if (ip2) { + ip2[0] = '\0'; + } + } else if (count == 7) { // ipv4 and subnet mask. Need to separate those. + temp = &orig[pos]; + if ((uint8_t)ip_size > temp-orig) { + memcpy(ip, orig, temp-orig); + ip[temp-orig] = '\0'; + } + temp++; // skip the '.' + if (ip2 && (ip2_size > strlen(temp))) { + memcpy(ip2, temp, strlen(temp)); + ip2[strlen(temp)] = '\0'; + } + } else if (count == 15) { // only one ipv6 address in ipv4-like notation + if (ip_size > strlen(orig)) { + memcpy(ip, orig, strlen(orig)); + ip[strlen(orig)] = '\0'; + convert_ipv6(ip); + } else { + ip[0] = '\0'; + } + if (ip2) { + ip2[0] = '\0'; + } + } else if (count == 31){ // ipv6 + ipv6subnet mask in ipv4-like notation separated by dot '.' + temp = &orig[pos]; + if ((uint8_t)ip_size > temp-orig) { + memcpy(ip, orig, temp-orig); + ip[temp-orig] = '\0'; + convert_ipv6(ip); + } + temp++; // skip the '.' + if (ip2 && (ip2_size > strlen(temp))) { + memcpy(ip2, temp, strlen(temp)); + ip2[strlen(temp)] = '\0'; + convert_ipv6(ip2); + } + } +} + +void separate_ip_addresses(char* orig, char* ip, size_t ip_size, char* ip2, size_t ip2_size) +{ + // orig can include ipv4, ipv6, both or two ip4/ipv6 addresses. + // also format depends on possible AT+CGPIAF + if (!orig || !ip) { + if (ip) { + ip[0] = '\0'; + } + if (ip2) { + ip2[0] = '\0'; + } + return; + } + // 1. try to found ':'. If it's found then we know that possible addresses are separated with space + char *temp; + temp = strchr(orig, ':'); + + if (temp != NULL) { + // found ':' + temp = strstr(orig, " "); + // found space as separator and it wasn't in beginning --> contains 2 ip addresses + if (temp && temp != orig) { + if ((uint8_t)ip_size > temp-orig) { + memcpy(ip, orig, temp-orig); + ip[temp-orig] = '\0'; + } else { + ip[0] = '\0'; + } + temp++; // skip the space + if (ip2 && (ip2_size > strlen(temp))) { + memcpy(ip2, temp, strlen(temp)); + ip2[strlen(temp)] = '\0'; + } else { + ip2[0] = '\0'; + } + } else { + // Space was the first char or no space found ---> only one ip, copy to ip + size_t size = strlen(orig); + if (temp) { + size = strlen(temp); + } + + if (ip_size > size) { + memcpy(ip, orig, size); + ip[size] = '\0'; + } else { + ip[0] = '\0'; + } + if (ip2) { + ip2[0] = '\0'; + } + } + } else { + temp = strstr(orig, " "); + // found space as separator and it wasn't in beginning --> contains 2 ip addresses + if (temp && temp != orig) { + separate_ip4like_addresses(temp++, ip2, ip2_size, NULL, 0); + orig[temp-orig-1] = '\0'; + separate_ip4like_addresses(orig, ip, ip_size, NULL, 0); + orig[temp-orig-1] = ' '; // put space back to keep orig as original + } + else { + separate_ip4like_addresses(orig, ip, ip_size, ip2, ip2_size); + } + } +} + +void prefer_ipv6(char* ip, size_t ip_size, char* ip2, size_t ip2_size) +{ + if (!ip || !ip2) { + return; + } + // assume that that ipv6 is already in formatted to use ':' + // 1. try to found ':'. If it's found then we know that this is ipv6 + char *temp; + temp = strchr(ip, ':'); + if (temp) { + // ip has ipv6 address, we can leave + return; + } else { + // ip was not ipv6, check if ip2 is + temp = strchr(ip2, ':'); + if (temp) { + // ipv6 was found in ip2 but not in ip ---> we must swap them. Sadly ip and ip2 might not be pointers + // so we can't just swap them, must use copy. + if (strlen(ip) < ip2_size && strlen(ip2) < ip_size && strlen(ip) < 64) { + char tmp[64]; + strncpy(tmp, ip, strlen(ip)); + tmp[strlen(ip)] = '\0'; + strncpy(ip, ip2, strlen(ip2)); + ip[strlen(ip2)] = '\0'; + strncpy(ip2, tmp, strlen(tmp)); + ip2[strlen(tmp)] = '\0'; + } + } + } +} + +void int_to_hex_str(uint8_t num, char* buf) +{ + char charNum = num; + char_str_to_hex_str(&charNum, 1, buf); +} + +int hex_str_to_int(const char *hex_string, int hex_string_length) +{ + const int base = 16; + int character_as_integer, integer_output = 0; + + for (int i=0;i= '0' && hex_string[i] <= '9') { + character_as_integer = hex_string[i] - '0'; + } else if (hex_string[i] >= 'A' && hex_string[i] <= 'F') { + character_as_integer = hex_string[i] - 'A' + 10; + } else { + character_as_integer = hex_string[i] - 'a' + 10; + } + integer_output *= base; + integer_output += character_as_integer; + } + + return integer_output; +} + +int hex_str_to_char_str(const char* str, uint16_t len, char *buf) +{ + int strcount = 0; + for (int i = 0; i+1 < len; i += 2) { + int upper = hex_str_to_int(str+i, 1); + int lower = hex_str_to_int(str+i+1, 1); + buf[strcount] = ((upper<<4) & 0xF0) | (lower & 0x0F); + strcount++; + } + + return strcount; +} + +void uint_to_binary_str(uint32_t num, char* str, int str_size, int bit_cnt) +{ + if (!str || str_size < bit_cnt) { + return; + } + int tmp, pos = 0; + + for (int i = 31; i >= 0; i--) { + tmp = num >> i; + if (i < bit_cnt) { + if (tmp&1) { + str[pos] = 1 + '0'; + } else { + str[pos] = 0 + '0'; + } + pos++; + } + } +} + +int char_str_to_hex_str(const char* str, uint16_t len, char *buf, bool omit_leading_zero) +{ + if (!str || !buf) { + return 0; + } + + char *ptr = buf; + int i=0; + while (i < len) { + if (omit_leading_zero == true && i == 0 && !(str[i]>>4 & 0x0F)) { + *ptr++ = hex_values[(str[i]) & 0x0F]; + } else { + *ptr++ = hex_values[((str[i])>>4) & 0x0F]; + *ptr++ = hex_values[(str[i]) & 0x0F]; + } + i++; + } + return ptr-buf; +} + +uint16_t get_dynamic_ip_port() +{ + static uint16_t port; + port++; + if (port < 49152) { + port = 49152; + } + return port; +} + +} // namespace mbed_cellular_util diff --git a/features/cellular/framework/common/CellularUtil.h b/features/cellular/framework/common/CellularUtil.h new file mode 100644 index 0000000000..28fa52be3c --- /dev/null +++ b/features/cellular/framework/common/CellularUtil.h @@ -0,0 +1,116 @@ +/* + * Copyright (c) 2017, 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 CELLULAR_UTIL_H_ +#define CELLULAR_UTIL_H_ + +#include +#include + +namespace mbed_cellular_util { + +// some helper macros +#define EMPTY_CHECK(val) (val ## 1) +#define EMPTY(val) (EMPTY_CHECK(val) == 1) +#define _CELLULAR_STRINGIFY(a) #a +#define CELLULAR_STRINGIFY(a) _CELLULAR_STRINGIFY(a) + +static const char hex_values[] = "0123456789ABCDEF"; + +/** Converts the given IP address to proper IPv6 address if needed. + * Conversion is done only if it's NOT IPv4 and separated with colons. + * AT command +CGPADDR can give IP address in format of a1.a2.a3.a4.a5.a6.a7.a8.a9.a10.a11.a12.a13.a14.a15.a16 for IPv6 + * where ax are in decimal format. In this case, function converts decimals to hex with separated with colons. + * + * @param ip IP address that can be IPv4 or IPv6 in different formats from AT command +CGPADDR. Converted result uses same buffer. + */ +void convert_ipv6(char* ip); + +/** Separates IP addresses from the given 'orig' string. 'orig' may contain zero, one or two IP addresses in various formats. + * See AT command +CGPIAF from 3GPP TS 27.007 for details. Does also needed conversions for IPv6 addresses. + * + * @param orig original string that contains zero, one or two IP addressees in various formats + * @param ip preallocated buffer that might contain IP address after return + * @param ip_size size of preallocated buffer IP + * @param ip2 preallocated buffer that might contain IP address after return + * @param ip2_size size of preallocated buffer ip2 + * + */ +void separate_ip_addresses(char* orig, char* ip, size_t ip_size, char* ip2, size_t ip2_size); + +/** Swaps the arrays if param IP does not contain IPv6 address but param ip2 does. + * + * @param ip IP address + * @param ip_size size of buffer ip + * @param ip2 IP address + * @param ip2_size size of buffer ip2 + */ +void prefer_ipv6(char* ip, size_t ip_size, char* ip2, size_t ip2_size); + +/** Converts the given int to two hex characters + * + * @param num number to be converted to hex string + * @param buf preallocated buffer that will contain 2 char length hex value + */ +void int_to_hex_str(uint8_t num, char* buf); + +/** Converts the given buffer 'str' to hex buffer 'buf. First 'len' char's are converted to two hex bytes. + * + * @param str char buffer that is to be converted to hex + * @param len how many chars from str are to be converted + * @param buf destination buffer for hex converted chars. Buffer should be double the size of str to fit hex-encoded string. + * @param omit_leading_zero if true then possible leading zeroes are omitted + */ +int char_str_to_hex_str(const char* str, uint16_t len, char *buf, bool omit_leading_zero = false); + +/** Converts the given hex string to integer + * + * @param hex_string hex string from where chars are converted to int + * @param hex_string_length length of the param hex_string + * @return hex_string converted to int + */ +int hex_str_to_int(const char *hex_string, int hex_string_length); + +/** Converts the given hex string str to char string to buf + * + * @param str hex string that is converted to char string to buf + * @param len length of the param str/how many hex are converted + * @param buf preallocated buffer where result conversion is stored + * @return length of the buf + */ +int hex_str_to_char_str(const char* str, uint16_t len, char *buf); + +/** Converts the given uint to binary string. Fills the given str starting from [0] with the number of bits defined by bit_cnt + * For example uint_to_binary_string(9, str, 10) would fill str "0000001001" + * For example uint_to_binary_string(9, str, 3) would fill str "001" + * + * @param num uint to converts to binary string + * @param str buffer for converted binary string + * @param str_size size of the str buffer + * @param bit_cnt defines how many bits are filled to buffer started from lsb + */ +void uint_to_binary_str(uint32_t num, char* str, int str_size, int bit_cnt); + +/** Get dynamic port for socket + * + * @return next port number above 49152 + */ +uint16_t get_dynamic_ip_port(); + +} // namespace mbed_cellular_util + +#endif diff --git a/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95.cpp b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95.cpp new file mode 100644 index 0000000000..30736b4549 --- /dev/null +++ b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95.cpp @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2017, 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 "QUECTEL_BC95_CellularNetwork.h" +#include "QUECTEL_BC95_CellularPower.h" + +#include "QUECTEL_BC95.h" + +#define CONNECT_DELIM "\r\n" +#define CONNECT_BUFFER_SIZE (1280 + 80 + 80) // AT response + sscanf format +#define CONNECT_TIMEOUT 8000 + +#define MAX_STARTUP_TRIALS 5 +#define MAX_RESET_TRIALS 5 + +using namespace events; +using namespace mbed; + +QUECTEL_BC95::QUECTEL_BC95(EventQueue &queue) : AT_CellularDevice(queue) +{ +} + +QUECTEL_BC95::~QUECTEL_BC95() +{ +} + +CellularNetwork *QUECTEL_BC95::open_network(FileHandle *fh) +{ + if (!_network) { + _network = new QUECTEL_BC95_CellularNetwork(*get_at_handler(fh)); + } + return _network; +} + +CellularPower *QUECTEL_BC95::open_power(FileHandle *fh) +{ + if (!_power) { + _power = new QUECTEL_BC95_CellularPower(*get_at_handler(fh)); + } + return _power; +} diff --git a/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95.h b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95.h new file mode 100644 index 0000000000..9dbce43544 --- /dev/null +++ b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2017, 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 QUECTEL_BC95_H_ +#define QUECTEL_BC95_H_ + +#include "AT_CellularDevice.h" + +namespace mbed { + +class QUECTEL_BC95 : public AT_CellularDevice +{ +public: + + QUECTEL_BC95(events::EventQueue &queue); + virtual ~QUECTEL_BC95(); + +public: // CellularDevice + virtual CellularNetwork *open_network(FileHandle *fh); + virtual CellularPower *open_power(FileHandle *fh); + +public: // NetworkInterface + void handle_urc(FileHandle *fh); +}; +} // namespace mbed +#endif // QUECTEL_BC95_H_ diff --git a/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularNetwork.cpp b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularNetwork.cpp new file mode 100644 index 0000000000..a3c59dc051 --- /dev/null +++ b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularNetwork.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2017, 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 "QUECTEL_BC95_CellularNetwork.h" +#include "QUECTEL_BC95_CellularStack.h" + +using namespace mbed; + +QUECTEL_BC95_CellularNetwork::QUECTEL_BC95_CellularNetwork(ATHandler &atHandler) : AT_CellularNetwork(atHandler) +{ + _op_act = operator_t::RAT_NB1; +} + +QUECTEL_BC95_CellularNetwork::~QUECTEL_BC95_CellularNetwork() +{ +} + +NetworkStack *QUECTEL_BC95_CellularNetwork::get_stack() +{ + if (!_stack) { + _stack = new QUECTEL_BC95_CellularStack(_at, _cid, _ip_stack_type); + } + return _stack; +} + +bool QUECTEL_BC95_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack) +{ + return requested_stack == IPV4_STACK ? true : false; +} + +bool QUECTEL_BC95_CellularNetwork::has_registration(RegistrationType reg_tech) +{ + return (reg_tech == C_EREG); +} + +nsapi_error_t QUECTEL_BC95_CellularNetwork::set_access_technology_impl(operator_t::RadioAccessTechnology opRat) +{ + if (opRat != operator_t::RAT_NB1) { + //TODO: Set as unknown or force to NB1? + _op_act = operator_t::RAT_UNKNOWN; + return NSAPI_ERROR_UNSUPPORTED; + } + + return NSAPI_ERROR_OK; +} diff --git a/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularNetwork.h b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularNetwork.h new file mode 100644 index 0000000000..e9d47823fa --- /dev/null +++ b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularNetwork.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017, 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 QUECTEL_BC95_CELLULAR_NETWORK_H_ +#define QUECTEL_BC95_CELLULAR_NETWORK_H_ + +#include "AT_CellularNetwork.h" + +namespace mbed { + +class QUECTEL_BC95_CellularNetwork : public AT_CellularNetwork +{ +public: + QUECTEL_BC95_CellularNetwork(ATHandler &atHandler); + virtual ~QUECTEL_BC95_CellularNetwork(); + +protected: + virtual NetworkStack *get_stack(); + + virtual nsapi_error_t set_access_technology_impl(operator_t::RadioAccessTechnology opRat); + + virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack); + + virtual bool has_registration(RegistrationType reg_type); +}; +} // namespace mbed +#endif // QUECTEL_BC95_CELLULAR_NETWORK_H_ diff --git a/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularPower.cpp b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularPower.cpp new file mode 100644 index 0000000000..5335361659 --- /dev/null +++ b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularPower.cpp @@ -0,0 +1,51 @@ +/* + * Copyright (c) 2017, 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 "QUECTEL_BC95_CellularPower.h" + +using namespace mbed; + +QUECTEL_BC95_CellularPower::QUECTEL_BC95_CellularPower(ATHandler &atHandler) : AT_CellularPower(atHandler) +{ + +} + +QUECTEL_BC95_CellularPower::~QUECTEL_BC95_CellularPower() +{ + +} + +nsapi_error_t QUECTEL_BC95_CellularPower::set_at_mode() +{ + _at.lock(); + _at.flush(); + _at.cmd_start("AT+CMEE="); // verbose responses + _at.write_int(1); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + return _at.unlock_return_error(); +} + +nsapi_error_t QUECTEL_BC95_CellularPower::reset() +{ + _at.lock(); + _at.cmd_start("AT+NRB"); // reset to full power levels + _at.cmd_stop(); + _at.resp_start("REBOOTING", true); + return _at.unlock_return_error(); +} diff --git a/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularPower.h b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularPower.h new file mode 100644 index 0000000000..c51a12d3d5 --- /dev/null +++ b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularPower.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2017, 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 TELIT_HE910_CELLULAR_POWER_H_ +#define TELIT_HE910_CELLULAR_POWER_H_ + +#include "AT_CellularPower.h" + +namespace mbed { + +class QUECTEL_BC95_CellularPower : public AT_CellularPower +{ +public: + QUECTEL_BC95_CellularPower(ATHandler &atHandler); + virtual ~QUECTEL_BC95_CellularPower(); + +public: //from CellularPower + virtual nsapi_error_t set_at_mode(); + + virtual nsapi_error_t reset(); +}; + +} // namespace mbed + +#endif // TELIT_HE910_CELLULAR_POWER_H_ diff --git a/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularStack.cpp b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularStack.cpp new file mode 100644 index 0000000000..4b77532f34 --- /dev/null +++ b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularStack.cpp @@ -0,0 +1,200 @@ +/* + * Copyright (c) 2017, 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 "QUECTEL_BC95_CellularStack.h" +#include "CellularUtil.h" + +using namespace mbed; +using namespace mbed_cellular_util; + +QUECTEL_BC95_CellularStack::QUECTEL_BC95_CellularStack(ATHandler &atHandler, int cid, nsapi_ip_stack_t stack_type) : AT_CellularStack(atHandler, cid, stack_type) +{ + _at.set_urc_handler("+NSONMI:", mbed::Callback(this, &QUECTEL_BC95_CellularStack::urc_nsonmi)); +} + +QUECTEL_BC95_CellularStack::~QUECTEL_BC95_CellularStack() +{ +} + +nsapi_error_t QUECTEL_BC95_CellularStack::socket_listen(nsapi_socket_t handle, int backlog) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t QUECTEL_BC95_CellularStack::socket_accept(void *server, void **socket, SocketAddress *addr) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +void QUECTEL_BC95_CellularStack::urc_nsonmi() +{ + int sock_id =_at.read_int(); + + for (int i = 0; i < get_max_socket_count(); i++) { + CellularSocket *sock = _socket[i]; + if (sock && sock->id == sock_id) { + if (sock->_cb) { + sock->_cb(sock->_data); + } + break; + } + } +} + +int QUECTEL_BC95_CellularStack::get_max_socket_count() +{ + return BC95_SOCKET_MAX; +} + +int QUECTEL_BC95_CellularStack::get_max_packet_size() +{ + return BC95_MAX_PACKET_SIZE; +} + +bool QUECTEL_BC95_CellularStack::is_protocol_supported(nsapi_protocol_t protocol) +{ + return (protocol == NSAPI_UDP); +} + +nsapi_error_t QUECTEL_BC95_CellularStack::socket_close_impl(int sock_id) +{ + _at.cmd_start("AT+NSOCL="); + _at.write_int(sock_id); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + + return _at.get_last_error(); +} + +nsapi_error_t QUECTEL_BC95_CellularStack::create_socket_impl(CellularSocket *socket) +{ + int sock_id; + bool socketOpenWorking = false; + + if (socket->proto == NSAPI_UDP) { + + _at.cmd_start("AT+NSOCR=DGRAM,17,"); + _at.write_int(socket->localAddress.get_port()); + _at.write_int(1); + _at.cmd_stop(); + _at.resp_start(); + sock_id = _at.read_int(); + _at.resp_stop(); + + socketOpenWorking = (_at.get_last_error() == NSAPI_ERROR_OK); + + if (!socketOpenWorking) { + _at.cmd_start("AT+NSOCL=0"); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + + _at.cmd_start("AT+NSOCR=DGRAM,17,"); + _at.write_int(socket->localAddress.get_port()); + _at.write_int(1); + _at.cmd_stop(); + _at.resp_start(); + sock_id = _at.read_int(); + _at.resp_stop(); + + socketOpenWorking = (_at.get_last_error() == NSAPI_ERROR_OK); + } + } + + if (!socketOpenWorking) { + return NSAPI_ERROR_NO_SOCKET; + } + + // Check for duplicate socket id delivered by modem + for (int i = 0; i < BC95_SOCKET_MAX; i++) { + CellularSocket *sock = _socket[i]; + if (sock && sock->created && sock->id == sock_id) { + return NSAPI_ERROR_NO_SOCKET; + } + } + + socket->id = sock_id; + socket->created = true; + + return NSAPI_ERROR_OK; +} + +nsapi_size_or_error_t QUECTEL_BC95_CellularStack::socket_sendto_impl(CellularSocket *socket, const SocketAddress &address, + const void *data, nsapi_size_t size) +{ + int sent_len = 0; + + char hexstr[BC95_MAX_PACKET_SIZE*2 + 1] = {0}; + char_str_to_hex_str((const char*)data, size, hexstr); + + _at.cmd_start("AT+NSOST="); + _at.write_int(socket->id); + _at.write_string(address.get_ip_address(), false); + _at.write_int(address.get_port()); + _at.write_int(size); + _at.write_string(hexstr, false); + _at.cmd_stop(); + _at.resp_start(); + socket->id = _at.read_int(); + sent_len = _at.read_int(); + _at.resp_stop(); + + if (_at.get_last_error() == NSAPI_ERROR_OK) { + return sent_len; + } + + return _at.get_last_error(); +} + +nsapi_size_or_error_t QUECTEL_BC95_CellularStack::socket_recvfrom_impl(CellularSocket *socket, SocketAddress *address, + void *buffer, nsapi_size_t size) +{ + nsapi_size_or_error_t recv_len=0; + int port; + char ip_address[NSAPI_IP_SIZE]; + char hexstr[BC95_MAX_PACKET_SIZE*2 + 1]; + + _at.cmd_start("AT+NSORF="); + _at.write_int(socket->id); + _at.write_int(size); + _at.cmd_stop(); + _at.resp_start(); + // receiving socket id + _at.skip_param(); + _at.read_string(ip_address, sizeof(ip_address)); + port = _at.read_int(); + recv_len = _at.read_int(); + _at.read_string(hexstr, sizeof(hexstr)); + // remaining length + _at.skip_param(); + + if (!recv_len || (recv_len == -1) || (_at.get_last_error() != NSAPI_ERROR_OK)) { + return NSAPI_ERROR_WOULD_BLOCK; + } + + if (address) { + address->set_ip_address(ip_address); + address->set_port(port); + } + + if (recv_len > 0) { + hex_str_to_char_str((const char*) hexstr, recv_len*2, (char*)buffer); + } + + return recv_len; +} diff --git a/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularStack.h b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularStack.h new file mode 100644 index 0000000000..9c2cf64cff --- /dev/null +++ b/features/cellular/framework/targets/QUECTEL/BC95/QUECTEL_BC95_CellularStack.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2017, 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 QUECTEL_BC95_CELLULARSTACK_H_ +#define QUECTEL_BC95_CELLULARSTACK_H_ + +#include "AT_CellularStack.h" + +#define BC95_SOCKET_MAX 7 +#define BC95_MAX_PACKET_SIZE 512 + +namespace mbed { + +class QUECTEL_BC95_CellularStack : public AT_CellularStack +{ +public: + QUECTEL_BC95_CellularStack(ATHandler &atHandler, int cid, nsapi_ip_stack_t stack_type); + virtual ~QUECTEL_BC95_CellularStack(); + +protected: // NetworkStack + + virtual nsapi_error_t socket_listen(nsapi_socket_t handle, int backlog); + + virtual nsapi_error_t socket_accept(nsapi_socket_t server, + nsapi_socket_t *handle, SocketAddress *address=0); + +protected: // AT_CellularStack + + virtual int get_max_socket_count(); + + virtual int get_max_packet_size(); + + virtual bool is_protocol_supported(nsapi_protocol_t protocol); + + virtual nsapi_error_t socket_close_impl(int sock_id); + + virtual nsapi_error_t create_socket_impl(CellularSocket *socket); + + virtual nsapi_size_or_error_t socket_sendto_impl(CellularSocket *socket, const SocketAddress &address, + const void *data, nsapi_size_t size); + + virtual nsapi_size_or_error_t socket_recvfrom_impl(CellularSocket *socket, SocketAddress *address, + void *buffer, nsapi_size_t size); + +private: + // URC handlers + void urc_nsonmi(); +}; +} // namespace mbed +#endif /* QUECTEL_BC95_CELLULARSTACK_H_ */ diff --git a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96.cpp b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96.cpp new file mode 100644 index 0000000000..5fd746d48e --- /dev/null +++ b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96.cpp @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2017, 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 "QUECTEL/BG96/QUECTEL_BG96.h" +#include "QUECTEL/BG96/QUECTEL_BG96_CellularNetwork.h" +#include "QUECTEL/BG96/QUECTEL_BG96_CellularStack.h" + +using namespace mbed; +using namespace events; + +#define CONNECT_DELIM "\r\n" +#define CONNECT_BUFFER_SIZE (1280 + 80 + 80) // AT response + sscanf format +#define CONNECT_TIMEOUT 8000 + +#define MAX_STARTUP_TRIALS 5 +#define MAX_RESET_TRIALS 5 + +QUECTEL_BG96::QUECTEL_BG96(EventQueue &queue) : AT_CellularDevice(queue) +{ +} + +QUECTEL_BG96::~QUECTEL_BG96() +{ +} + +CellularNetwork *QUECTEL_BG96::open_network(FileHandle *fh) +{ + if (!_network) { + _network = new QUECTEL_BG96_CellularNetwork(*get_at_handler(fh)); + } + return _network; +} diff --git a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96.h b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96.h new file mode 100644 index 0000000000..2fe2ea0b87 --- /dev/null +++ b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017, 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 QUECTEL_BG96_H_ +#define QUECTEL_BG96_H_ + +#include "AT_CellularDevice.h" + +namespace mbed { + +#ifdef TARGET_MCU_K64F +#define CELLULAR_SERIAL_TX PTC17 +#define CELLULAR_SERIAL_RX PTC16 +#else +#define CELLULAR_SERIAL_TX PC_1 +#define CELLULAR_SERIAL_RX PC_0 +#endif + +class QUECTEL_BG96 : public AT_CellularDevice +{ +public: + + QUECTEL_BG96(events::EventQueue &queue); + virtual ~QUECTEL_BG96(); + +public: // CellularDevice + virtual CellularNetwork *open_network(FileHandle *fh); + +public: // NetworkInterface + void handle_urc(FileHandle *fh); +}; +} // namespace mbed +#endif // QUECTEL_BG96_H_ diff --git a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularNetwork.cpp b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularNetwork.cpp new file mode 100644 index 0000000000..eaa1377cb6 --- /dev/null +++ b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularNetwork.cpp @@ -0,0 +1,115 @@ +/* + * Copyright (c) 2017, 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 "QUECTEL/BG96/QUECTEL_BG96_CellularNetwork.h" +#include "QUECTEL/BG96/QUECTEL_BG96_CellularStack.h" + +using namespace mbed; + +QUECTEL_BG96_CellularNetwork::QUECTEL_BG96_CellularNetwork(ATHandler &atHandler) : AT_CellularNetwork(atHandler) +{ +} + +QUECTEL_BG96_CellularNetwork::~QUECTEL_BG96_CellularNetwork() +{ +} + +bool QUECTEL_BG96_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack) +{ + if ((requested_stack == IPV4_STACK) || + (requested_stack == IPV6_STACK) || + (requested_stack == IPV4V6_STACK)) { + return true; + } + + return false; +} + +NetworkStack *QUECTEL_BG96_CellularNetwork::get_stack() +{ + if (!_stack) { + _stack = new QUECTEL_BG96_CellularStack(_at, _cid, _ip_stack_type); + } + return _stack; +} + +nsapi_error_t QUECTEL_BG96_CellularNetwork::set_access_technology_impl(operator_t::RadioAccessTechnology opsAct) +{ + _at.lock(); + + switch (opsAct) { + case operator_t::RAT_CATM1: + _at.cmd_start("AT+QCFG=\"nwscanseq\",020301"); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + _at.cmd_start("AT+QCFG=\"nwscanmode\",3,1"); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + _at.cmd_start("AT+QCFG=\"iotopmode\",0,1"); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + break; + case operator_t::RAT_NB1: + _at.cmd_start("AT+QCFG=\"nwscanseq\",030201"); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + _at.cmd_start("AT+QCFG=\"nwscanmode\",3,1"); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + _at.cmd_start("AT+QCFG=\"iotopmode\",1,1"); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + break; + case operator_t::RAT_GSM: + case operator_t::RAT_GSM_COMPACT: + case operator_t::RAT_UTRAN: + case operator_t::RAT_EGPRS: + _at.cmd_start("AT+QCFG=\"nwscanseq\",010203"); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + _at.cmd_start("AT+QCFG=\"nwscanmode\",1,1"); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + break; + default: + _at.cmd_start("AT+QCFG=\"nwscanseq\",020301"); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + _at.cmd_start("AT+QCFG=\"nwscanmode\",0,1"); //auto mode + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + _at.cmd_start("AT+QCFG=\"iotopmode\",2,1"); //auto mode + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + _at.unlock(); + _op_act = operator_t::RAT_UNKNOWN; + return NSAPI_ERROR_UNSUPPORTED; + } + + return _at.unlock_return_error(); +} diff --git a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularNetwork.h b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularNetwork.h new file mode 100644 index 0000000000..0bfa3dc4e5 --- /dev/null +++ b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularNetwork.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017, 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 QUECTEL_BG96_CELLULAR_NETWORK_H_ +#define QUECTEL_BG96_CELLULAR_NETWORK_H_ + +#include "AT_CellularNetwork.h" + +namespace mbed { + +class QUECTEL_BG96_CellularNetwork : public AT_CellularNetwork +{ +public: + QUECTEL_BG96_CellularNetwork(ATHandler &atHandler); + virtual ~QUECTEL_BG96_CellularNetwork(); + +protected: + virtual NetworkStack *get_stack(); + + virtual nsapi_error_t set_access_technology_impl(operator_t::RadioAccessTechnology opRat); + + virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack); +}; + +} // namespace mbed + +#endif // QUECTEL_BG96_CELLULAR_NETWORK_H_ diff --git a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularStack.cpp b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularStack.cpp new file mode 100644 index 0000000000..3af61cb38a --- /dev/null +++ b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularStack.cpp @@ -0,0 +1,262 @@ +/* + * Copyright (c) 2017, 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 "QUECTEL/BG96/QUECTEL_BG96_CellularStack.h" +#include "CellularLog.h" + +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) +{ + _at.set_urc_handler("+QIURC:", mbed::Callback(this, &QUECTEL_BG96_CellularStack::urc_qiurc)); +} + +QUECTEL_BG96_CellularStack::~QUECTEL_BG96_CellularStack() +{ +} + +nsapi_error_t QUECTEL_BG96_CellularStack::socket_listen(nsapi_socket_t handle, int backlog) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +nsapi_error_t QUECTEL_BG96_CellularStack::socket_accept(void *server, void **socket, SocketAddress *addr) +{ + return NSAPI_ERROR_UNSUPPORTED; +} + +void QUECTEL_BG96_CellularStack::urc_qiurc() +{ + int sock_id=0; + + _at.lock(); + (void) _at.skip_param(); + sock_id = _at.read_int(); + _at.unlock(); + + for (int i = 0; i < get_max_socket_count(); i++) { + CellularSocket *sock = _socket[i]; + if (sock && sock->id == sock_id) { + if (sock->_cb) { + sock->_cb(sock->_data); + } + break; + } + } +} + +int QUECTEL_BG96_CellularStack::get_max_socket_count() +{ + return BG96_SOCKET_MAX; +} + +int QUECTEL_BG96_CellularStack::get_max_packet_size() +{ + return BG96_MAX_PACKET_SIZE; +} + +bool QUECTEL_BG96_CellularStack::is_protocol_supported(nsapi_protocol_t protocol) +{ + return (protocol == NSAPI_UDP); +} + +nsapi_error_t QUECTEL_BG96_CellularStack::socket_close_impl(int sock_id) +{ + _at.cmd_start("AT+QICLOSE="); + _at.write_int(sock_id); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + + return _at.get_last_error(); +} + +void QUECTEL_BG96_CellularStack::handle_open_socket_response(int &modem_connect_id, int &err) +{ + // OK + _at.resp_start(); + _at.resp_stop(); + // QIOPEN -> should be handled as URC? + _at.set_at_timeout(BG96_CREATE_SOCKET_TIMEOUT); + _at.resp_start("+QIOPEN:"); + _at.restore_at_timeout(); + modem_connect_id = _at.read_int(); + err = _at.read_int(); +} +nsapi_error_t QUECTEL_BG96_CellularStack::create_socket_impl(CellularSocket *socket) +{ + int modem_connect_id; + int request_connect_id = socket->id; + int remote_port = 0; + int err = -1; + + if (socket->proto == NSAPI_UDP && !socket->connected) { + _at.cmd_start("AT+QIOPEN="); + _at.write_int(_cid); + _at.write_int(request_connect_id); + _at.write_string("UDP SERVICE"); + _at.write_string("127.0.0.1"); + _at.write_int(remote_port); + _at.write_int(socket->localAddress.get_port()); + _at.write_int(0); + _at.cmd_stop(); + + handle_open_socket_response(modem_connect_id, err); + + if ((_at.get_last_error() == NSAPI_ERROR_OK) && err) { + _at.cmd_start("AT+QICLOSE="); + _at.write_int(modem_connect_id); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + + _at.cmd_start("AT+QIOPEN="); + _at.write_int(_cid); + _at.write_int(request_connect_id); + _at.write_string("UDP SERVICE"); + _at.write_string("127.0.0.1"); + _at.write_int(remote_port); + _at.write_int(socket->localAddress.get_port()); + _at.write_int(0); + _at.cmd_stop(); + + handle_open_socket_response(modem_connect_id, err); + } + } else if (socket->proto == NSAPI_UDP && socket->connected) { + _at.cmd_start("AT+QIOPEN="); + _at.write_int(_cid); + _at.write_int(request_connect_id); + _at.write_string("UDP"); + _at.write_string(socket->remoteAddress.get_ip_address()); + _at.write_int(socket->remoteAddress.get_port()); + _at.cmd_stop(); + + handle_open_socket_response(modem_connect_id, err); + + if ((_at.get_last_error() == NSAPI_ERROR_OK) && err) { + _at.cmd_start("AT+QICLOSE="); + _at.write_int(modem_connect_id); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + + _at.cmd_start("AT+QIOPEN="); + _at.write_int(_cid); + _at.write_int(request_connect_id); + _at.write_string("UDP"); + _at.write_string(socket->remoteAddress.get_ip_address()); + _at.write_int(socket->remoteAddress.get_port()); + _at.cmd_stop(); + + handle_open_socket_response(modem_connect_id, err); + } + } + + // If opened successfully BUT not requested one, close it + if (!err && (modem_connect_id != request_connect_id)) { + _at.cmd_start("AT+QICLOSE="); + _at.write_int(modem_connect_id); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + } + + nsapi_error_t ret_val = _at.get_last_error(); + + socket->created = ((ret_val == NSAPI_ERROR_OK) && (modem_connect_id == request_connect_id)); + + return ret_val; +} + +nsapi_size_or_error_t QUECTEL_BG96_CellularStack::socket_sendto_impl(CellularSocket *socket, const SocketAddress &address, + const void *data, nsapi_size_t size) +{ + int sent_len = 0; + int sent_len_before = 0; + int sent_len_after = 0; + + // Get the sent count before sending + _at.cmd_start("AT+QISEND="); + _at.write_int(socket->id); + _at.write_int(0); + _at.cmd_stop(); + + _at.resp_start("+QISEND:"); + sent_len_before = _at.read_int(); + _at.resp_stop(); + + // Send + _at.cmd_start("AT+QISEND="); + _at.write_int(socket->id); + _at.write_int(size); + _at.write_string(address.get_ip_address()); + _at.write_int(address.get_port()); + _at.cmd_stop(); + + _at.resp_start(">"); + _at.write_bytes((uint8_t*)data, size); + _at.resp_start(); + _at.set_stop_tag("\r\n"); + _at.resp_stop(); + + // Get the sent count after sending + _at.cmd_start("AT+QISEND="); + _at.write_int(socket->id); + _at.write_int(0); + _at.cmd_stop(); + + _at.resp_start("+QISEND:"); + sent_len_after = _at.read_int(); + _at.resp_stop(); + + if (_at.get_last_error() == NSAPI_ERROR_OK) { + sent_len = sent_len_after - sent_len_before; + return sent_len; + } + + return _at.get_last_error(); +} + +nsapi_size_or_error_t QUECTEL_BG96_CellularStack::socket_recvfrom_impl(CellularSocket *socket, SocketAddress *address, + void *buffer, nsapi_size_t size) +{ + nsapi_size_or_error_t recv_len=0; + int port; + char ip_address[NSAPI_IP_SIZE + 1]; + + _at.cmd_start("AT+QIRD="); + _at.write_int(socket->id); + _at.cmd_stop(); + + _at.resp_start("+QIRD:"); + recv_len = _at.read_int(); + _at.read_string(ip_address, sizeof(ip_address)); + port = _at.read_int(); + _at.read_bytes((uint8_t*)buffer, recv_len); + _at.resp_stop(); + + if (!recv_len || (_at.get_last_error() != NSAPI_ERROR_OK)) { + return NSAPI_ERROR_WOULD_BLOCK; + } + + if (address) { + address->set_ip_address(ip_address); + address->set_port(port); + } + + return recv_len; +} diff --git a/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularStack.h b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularStack.h new file mode 100644 index 0000000000..af243ccfab --- /dev/null +++ b/features/cellular/framework/targets/QUECTEL/BG96/QUECTEL_BG96_CellularStack.h @@ -0,0 +1,67 @@ +/* + * Copyright (c) 2017, 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 QUECTEL_BG96_CELLULARSTACK_H_ +#define QUECTEL_BG96_CELLULARSTACK_H_ + +#include "AT_CellularStack.h" + +namespace mbed { + +#define BG96_SOCKET_MAX 12 +#define BG96_MAX_PACKET_SIZE 1460 +#define BG96_CREATE_SOCKET_TIMEOUT 150000 //150 seconds + +class QUECTEL_BG96_CellularStack : public AT_CellularStack +{ +public: + QUECTEL_BG96_CellularStack(ATHandler &atHandler, int cid, nsapi_ip_stack_t stack_type); + virtual ~QUECTEL_BG96_CellularStack(); + +protected: // NetworkStack + + virtual nsapi_error_t socket_listen(nsapi_socket_t handle, int backlog); + + virtual nsapi_error_t socket_accept(nsapi_socket_t server, + nsapi_socket_t *handle, SocketAddress *address=0); + +protected: // AT_CellularStack + + virtual int get_max_socket_count(); + + virtual int get_max_packet_size(); + + virtual bool is_protocol_supported(nsapi_protocol_t protocol); + + virtual nsapi_error_t socket_close_impl(int sock_id); + + virtual nsapi_error_t create_socket_impl(CellularSocket *socket); + + virtual nsapi_size_or_error_t socket_sendto_impl(CellularSocket *socket, const SocketAddress &address, + const void *data, nsapi_size_t size); + + virtual nsapi_size_or_error_t socket_recvfrom_impl(CellularSocket *socket, SocketAddress *address, + void *buffer, nsapi_size_t size); + +private: + // URC handlers + void urc_qiurc(); + + void handle_open_socket_response(int &modem_connect_id, int &err); +}; +} // namespace mbed +#endif /* QUECTEL_BG96_CELLULARSTACK_H_ */ diff --git a/features/cellular/framework/targets/TELIT/HE910/TELIT_HE910.cpp b/features/cellular/framework/targets/TELIT/HE910/TELIT_HE910.cpp new file mode 100644 index 0000000000..89f4f985ef --- /dev/null +++ b/features/cellular/framework/targets/TELIT/HE910/TELIT_HE910.cpp @@ -0,0 +1,60 @@ +/* + * Copyright (c) 2017, 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 "TELIT_HE910.h" +#include "TELIT_HE910_CellularPower.h" +#include "TELIT_HE910_CellularNetwork.h" + +using namespace mbed; +using namespace events; + +TELIT_HE910::TELIT_HE910(EventQueue &queue) : AT_CellularDevice(queue) +{ + +} + +TELIT_HE910::~TELIT_HE910() +{ +} + +CellularPower *TELIT_HE910::open_power(FileHandle *fh) +{ + if (!_power) { + ATHandler *atHandler = get_at_handler(fh); + if (atHandler) { + _power = new TELIT_HE910_CellularPower(*atHandler); + if (!_power) { + release_at_handler(atHandler); + } + } + } + return _power; +} + +CellularNetwork *TELIT_HE910::open_network(FileHandle *fh) +{ + if (!_network) { + ATHandler *atHandler = get_at_handler(fh); + if (atHandler) { + _network = new TELIT_HE910_CellularNetwork(*atHandler); + if (!_network) { + release_at_handler(atHandler); + } + } + } + return _network; +} diff --git a/features/cellular/framework/targets/TELIT/HE910/TELIT_HE910.h b/features/cellular/framework/targets/TELIT/HE910/TELIT_HE910.h new file mode 100644 index 0000000000..2d66a21b1c --- /dev/null +++ b/features/cellular/framework/targets/TELIT/HE910/TELIT_HE910.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2017, 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 CELLULAR_TARGETS_TELIT_HE910_TELIT_HE910_H_ +#define CELLULAR_TARGETS_TELIT_HE910_TELIT_HE910_H_ + +#include "AT_CellularDevice.h" + +namespace mbed { + +class TELIT_HE910 : public AT_CellularDevice +{ + +public: + TELIT_HE910(events::EventQueue &queue); + virtual ~TELIT_HE910(); + +public: // from CellularDevice + virtual CellularPower *open_power(FileHandle *fh); + virtual CellularNetwork *open_network(FileHandle *fh); +}; +} // namespace mbed +#endif /* CELLULAR_TARGETS_TELIT_HE910_TELIT_HE910_H_ */ diff --git a/features/cellular/framework/targets/TELIT/HE910/TELIT_HE910_CellularNetwork.cpp b/features/cellular/framework/targets/TELIT/HE910/TELIT_HE910_CellularNetwork.cpp new file mode 100644 index 0000000000..cfb5f88190 --- /dev/null +++ b/features/cellular/framework/targets/TELIT/HE910/TELIT_HE910_CellularNetwork.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2017, 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 "TELIT_HE910_CellularNetwork.h" + +using namespace mbed; + +TELIT_HE910_CellularNetwork::TELIT_HE910_CellularNetwork(ATHandler &atHandler) : AT_CellularNetwork(atHandler) +{ +} + +TELIT_HE910_CellularNetwork::~TELIT_HE910_CellularNetwork() +{ +} + +bool TELIT_HE910_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack) +{ + return requested_stack == IPV4_STACK ? true : false; +} + +bool TELIT_HE910_CellularNetwork::has_registration(RegistrationType reg_type) +{ + return (reg_type == C_REG || reg_type == C_GREG); +} + +nsapi_error_t TELIT_HE910_CellularNetwork::set_access_technology_impl(operator_t::RadioAccessTechnology opRat) +{ + _op_act = operator_t::RAT_UNKNOWN; + return NSAPI_ERROR_UNSUPPORTED; +} diff --git a/features/cellular/framework/targets/TELIT/HE910/TELIT_HE910_CellularNetwork.h b/features/cellular/framework/targets/TELIT/HE910/TELIT_HE910_CellularNetwork.h new file mode 100644 index 0000000000..35d73fd87c --- /dev/null +++ b/features/cellular/framework/targets/TELIT/HE910/TELIT_HE910_CellularNetwork.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017, 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 TELIT_HE910_CELLULAR_NETWORK_H_ +#define TELIT_HE910_CELLULAR_NETWORK_H_ + +#include "AT_CellularNetwork.h" + +namespace mbed { + +class TELIT_HE910_CellularNetwork : public AT_CellularNetwork +{ +public: + TELIT_HE910_CellularNetwork(ATHandler &atHandler); + virtual ~TELIT_HE910_CellularNetwork(); + +protected: + + virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack); + + virtual bool has_registration(RegistrationType rat); + + virtual nsapi_error_t set_access_technology_impl(operator_t::RadioAccessTechnology opRat); +}; + +} // namespace mbed + +#endif // TELIT_HE910_CELLULAR_NETWORK_H_ diff --git a/features/cellular/framework/targets/TELIT/HE910/TELIT_HE910_CellularPower.cpp b/features/cellular/framework/targets/TELIT/HE910/TELIT_HE910_CellularPower.cpp new file mode 100644 index 0000000000..63a2b42027 --- /dev/null +++ b/features/cellular/framework/targets/TELIT/HE910/TELIT_HE910_CellularPower.cpp @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2017, 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 "TELIT_HE910_CellularPower.h" +// for modem powering up&down +#include "onboard_modem_api.h" + +using namespace mbed; + +TELIT_HE910_CellularPower::TELIT_HE910_CellularPower(ATHandler &atHandler) : AT_CellularPower(atHandler) +{ + +} + +TELIT_HE910_CellularPower::~TELIT_HE910_CellularPower() +{ + +} + +nsapi_error_t TELIT_HE910_CellularPower::on() +{ +#if MODEM_ON_BOARD + ::onboard_modem_init(); + ::onboard_modem_power_up(); +#endif + return NSAPI_ERROR_OK; +} + +nsapi_error_t TELIT_HE910_CellularPower::off() +{ +#if MODEM_ON_BOARD + ::onboard_modem_power_down(); +#endif + return NSAPI_ERROR_OK; +} + +/** + * Set AT command mode. + * @remark must be called after power on to prepare correct AT mode + * @return blocking until success or failure + */ +nsapi_error_t TELIT_HE910_CellularPower::set_at_mode() +{ + nsapi_error_t err = AT_CellularPower::set_at_mode(); + if (err != NSAPI_ERROR_OK) { + return err; + } + _at.lock(); + _at.cmd_start("AT&K0;&C1;&D0"); + _at.cmd_stop(); + _at.resp_start(); + _at.resp_stop(); + + return _at.unlock_return_error(); +} diff --git a/features/cellular/framework/targets/TELIT/HE910/TELIT_HE910_CellularPower.h b/features/cellular/framework/targets/TELIT/HE910/TELIT_HE910_CellularPower.h new file mode 100644 index 0000000000..885746a1e1 --- /dev/null +++ b/features/cellular/framework/targets/TELIT/HE910/TELIT_HE910_CellularPower.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2017, 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 TELIT_HE910_CELLULAR_POWER_H_ +#define TELIT_HE910_CELLULAR_POWER_H_ + +#include "AT_CellularPower.h" + +namespace mbed { + +class TELIT_HE910_CellularPower : public AT_CellularPower +{ +public: + TELIT_HE910_CellularPower(ATHandler &atHandler); + virtual ~TELIT_HE910_CellularPower(); + +public: //from CellularPower + + virtual nsapi_error_t on(); + + virtual nsapi_error_t off(); + + virtual nsapi_error_t set_at_mode(); +}; + +} // namespace mbed + +#endif // TELIT_HE910_CELLULAR_POWER_H_ diff --git a/features/cellular/framework/targets/UBLOX/LISA_U/UBLOX_LISA_U.cpp b/features/cellular/framework/targets/UBLOX/LISA_U/UBLOX_LISA_U.cpp new file mode 100644 index 0000000000..50310ca9d1 --- /dev/null +++ b/features/cellular/framework/targets/UBLOX/LISA_U/UBLOX_LISA_U.cpp @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2017, 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_LISA_U.h" +#include "UBLOX_LISA_U_CellularNetwork.h" +#include "UBLOX_LISA_U_CellularPower.h" + +using namespace mbed; +using namespace events; + +UBLOX_LISA_U::UBLOX_LISA_U(EventQueue &queue) : AT_CellularDevice(queue) +{ +} + +UBLOX_LISA_U::~UBLOX_LISA_U() +{ +} + +CellularNetwork *UBLOX_LISA_U::open_network(FileHandle *fh) +{ + if (!_network) { + _network = new UBLOX_LISA_U_CellularNetwork(*get_at_handler(fh)); + } + return _network; +} + +CellularPower *UBLOX_LISA_U::open_power(FileHandle *fh) +{ + if (!_power) { + _power = new UBLOX_LISA_U_CellularPower(*get_at_handler(fh)); + } + return _power; +} diff --git a/features/cellular/framework/targets/UBLOX/LISA_U/UBLOX_LISA_U.h b/features/cellular/framework/targets/UBLOX/LISA_U/UBLOX_LISA_U.h new file mode 100644 index 0000000000..eedd88d831 --- /dev/null +++ b/features/cellular/framework/targets/UBLOX/LISA_U/UBLOX_LISA_U.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2017, 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_LISA_U_H_ +#define UBLOX_LISA_U_H_ + +#include "AT_CellularDevice.h" + +namespace mbed { + +class UBLOX_LISA_U : public AT_CellularDevice +{ + +public: + UBLOX_LISA_U(events::EventQueue &queue); + virtual ~UBLOX_LISA_U(); + +public: // CellularDevice + virtual CellularNetwork *open_network(FileHandle *fh); + virtual CellularPower *open_power(FileHandle *fh); +}; + +} // namespace mbed + +#endif // UBLOX_LISA_U_H_ diff --git a/features/cellular/framework/targets/UBLOX/LISA_U/UBLOX_LISA_U_CellularNetwork.cpp b/features/cellular/framework/targets/UBLOX/LISA_U/UBLOX_LISA_U_CellularNetwork.cpp new file mode 100644 index 0000000000..b48910cee2 --- /dev/null +++ b/features/cellular/framework/targets/UBLOX/LISA_U/UBLOX_LISA_U_CellularNetwork.cpp @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2017, 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_LISA_U_CellularNetwork.h" + +using namespace mbed; + +UBLOX_LISA_U_CellularNetwork::UBLOX_LISA_U_CellularNetwork(ATHandler &atHandler) : AT_CellularNetwork(atHandler) +{ +} + +UBLOX_LISA_U_CellularNetwork::~UBLOX_LISA_U_CellularNetwork() +{ +} + +bool UBLOX_LISA_U_CellularNetwork::get_modem_stack_type(nsapi_ip_stack_t requested_stack) +{ + return requested_stack == IPV4_STACK ? true : false; +} + +bool UBLOX_LISA_U_CellularNetwork::has_registration(RegistrationType reg_type) +{ + return (reg_type == C_REG || reg_type == C_GREG); +} + +nsapi_error_t UBLOX_LISA_U_CellularNetwork::set_access_technology_impl(operator_t::RadioAccessTechnology opRat) +{ + _op_act = operator_t::RAT_UNKNOWN; + return NSAPI_ERROR_UNSUPPORTED; +} diff --git a/features/cellular/framework/targets/UBLOX/LISA_U/UBLOX_LISA_U_CellularNetwork.h b/features/cellular/framework/targets/UBLOX/LISA_U/UBLOX_LISA_U_CellularNetwork.h new file mode 100644 index 0000000000..d7dfa1bf91 --- /dev/null +++ b/features/cellular/framework/targets/UBLOX/LISA_U/UBLOX_LISA_U_CellularNetwork.h @@ -0,0 +1,41 @@ +/* + * Copyright (c) 2017, 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_LISA_U_CELLULAR_NETWORK_H_ +#define UBLOX_LISA_U_CELLULAR_NETWORK_H_ + +#include "AT_CellularNetwork.h" + +namespace mbed { + +class UBLOX_LISA_U_CellularNetwork : public AT_CellularNetwork +{ +public: + UBLOX_LISA_U_CellularNetwork(ATHandler &atHandler); + virtual ~UBLOX_LISA_U_CellularNetwork(); + +protected: + virtual bool get_modem_stack_type(nsapi_ip_stack_t requested_stack); + + virtual bool has_registration(RegistrationType rat); + + virtual nsapi_error_t set_access_technology_impl(operator_t::RadioAccessTechnology opRat); +}; + +} // namespace mbed + +#endif // UBLOX_LISA_U_CELLULAR_NETWORK_H_ diff --git a/features/cellular/framework/targets/UBLOX/LISA_U/UBLOX_LISA_U_CellularPower.cpp b/features/cellular/framework/targets/UBLOX/LISA_U/UBLOX_LISA_U_CellularPower.cpp new file mode 100644 index 0000000000..984c7f1209 --- /dev/null +++ b/features/cellular/framework/targets/UBLOX/LISA_U/UBLOX_LISA_U_CellularPower.cpp @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2017, 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_LISA_U_CellularPower.h" + +#include "onboard_modem_api.h" + +using namespace mbed; + +UBLOX_LISA_U_CellularPower::UBLOX_LISA_U_CellularPower(ATHandler &atHandler) : AT_CellularPower(atHandler) +{ + +} + +UBLOX_LISA_U_CellularPower::~UBLOX_LISA_U_CellularPower() +{ + +} + +nsapi_error_t UBLOX_LISA_U_CellularPower::on() +{ +#if MODEM_ON_BOARD + ::onboard_modem_init(); + ::onboard_modem_power_up(); +#endif + return NSAPI_ERROR_OK; +} + +nsapi_error_t UBLOX_LISA_U_CellularPower::off() +{ +#if MODEM_ON_BOARD + ::onboard_modem_power_down(); +#endif + return NSAPI_ERROR_OK; +} diff --git a/features/cellular/framework/targets/UBLOX/LISA_U/UBLOX_LISA_U_CellularPower.h b/features/cellular/framework/targets/UBLOX/LISA_U/UBLOX_LISA_U_CellularPower.h new file mode 100644 index 0000000000..ea56bc0153 --- /dev/null +++ b/features/cellular/framework/targets/UBLOX/LISA_U/UBLOX_LISA_U_CellularPower.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2017, 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_LISA_U_CELLULARPOWER_H_ +#define UBLOX_LISA_U_CELLULARPOWER_H_ + +#include "AT_CellularPower.h" + +namespace mbed { + +class UBLOX_LISA_U_CellularPower : public AT_CellularPower +{ +public: + UBLOX_LISA_U_CellularPower(ATHandler &atHandler); + virtual ~UBLOX_LISA_U_CellularPower(); + +public: //from CellularPower + + virtual nsapi_error_t on(); + + virtual nsapi_error_t off(); +}; + +} // namespace mbed + +#endif // UBLOX_LISA_U_CELLULARPOWER_H_ diff --git a/features/cellular/junit_xsl.xslt b/features/cellular/junit_xsl.xslt new file mode 100644 index 0000000000..7376b27f26 --- /dev/null +++ b/features/cellular/junit_xsl.xslt @@ -0,0 +1,101 @@ + + + + + + + + + +

+ Unittest report +

+ +

+ + Total tests run + , failures: + + + + + +

+
+ + +

+ +

+ + + + + + + + + + + +
Tests runTests failedOther errors
+
+ + + + + + + + +
Tests namePASS/FAILFailing caseReason
+
+ + + + + + + + + + + PASS + + + + + + + FAIL + + + + + + + + + + + + + + + + FAIL + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/features/cellular/mbed_lib.json b/features/cellular/mbed_lib.json new file mode 100644 index 0000000000..169fe39d25 --- /dev/null +++ b/features/cellular/mbed_lib.json @@ -0,0 +1,13 @@ +{ + "name": "cellular", + "config": { + "use-apn-lookup": { + "help": "Use APN database lookup", + "value": true + }, + "random_max_start_delay": { + "help": "Maximum random delay value used in start-up sequence in milliseconds", + "value": 0 + } + } +} diff --git a/features/cellular/xsl_script.sh b/features/cellular/xsl_script.sh new file mode 100755 index 0000000000..d5320b42b8 --- /dev/null +++ b/features/cellular/xsl_script.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +# Copyright (c) 2015 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. + +echo +echo "Creating report" +echo + +echo ' + +' >> lcov/index.xml + +for f in lcov/results/*.xml +do +name=${f##*/} +echo ''>> lcov/index.xml +done + +echo '' >> lcov/index.xml + +echo +echo "Report created to lcov/index.xml (outputs html)" +echo \ No newline at end of file diff --git a/features/netsocket/cellular/generic_modem_driver/OnboardCellularInterface.cpp b/features/netsocket/cellular/generic_modem_driver/OnboardCellularInterface.cpp index 6c823a383b..fbd111eff7 100644 --- a/features/netsocket/cellular/generic_modem_driver/OnboardCellularInterface.cpp +++ b/features/netsocket/cellular/generic_modem_driver/OnboardCellularInterface.cpp @@ -12,8 +12,11 @@ * See the License for the specific language governing permissions and * limitations under the License. */ + #include "OnboardCellularInterface.h" +#ifndef CELLULAR_DEVICE + #if MODEM_ON_BOARD && MODEM_ON_BOARD_UART && NSAPI_PPP_AVAILABLE #include "onboard_modem_api.h" @@ -52,3 +55,5 @@ void OnboardCellularInterface::modem_power_down() ::onboard_modem_power_down(); } #endif + +#endif // CELLULAR_DEVICE diff --git a/features/netsocket/cellular/generic_modem_driver/OnboardCellularInterface.h b/features/netsocket/cellular/generic_modem_driver/OnboardCellularInterface.h index 1adc085e74..379ece87ec 100644 --- a/features/netsocket/cellular/generic_modem_driver/OnboardCellularInterface.h +++ b/features/netsocket/cellular/generic_modem_driver/OnboardCellularInterface.h @@ -16,7 +16,10 @@ #ifndef ONBOARD_CELLULAR_INTERFACE_ #define ONBOARD_CELLULAR_INTERFACE_ -#if MODEM_ON_BOARD && MODEM_ON_BOARD_UART && NSAPI_PPP_AVAILABLE +#include "EasyCellularConnection.h" +#ifdef CELLULAR_DEVICE +typedef mbed::EasyCellularConnection OnboardCellularInterface; +#elif MODEM_ON_BOARD && MODEM_ON_BOARD_UART && NSAPI_PPP_AVAILABLE #include "UARTCellularInterface.h" @@ -40,16 +43,16 @@ public: protected: /** Sets the modem up for powering on * - * modem_init() is equivalent to plugging in the device, e.g., attaching power and serial port. - * Uses onboard_modem_api.h where the implementation of onboard_modem_api is provided by the target. + * modem_init() is equivalent to plugging in the device, for example, attaching power and serial port. + * Uses onboard_modem_api.h where the target provides the implementation of onboard_modem_api. */ virtual void modem_init(); /** Sets the modem in unplugged state * - * modem_deinit() will be equivalent to pulling the plug off of the device, i.e., detaching power + * modem_deinit() will be equivalent to pulling the plug off of the device, in other words, detaching power * and serial port. This puts the modem in lowest power state. - * Uses onboard_modem_api.h where the implementation of onboard_modem_api is provided by the target. + * Uses onboard_modem_api.h where the target provides the implementation of onboard_modem_api. */ virtual void modem_deinit(); @@ -57,14 +60,14 @@ protected: * * modem_power_up() is equivalent to pressing the soft power button. * The driver may repeat this if the modem is not responsive to AT commands. - * Uses onboard_modem_api.h where the implementation of onboard_modem_api is provided by the target. + * Uses onboard_modem_api.h where the target provides the implementation of onboard_modem_api. */ virtual void modem_power_up(); /** Powers down the modem * * modem_power_down() is equivalent to turning off the modem by button press. - * Uses onboard_modem_api.h where the implementation of onboard_modem_api is provided by the target. + * Uses onboard_modem_api.h where the target provides the implementation of onboard_modem_api. */ virtual void modem_power_down(); };