diff --git a/connectivity/cellular/include/cellular/framework/API/ATHandler.h b/connectivity/cellular/include/cellular/framework/API/ATHandler.h
index 02499118ccc..6f8228def30 100644
--- a/connectivity/cellular/include/cellular/framework/API/ATHandler.h
+++ b/connectivity/cellular/include/cellular/framework/API/ATHandler.h
@@ -363,6 +363,12 @@ class ATHandler {
*/
void write_hex_string(const char *str, size_t size, bool quote_string = true);
+ /** Get the error detected during read_int()
+ *
+ * @return the latest negative integer error got from read_int().
+ */
+ int32_t get_last_read_error() const;
+
/** Reads as string and converts result to integer. Supports only non-negative integers.
*
* @return the non-negative integer or -1 in case of error.
@@ -599,6 +605,7 @@ class ATHandler {
nsapi_error_t _last_err;
int _last_3gpp_error;
device_err_t _last_at_err;
+ int32_t _last_read_error{};
uint16_t _oob_string_max_length;
char *_output_delimiter;
diff --git a/connectivity/cellular/include/cellular/framework/API/CellularContext.h b/connectivity/cellular/include/cellular/framework/API/CellularContext.h
index e9c22f95119..ffc597b0b57 100644
--- a/connectivity/cellular/include/cellular/framework/API/CellularContext.h
+++ b/connectivity/cellular/include/cellular/framework/API/CellularContext.h
@@ -41,6 +41,12 @@ namespace mbed {
* @{
*/
+/// Radio Access Technology type
+enum RadioAccessTechnologyType {
+ CATM1, ///< LTE CAT-M or LTE-M
+ CATNB ///< NB-IoT (Narrowband IoT)
+};
+
/// CellularContext is CellularInterface/NetworkInterface with extensions for cellular connectivity
class CellularContext : public CellularInterface {
@@ -158,6 +164,7 @@ class CellularContext : public CellularInterface {
virtual nsapi_error_t connect(const char *sim_pin, const char *apn = 0, const char *uname = 0,
const char *pwd = 0) = 0;
virtual void set_credentials(const char *apn, const char *uname = 0, const char *pwd = 0) = 0;
+ virtual void set_access_technology(RadioAccessTechnologyType rat = CATM1) = 0;
virtual bool is_connected() = 0;
/** Same as NetworkInterface::get_default_instance()
diff --git a/connectivity/cellular/include/cellular/framework/API/CellularDevice.h b/connectivity/cellular/include/cellular/framework/API/CellularDevice.h
index 7d0adbf1cc2..d1c9dbe4d51 100644
--- a/connectivity/cellular/include/cellular/framework/API/CellularDevice.h
+++ b/connectivity/cellular/include/cellular/framework/API/CellularDevice.h
@@ -424,6 +424,14 @@ class CellularDevice {
*/
void set_retry_timeout_array(const uint16_t timeout[], int array_len);
+ /**
+ * @brief Enable serial multiplexing according to 3GPP TS 27.010, if implemented
+ * on this modem.
+ *
+ * @return Error code or success
+ */
+ virtual nsapi_error_t enable_cmux() { return NSAPI_ERROR_UNSUPPORTED;};
+
protected: //Common functions
friend class AT_CellularNetwork;
friend class AT_CellularContext;
@@ -453,6 +461,8 @@ class CellularDevice {
CellularStateMachine *_state_machine;
Callback _status_cb;
+ bool _cmux_enabled = false;
+
private: //Member variables
CellularNetwork *_nw;
char _sim_pin[MAX_PIN_SIZE + 1];
diff --git a/connectivity/cellular/include/cellular/framework/AT/AT_CellularContext.h b/connectivity/cellular/include/cellular/framework/AT/AT_CellularContext.h
index d30709954b7..2db191c4dad 100644
--- a/connectivity/cellular/include/cellular/framework/AT/AT_CellularContext.h
+++ b/connectivity/cellular/include/cellular/framework/AT/AT_CellularContext.h
@@ -22,6 +22,7 @@
#include "rtos/Semaphore.h"
#include "AT_CellularDevice.h"
+#include
const int MAX_APN_LENGTH = 63 + 1;
@@ -54,6 +55,7 @@ class AT_CellularContext : public CellularContext {
virtual nsapi_error_t connect(const char *sim_pin, const char *apn = 0, const char *uname = 0,
const char *pwd = 0);
virtual void set_credentials(const char *apn, const char *uname = 0, const char *pwd = 0);
+ virtual void set_access_technology(RadioAccessTechnologyType rat = CATM1);
// from CellularContext
virtual nsapi_error_t get_pdpcontext_params(pdpContextList_t ¶ms_list);
@@ -115,6 +117,13 @@ class AT_CellularContext : public CellularContext {
*/
virtual const char *get_nonip_context_type_str();
+ /**
+ * @brief Set the cellular technology and band based on the \c _rat and \c _band class variables.
+ *
+ * Modems which support this functionality should override this in their CellularContext implementations.
+ */
+ virtual void enable_access_technology() {}
+
private:
#if NSAPI_PPP_AVAILABLE
nsapi_error_t open_data_channel();
@@ -130,6 +139,8 @@ class AT_CellularContext : public CellularContext {
nsapi_error_t check_operation(nsapi_error_t err, ContextOperation op);
void ciot_opt_cb(mbed::CellularNetwork::CIoT_Supported_Opt ciot_opt);
virtual void do_connect_with_retry();
+
+protected:
void set_cid(int cid);
private:
@@ -146,6 +157,7 @@ class AT_CellularContext : public CellularContext {
bool _cp_req;
bool _is_connected;
ATHandler &_at;
+ std::optional _rat;
};
/**
diff --git a/connectivity/cellular/include/cellular/framework/AT/AT_CellularDevice.h b/connectivity/cellular/include/cellular/framework/AT/AT_CellularDevice.h
index 5fc37e791dd..95a0447a02f 100755
--- a/connectivity/cellular/include/cellular/framework/AT/AT_CellularDevice.h
+++ b/connectivity/cellular/include/cellular/framework/AT/AT_CellularDevice.h
@@ -130,6 +130,8 @@ class AT_CellularDevice : public CellularDevice {
virtual nsapi_error_t set_baud_rate(int baud_rate);
+ nsapi_error_t enable_cmux() override;
+
#if MBED_CONF_CELLULAR_USE_SMS
virtual CellularSMS *open_sms();
diff --git a/connectivity/cellular/source/framework/AT/AT_CellularContext.cpp b/connectivity/cellular/source/framework/AT/AT_CellularContext.cpp
index f2b1d632b95..27601a3472c 100644
--- a/connectivity/cellular/source/framework/AT/AT_CellularContext.cpp
+++ b/connectivity/cellular/source/framework/AT/AT_CellularContext.cpp
@@ -109,6 +109,19 @@ nsapi_error_t AT_CellularContext::connect()
}
call_network_cb(NSAPI_STATUS_CONNECTING);
+ set_device_ready();
+
+ _at.lock();
+ bool valid_context = get_context();
+ _at.unlock();
+ if(!valid_context) {
+ set_new_context(_cid);
+ }
+
+ do_user_authentication();
+
+ enable_access_technology();
+
nsapi_error_t err = _device->attach_to_network();
_cb_data.error = check_operation(err, OP_CONNECT);
_retry_count = 0;
@@ -278,6 +291,11 @@ void AT_CellularContext::set_credentials(const char *apn, const char *uname, con
_pwd = pwd;
}
+void AT_CellularContext::set_access_technology(RadioAccessTechnologyType rat)
+{
+ _rat = rat;
+}
+
// PDP Context handling
void AT_CellularContext::delete_current_context()
{
diff --git a/connectivity/cellular/source/framework/AT/AT_CellularDevice.cpp b/connectivity/cellular/source/framework/AT/AT_CellularDevice.cpp
index 7a2d79f07a4..b751d0e2cbc 100644
--- a/connectivity/cellular/source/framework/AT/AT_CellularDevice.cpp
+++ b/connectivity/cellular/source/framework/AT/AT_CellularDevice.cpp
@@ -414,7 +414,8 @@ nsapi_error_t AT_CellularDevice::init()
_at.flush();
_at.at_cmd_discard("E0", "");
if (_at.get_last_error() == NSAPI_ERROR_OK) {
- _at.at_cmd_discard("+CMEE", "=1");
+ // Enable verbose error messages
+ _at.at_cmd_discard("+CMEE", "=2");
_at.at_cmd_discard("+CFUN", "=1");
if (_at.get_last_error() == NSAPI_ERROR_OK) {
break;
@@ -623,6 +624,29 @@ nsapi_error_t AT_CellularDevice::set_baud_rate(int baud_rate)
return error;
}
+nsapi_error_t AT_CellularDevice::enable_cmux()
+{
+ setup_at_handler();
+
+ _at.lock();
+ for (int retry = 1; retry <= 3; retry++) {
+ _at.clear_error();
+ _at.flush();
+ _at.at_cmd_discard("E0", "");
+ if (_at.get_last_error() == NSAPI_ERROR_OK) {
+ _at.at_cmd_discard("+CMUX", "=0");
+ if (_at.get_last_error() == NSAPI_ERROR_OK) {
+ _cmux_enabled = true;
+ break;
+ }
+ }
+ tr_debug("Wait 100ms to init modem");
+ rtos::ThisThread::sleep_for(100ms); // let modem have time to get ready
+ }
+
+ return _at.unlock_return_error();
+}
+
nsapi_error_t AT_CellularDevice::set_baud_rate_impl(int baud_rate)
{
return _at.at_cmd_discard("+IPR", "=", "%d", baud_rate);
diff --git a/connectivity/cellular/source/framework/AT/AT_CellularNetwork.cpp b/connectivity/cellular/source/framework/AT/AT_CellularNetwork.cpp
index 0afbf88e4a1..d780e459e28 100644
--- a/connectivity/cellular/source/framework/AT/AT_CellularNetwork.cpp
+++ b/connectivity/cellular/source/framework/AT/AT_CellularNetwork.cpp
@@ -219,6 +219,7 @@ nsapi_error_t AT_CellularNetwork::set_registration(const char *plmn)
return NSAPI_ERROR_DEVICE_ERROR;
}
if (mode != NWModeAutomatic) {
+ // Force operator registration
return _at.at_cmd_discard("+COPS", "=0");
}
return NSAPI_ERROR_OK;
diff --git a/connectivity/cellular/source/framework/AT/AT_CellularStack.cpp b/connectivity/cellular/source/framework/AT/AT_CellularStack.cpp
index 961d101c9b5..478905e5f75 100644
--- a/connectivity/cellular/source/framework/AT/AT_CellularStack.cpp
+++ b/connectivity/cellular/source/framework/AT/AT_CellularStack.cpp
@@ -332,7 +332,7 @@ nsapi_size_or_error_t AT_CellularStack::socket_recvfrom(nsapi_socket_t handle, S
if (socket->closed) {
tr_info("recvfrom socket %d closed", socket->id);
- return 0;
+ return NSAPI_ERROR_NO_CONNECTION;
}
nsapi_size_or_error_t ret_val = NSAPI_ERROR_OK;
diff --git a/connectivity/cellular/source/framework/device/ATHandler.cpp b/connectivity/cellular/source/framework/device/ATHandler.cpp
index 7388bd4eb4a..7f0337a3d79 100644
--- a/connectivity/cellular/source/framework/device/ATHandler.cpp
+++ b/connectivity/cellular/source/framework/device/ATHandler.cpp
@@ -46,7 +46,7 @@ using namespace std::chrono_literals;
#define PROCESS_URC_TIME 20ms
// Suppress logging of very big packet payloads, maxlen is approximate due to write/read are cached
-#define DEBUG_MAXLEN 60
+#define DEBUG_MAXLEN 120
#define DEBUG_END_MARK "..\r"
const char *mbed::OK = "OK\r\n";
@@ -697,6 +697,11 @@ ssize_t ATHandler::read_hex_string(char *buf, size_t size)
return buf_idx;
}
+int32_t ATHandler::get_last_read_error() const
+{
+ return _last_read_error;
+}
+
int32_t ATHandler::read_int()
{
if (!ok_to_proceed() || !_stop_tag || _stop_tag->found) {
@@ -711,9 +716,11 @@ int32_t ATHandler::read_int()
errno = 0;
long result = std::strtol(buff, NULL, 10);
if ((result == LONG_MIN || result == LONG_MAX) && errno == ERANGE) {
+ _last_read_error = result;
return -1; // overflow/underflow
}
if (result < 0) {
+ _last_read_error = result;
return -1; // negative values are unsupported
}
if (*buff == '\0') {
diff --git a/connectivity/cellular/source/framework/device/CellularStateMachine.cpp b/connectivity/cellular/source/framework/device/CellularStateMachine.cpp
index 44d67b729a8..0a452eacb3a 100644
--- a/connectivity/cellular/source/framework/device/CellularStateMachine.cpp
+++ b/connectivity/cellular/source/framework/device/CellularStateMachine.cpp
@@ -28,7 +28,7 @@ using namespace std::chrono_literals;
// timeout to wait for AT responses
#define TIMEOUT_POWER_ON 1s
-#define TIMEOUT_SIM_PIN 1s
+#define TIMEOUT_SIM_PIN 10s
#define TIMEOUT_NETWORK 10s
/** CellularStateMachine does connecting up to packet service attach, and
* after that it's up to CellularContext::connect() to connect to PDN.
diff --git a/connectivity/drivers/cellular/GEMALTO/CMakeLists.txt b/connectivity/drivers/cellular/GEMALTO/CMakeLists.txt
index d7bf4f24272..076c1fd212c 100644
--- a/connectivity/drivers/cellular/GEMALTO/CMakeLists.txt
+++ b/connectivity/drivers/cellular/GEMALTO/CMakeLists.txt
@@ -2,5 +2,5 @@
# SPDX-License-Identifier: Apache-2.0
if("COMPONENT_GEMALTO_CINTERION=1" IN_LIST MBED_TARGET_DEFINITIONS)
- add_subdirectory(CINTERION)
+ add_subdirectory(COMPONENT_GEMALTO_CINTERION)
endif()
\ No newline at end of file
diff --git a/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION.cpp b/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION.cpp
index 4a72a93f8a1..2b73e91ba0d 100644
--- a/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION.cpp
+++ b/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION.cpp
@@ -17,6 +17,7 @@
#include "GEMALTO_CINTERION_CellularContext.h"
#include "GEMALTO_CINTERION_CellularInformation.h"
+#include "GEMALTO_CINTERION_CellularNetwork.h"
#include "GEMALTO_CINTERION.h"
#include "AT_CellularNetwork.h"
#include "CellularLog.h"
@@ -30,6 +31,79 @@ GEMALTO_CINTERION::GEMALTO_CINTERION(FileHandle *fh) : AT_CellularDevice(fh)
{
}
+time_t GEMALTO_CINTERION::get_time()
+{
+ tr_info("GEMALTO_CINTERION::get_time\n");
+
+ _at.lock();
+
+ //"+CCLK: \"%y/%m/%d,%H:%M:%S+ZZ"
+ _at.cmd_start_stop("+CCLK", "?");
+ _at.resp_start("+CCLK:");
+
+ char time_str[50];
+ time_t now = 0;
+ while (_at.info_resp()) {
+ int date_len = _at.read_string(time_str, sizeof(time_str));
+ tr_debug("Read %d bytes for the date\n", date_len);
+ if (date_len > 0) {
+ now = parse_time(time_str);
+ }
+ }
+ _at.resp_stop();
+
+ _at.unlock();
+
+ // adjust for timezone offset which is +/- in 15 minute increments
+ time_t delta = ((time_str[18] - '0') * 10 + (time_str[19] - '0')) * (15 * 60);
+
+ if (time_str[17] == '-') {
+ now = now + delta;
+ } else if (time_str[17] == '+') {
+ now = now - delta;
+ }
+
+ return now;
+}
+
+time_t GEMALTO_CINTERION::get_local_time()
+{
+ tr_info("GEMALTO_CINTERION::get_local_time\n");
+
+ _at.lock();
+
+ //"+CCLK: \"%y/%m/%d,%H:%M:%S"
+ _at.cmd_start_stop("+CCLK", "?");
+ _at.resp_start("+CCLK:");
+
+ char time_str[50];
+ time_t now;
+ while (_at.info_resp()) {
+ int date_len = _at.read_string(time_str, sizeof(time_str));
+ tr_debug("Read %d bytes for the date\n", date_len);
+ if (date_len > 0) {
+ now = parse_time(time_str);
+ }
+ }
+ _at.resp_stop();
+
+ _at.unlock();
+
+ return now;
+}
+
+void GEMALTO_CINTERION::set_time(time_t const epoch, int const timezone)
+{
+ char time_buf[21];
+ strftime(time_buf, sizeof(time_buf), "%g/%m/%d,%H:%M:%S", gmtime(&epoch));
+ snprintf(time_buf + 17, 4, "%+03d", timezone);
+
+ _at.lock();
+ _at.at_cmd_discard("+CCLK", "=", "%s", time_buf);
+ _at.unlock();
+}
+
+
AT_CellularContext *GEMALTO_CINTERION::create_context_impl(ATHandler &at, const char *apn, bool cp_req, bool nonip_req)
{
return new GEMALTO_CINTERION_CellularContext(at, this, apn, cp_req, nonip_req);
@@ -43,6 +117,11 @@ AT_CellularInformation *GEMALTO_CINTERION::open_information_impl(ATHandler &at)
return AT_CellularDevice::open_information_impl(at);
}
+AT_CellularNetwork *GEMALTO_CINTERION::open_network_impl(ATHandler &at)
+{
+ return new GEMALTO_CINTERION_CellularNetwork(at, *this, _module);
+}
+
nsapi_error_t GEMALTO_CINTERION::init()
{
nsapi_error_t err = AT_CellularDevice::init();
@@ -70,6 +149,8 @@ nsapi_error_t GEMALTO_CINTERION::init()
init_module_ems31();
} else if (memcmp(model, "EHS5-E", sizeof("EHS5-E") - 1) == 0) {
init_module_ehs5e();
+ } else if (memcmp(model, "TX62", sizeof("TX62") - 1) == 0) {
+ init_module_tx62();
} else {
tr_error("Cinterion model unsupported %s", model);
return NSAPI_ERROR_UNSUPPORTED;
@@ -202,6 +283,58 @@ void GEMALTO_CINTERION::init_module_ehs5e()
_module = ModuleEHS5E;
}
+void GEMALTO_CINTERION::init_module_tx62()
+{
+ // TX-62
+ static const intptr_t cellular_properties[AT_CellularDevice::PROPERTY_MAX] = {
+ AT_CellularNetwork::RegistrationModeLAC,// C_EREG
+ AT_CellularNetwork::RegistrationModeDisable, // C_GREG
+ AT_CellularNetwork::RegistrationModeDisable, // C_REG
+ 0, // AT_CGSN_WITH_TYPE
+ 0, // AT_CGDATA
+ 1, // AT_CGAUTH
+ 1, // AT_CNMI
+ 1, // AT_CSMP
+ 1, // AT_CMGF
+ 1, // AT_CSDH
+ 1, // PROPERTY_IPV4_STACK
+ 0, // PROPERTY_IPV6_STACK
+ 0, // PROPERTY_IPV4V6_STACK
+ 0, // PROPERTY_NON_IP_PDP_TYPE
+ 1, // PROPERTY_AT_CGEREP
+ 1, // PROPERTY_AT_COPS_FALLBACK_AUTO
+ 7, // PROPERTY_SOCKET_COUNT
+ 1, // PROPERTY_IP_TCP
+ 1, // PROPERTY_IP_UDP
+ 0, // PROPERTY_AT_SEND_DELAY
+ };
+ set_cellular_properties(cellular_properties);
+ _module = ModuleTX62;
+
+ // Enable network time zone updates
+ _at.at_cmd_discard("+CTZU", "=", "%d", 1);
+}
+
+time_t GEMALTO_CINTERION::parse_time(char const *time_str) {
+ struct tm now;
+
+ now.tm_year = std::strtol(time_str, NULL, 10) + 100; // mktime starts from 1900
+ time_str += 3; // Skip '/'
+ now.tm_mon = std::strtol(time_str, NULL, 10);
+ time_str += 3; // Skip '/'
+ now.tm_mday = std::strtol(time_str, NULL, 10);
+ time_str += 3; // Skip ','
+ now.tm_hour = std::strtol(time_str, NULL, 10);
+ time_str += 3; // Skip ':'
+ now.tm_min = std::strtol(time_str, NULL, 10);
+ time_str += 3;
+ now.tm_sec = std::strtol(time_str, NULL, 10);
+
+ tr_debug("Year: %d, month: %d, day:%d, hour:%d, minute:%d, second:%d\n", now.tm_year, now.tm_mon, now.tm_mday, now.tm_hour, now.tm_min, now.tm_sec);
+
+ return mktime(&now);
+}
+
#if MBED_CONF_GEMALTO_CINTERION_PROVIDE_DEFAULT
#include "drivers/BufferedSerial.h"
CellularDevice *CellularDevice::get_default_instance()
diff --git a/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION.h b/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION.h
index ca2d6f542ab..e5c2e59f0bc 100644
--- a/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION.h
+++ b/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION.h
@@ -44,15 +44,38 @@ class GEMALTO_CINTERION : public AT_CellularDevice {
ModuleBGS2,
ModuleEMS31,
ModuleEHS5E,
+ ModuleTX62,
};
static Module get_module();
+ /**
+ * @brief Get the RTC time from the Cinterion, as a UNIX seconds timestamp in UTC
+ */
+ time_t get_time();
+
+ /**
+ * @brief Get the RTC time from the Cinterion, as a UNIX seconds timestamp in the local time zone
+ */
+ time_t get_local_time();
+
+ /**
+ * @brief Set the RTC time on the Cinterion.
+ *
+ * Note that any time set will be overwritten once the modem can get time from a cellular network
+ *
+ * @param timestamp UNIX timestamp to set, in the local time zone
+ * @param timezone Local time zone, as a signed number of 15-minute increments from UTC time. Example:
+ * passing -8 would indicate UTC-2.
+ */
+ virtual void set_time(time_t timestamp, int const timezone = 0);
+
protected: // AT_CellularDevice
virtual AT_CellularContext *create_context_impl(ATHandler &at, const char *apn, bool cp_req = false, bool nonip_req = false);
virtual AT_CellularInformation *open_information_impl(ATHandler &at);
+ AT_CellularNetwork *open_network_impl(ATHandler &at) override;
-protected:
- virtual nsapi_error_t init();
+public:
+ nsapi_error_t init() override;
private:
static Module _module;
@@ -60,6 +83,10 @@ class GEMALTO_CINTERION : public AT_CellularDevice {
void init_module_els61();
void init_module_ems31();
void init_module_ehs5e();
+ void init_module_tx62();
+
+ /// Convert time & date string returned by the modem into time_t
+ time_t parse_time(char const * time_str);
};
} // namespace mbed
diff --git a/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION_CellularContext.cpp b/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION_CellularContext.cpp
index 38a5ba48196..28faa47e616 100644
--- a/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION_CellularContext.cpp
+++ b/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION_CellularContext.cpp
@@ -49,4 +49,108 @@ NetworkStack *GEMALTO_CINTERION_CellularContext::get_stack()
}
#endif // NSAPI_PPP_AVAILABLE
+nsapi_error_t GEMALTO_CINTERION_CellularContext::do_user_authentication()
+{
+ // if user has defined user name and password we need to call CGAUTH before activating or modifying context
+ if (_pwd && _uname && (strcmp(_pwd, "") != 0) && (strcmp(_uname, "") != 0)) {
+ if (!get_device()->get_property(AT_CellularDevice::PROPERTY_AT_CGAUTH)) {
+ return NSAPI_ERROR_UNSUPPORTED;
+ }
+
+ _at.at_cmd_discard("^SGAUTH", "=", "%d%d%s%s", _cid, _authentication_type, _uname, _pwd);
+
+ if (_at.get_last_error() != NSAPI_ERROR_OK) {
+ return NSAPI_ERROR_AUTH_FAILURE;
+ }
+ }
+ else {
+ tr_info("Empty pwd and username fields: no need for authentication\n");
+ }
+
+ return NSAPI_ERROR_OK;
+}
+
+void GEMALTO_CINTERION_CellularContext::enable_access_technology()
+{
+ if (!_rat.has_value()) {
+ return;
+ }
+
+ switch (*_rat)
+ {
+ case CATM1:
+ _at.at_cmd_discard("^SXRAT", "=","%d", 7); // 7 = CAT.M1
+
+ // Ensure all bands are enabled by setting ^SCFG to the bitmask of all valid bands
+ _at.cmd_start_stop("^SCFG", "=","%s%d", "Radio/Band/CatM", "F0E189F");
+ _at.resp_start("^SCFG");
+ break;
+
+ case CATNB:
+ _at.at_cmd_discard("^SXRAT", "=","%d", 8); // 8 = CAT.NB1
+
+ // Ensure all bands are enabled by setting ^SCFG to the bitmask of all valid bands
+ _at.cmd_start_stop("^SCFG", "=","%s%s", "Radio/Band/CatNB", "10000200000000");
+ _at.resp_start("^SCFG");
+ break;
+
+ default:
+ break;
+ }
+}
+
+bool GEMALTO_CINTERION_CellularContext::get_context()
+{
+ _at.cmd_start_stop("+CGDCONT", "?");
+ _at.resp_start("+CGDCONT:");
+ set_cid(-1);
+ int cid_max = 0; // needed when creating new context
+ char apn[MAX_ACCESSPOINT_NAME_LENGTH];
+ int apn_len = 0;
+
+ 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));
+ if (pdp_type_len > 0) {
+ apn_len = _at.read_string(apn, sizeof(apn));
+ if (apn_len > 0 && (strcmp(apn, _apn) == 0)) {
+ // APN matched -> Check PDP type
+ pdp_type_t pdp_type = string_to_pdp_type(pdp_type_from_context);
+ tr_debug("CID %d APN \"%s\" pdp_type %u", cid, apn, pdp_type);
+
+ // Accept exact matching PDP context type or dual PDP context for modems that support both IPv4 and IPv6 stacks
+ if (get_device()->get_property(pdp_type_t_to_cellular_property(pdp_type)) ||
+ ((pdp_type == IPV4V6_PDP_TYPE && (get_device()->get_property(AT_CellularDevice::PROPERTY_IPV4_PDP_TYPE) &&
+ get_device()->get_property(AT_CellularDevice::PROPERTY_IPV6_PDP_TYPE))) && !_nonip_req)) {
+ _pdp_type = pdp_type;
+ set_cid(cid);
+ }
+ }
+ else {
+ cid_max = 0;
+ }
+ }
+ }
+
+ _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) {
+ memcpy(_found_apn, apn, apn_len + 1);
+ }
+
+ tr_info("Found PDP context %d", _cid);
+
+ return true;
+}
+
} /* namespace mbed */
diff --git a/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION_CellularContext.h b/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION_CellularContext.h
index 86209eda599..987d116aefa 100644
--- a/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION_CellularContext.h
+++ b/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION_CellularContext.h
@@ -30,6 +30,9 @@ class GEMALTO_CINTERION_CellularContext: public AT_CellularContext {
#if !NSAPI_PPP_AVAILABLE
virtual NetworkStack *get_stack();
#endif // NSAPI_PPP_AVAILABLE
+ nsapi_error_t do_user_authentication() override;
+ void enable_access_technology() override;
+ bool get_context() override;
};
} /* namespace mbed */
diff --git a/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION_CellularNetwork.h b/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION_CellularNetwork.h
new file mode 100644
index 00000000000..421b8e7e0e1
--- /dev/null
+++ b/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION_CellularNetwork.h
@@ -0,0 +1,46 @@
+/*
+ * 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 GEMALTO_CINTERION_CELLULARNETWORK_H_
+#define GEMALTO_CINTERION_CELLULARNETWORK_H_
+
+#include "AT_CellularNetwork.h"
+#include "GEMALTO_CINTERION.h"
+
+namespace mbed {
+
+class GEMALTO_CINTERION_CellularNetwork: public AT_CellularNetwork {
+ const GEMALTO_CINTERION::Module _module;
+public:
+ GEMALTO_CINTERION_CellularNetwork(ATHandler &at, AT_CellularDevice &device, GEMALTO_CINTERION::Module module):
+ AT_CellularNetwork(at, device),
+ _module(module)
+ {}
+
+ virtual nsapi_error_t set_attach()
+ {
+ if (_module == GEMALTO_CINTERION::ModuleTX62) {
+ return NSAPI_ERROR_OK;
+ }
+ return AT_CellularNetwork::set_attach();
+ }
+
+protected:
+};
+
+} /* namespace mbed */
+
+#endif // GEMALTO_CINTERION_CELLULARNETWORK_H_
\ No newline at end of file
diff --git a/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION_CellularStack.cpp b/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION_CellularStack.cpp
index a78e89a062b..dbca19afaa2 100644
--- a/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION_CellularStack.cpp
+++ b/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION_CellularStack.cpp
@@ -100,19 +100,111 @@ void GEMALTO_CINTERION_CellularStack::urc_sisr()
sisr_urc_handler(sock_id, urc_code);
}
+void GEMALTO_CINTERION_CellularStack::urc_sysstart()
+{
+ // close sockets if open
+ _at.lock();
+ for (int i = 0; i < _device.get_property(AT_CellularDevice::PROPERTY_SOCKET_COUNT); i++) {
+ _at.clear_error();
+ socket_close_impl(i);
+ }
+ _at.clear_error();
+ _at.unlock();
+}
+
void GEMALTO_CINTERION_CellularStack::sisr_urc_handler(int sock_id, int urc_code)
{
CellularSocket *sock = find_socket(sock_id);
if (sock) {
- if (urc_code == 1) { // data available
+ if (urc_code > 0) { // data available
if (sock->_cb) {
- sock->pending_bytes = 1;
+ sock->pending_bytes = urc_code;
sock->_cb(sock->_data);
}
}
}
}
+void GEMALTO_CINTERION_CellularStack::urc_gnss() {
+ char gnss_string[100] = {'$', 'G'};
+ if (_gnss_cb) {
+ _at.set_delimiter('\n');
+ _at.read_string(&gnss_string[2], 98);
+ _at.set_default_delimiter();
+ _gnss_cb(gnss_string);
+ }
+}
+
+void GEMALTO_CINTERION_CellularStack::beginGNSS(mbed::Callback gnss_cb) {
+ _at.lock();
+ _gnss_cb = gnss_cb;
+ _at.at_cmd_discard("^SGPSC", "=", "%s%d", "Engine/StartMode", 0);
+ _at.at_cmd_discard("^SGPSC", "=", "%s%d", "Engine", 0);
+ _at.at_cmd_discard("^SGPSC", "=", "%s%s", "Nmea/Urc", "off");
+
+ // Set up LNA_ENABLE GPIO
+ _at.at_cmd_discard("^SPIO", "=", "%d", 1);
+ _at.at_cmd_discard("^SCPIN", "=", "%d%d%d%d", 1, 7, 1, 0);
+ _at.clear_error();
+ _at.unlock();
+}
+
+void GEMALTO_CINTERION_CellularStack::endGNSS() {
+ _at.lock();
+ _at.at_cmd_discard("^SSIO", "=", "%d%d", 7, 0);
+ _gnss_cb = nullptr;
+ _at.clear_error();
+ _at.unlock();
+}
+
+void GEMALTO_CINTERION_CellularStack::enableCmux()
+{
+ _at.at_cmd_discard("+CMUX", "=0");
+}
+
+int GEMALTO_CINTERION_CellularStack::startGNSS() {
+ _at.lock();
+ _engine = false;
+ _at.at_cmd_discard("^SSIO", "=", "%d%d", 7, 1);
+ _at.cmd_start_stop("^SGPSC", "=", "%s%d", "Engine", 3);
+ _at.resp_start("^SGPSC: \"Engine\",");
+
+ char respEng[2];
+ int resp_len = _at.read_string(respEng, sizeof(respEng));
+ if (strcmp(respEng, "3") != 0) {
+ _engine = false;
+ _at.at_cmd_discard("^SGPSC", "=", "%s%d", "Engine", 0);
+ _at.at_cmd_discard("^SGPSC", "=", "%s%s", "Nmea/Urc", "off");
+ return 0;
+ }
+ _engine = true;
+ _at.at_cmd_discard("^SGPSC", "=", "%s%s", "Nmea/Urc", "on");
+ _at.clear_error();
+ _at.unlock();
+
+ return 1;
+}
+
+void GEMALTO_CINTERION_CellularStack::stopGNSS() {
+ if(_engine) {
+ _at.lock();
+ _at.at_cmd_discard("^SGPSC", "=", "%s%s", "Nmea/Urc", "off");
+ _at.at_cmd_discard("^SGPSC", "=", "%s%d", "Engine", 0);
+ _at.clear_error();
+ _at.unlock();
+ _engine = false;
+ }
+}
+
+void GEMALTO_CINTERION_CellularStack::setGNSS_PSM(bool const enable) {
+ if(_engine) {
+ _at.lock();
+ _at.at_cmd_discard("^SGPSC", "=", "%s%d", "Power/Psm", enable);
+ _at.clear_error();
+ _at.unlock();
+ }
+}
+
nsapi_error_t GEMALTO_CINTERION_CellularStack::socket_stack_init()
{
_at.lock();
@@ -121,6 +213,9 @@ nsapi_error_t GEMALTO_CINTERION_CellularStack::socket_stack_init()
_at.set_urc_handler("^SIS:", mbed::Callback(this, &GEMALTO_CINTERION_CellularStack::urc_sis));
_at.set_urc_handler("^SISW:", mbed::Callback(this, &GEMALTO_CINTERION_CellularStack::urc_sisw));
_at.set_urc_handler("^SISR:", mbed::Callback(this, &GEMALTO_CINTERION_CellularStack::urc_sisr));
+ _at.set_urc_handler("^SYSSTART", mbed::Callback(this, &GEMALTO_CINTERION_CellularStack::urc_sysstart));
+ _at.set_urc_handler("^SGPSE", mbed::Callback(this, &GEMALTO_CINTERION_CellularStack::urc_gnss));
+ _at.set_urc_handler("$G", mbed::Callback(this, &GEMALTO_CINTERION_CellularStack::urc_gnss));
} else { // recovery cleanup
// close all Internet and connection profiles
for (int i = 0; i < _device.get_property(AT_CellularDevice::PROPERTY_SOCKET_COUNT); i++) {
@@ -151,6 +246,46 @@ nsapi_error_t GEMALTO_CINTERION_CellularStack::socket_close_impl(int sock_id)
return _at.get_last_error();
}
+#ifdef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES
+nsapi_error_t GEMALTO_CINTERION_CellularStack::gethostbyname(const char *host, SocketAddress *address,
+ nsapi_version_t version, const char *interface_name)
+{
+ (void) interface_name;
+ MBED_ASSERT(host);
+ MBED_ASSERT(address);
+
+ _at.lock();
+
+ if (_dns_callback) {
+ _at.unlock();
+ return NSAPI_ERROR_BUSY;
+ }
+
+ if (!address->set_ip_address(host)) {
+ //_at.set_at_timeout(1min);
+ _at.cmd_start_stop("^SISX" , "=" , "%s%d%s", "HostByName" , _cid, host);
+ _at.resp_start("^SISX: \"HostByName\",");
+ char ipAddress[NSAPI_IP_SIZE];
+ int size = _at.read_string(ipAddress, sizeof(ipAddress));
+ if (size > 0) {
+ //Valid string received
+ tr_info("Read %d bytes. Valid string: %s\n", size, ipAddress);
+ _at.restore_at_timeout();
+ if (!address->set_ip_address(ipAddress)) {
+ _at.unlock();
+ return NSAPI_ERROR_DNS_FAILURE;
+ }
+ } else {
+ //Null string received
+ tr_info("Read %d bytes. Null string\n", size);
+ return NSAPI_ERROR_NO_ADDRESS;
+ }
+ }
+
+ return _at.unlock_return_error();
+}
+#endif
+
nsapi_error_t GEMALTO_CINTERION_CellularStack::socket_open_defer(CellularSocket *socket, const SocketAddress *address)
{
int retry_open = 1;
@@ -159,6 +294,7 @@ nsapi_error_t GEMALTO_CINTERION_CellularStack::socket_open_defer(CellularSocket
int internet_service_id = find_socket_index(socket);
bool foundSrvType = false;
bool foundConIdType = false;
+
_at.cmd_start_stop("^SISS", "?");
_at.resp_start("^SISS:");
/*
@@ -393,6 +529,7 @@ nsapi_size_or_error_t GEMALTO_CINTERION_CellularStack::socket_recvfrom_impl(Cell
size = UDP_PACKET_SIZE;
}
+ tr_info("requesting %d bytes\n", size);
_at.cmd_start_stop("^SISR", "=", "%d%d", socket->id, size);
sisr_retry:
@@ -421,26 +558,63 @@ nsapi_size_or_error_t GEMALTO_CINTERION_CellularStack::socket_recvfrom_impl(Cell
return NSAPI_ERROR_WOULD_BLOCK;
}
if (len == -1) {
+ if (GEMALTO_CINTERION::get_module() == GEMALTO_CINTERION::ModuleTX62 && _at.get_last_read_error() == -2) {
+ _at.process_oob();
+ tr_error("Socket %d recvfrom finished!", socket->id);
+ socket->pending_bytes = 0;
+ return NSAPI_ERROR_OK;
+ }
tr_error("Socket %d recvfrom failed!", socket->id);
return NSAPI_ERROR_DEVICE_ERROR;
}
- socket->pending_bytes = 0;
if (len >= (nsapi_size_or_error_t)size) {
len = (nsapi_size_or_error_t)size;
- int remain_len = _at.read_int();
- if (remain_len > 0) {
- socket->pending_bytes = 1;
- }
}
// UDP Udp_RemClient
if (socket->proto == NSAPI_UDP && GEMALTO_CINTERION::get_module() != GEMALTO_CINTERION::ModuleBGS2) {
- char ip_address[NSAPI_IPv6_SIZE + sizeof("[]:12345") - 1 + 1];
- int ip_len = _at.read_string(ip_address, sizeof(ip_address));
- if (ip_len <= 0) {
- tr_error("Socket %d recvfrom addr (len %d)", socket->id, ip_len);
- return NSAPI_ERROR_DEVICE_ERROR;
- }
+ size_t ip_address_len = NSAPI_IPv6_SIZE + sizeof("[]:12345") - 1 + 1;
+ char ip_address[ip_address_len];
+
+ if (GEMALTO_CINTERION::get_module() == GEMALTO_CINTERION::ModuleTX62) {
+ // Local buffer for parsing Udp_RemClient for TX62
+ uint8_t at_buf[ip_address_len];
+ size_t ip_len = 0;
+
+ // Skip
+ nsapi_size_or_error_t rem_len = _at.read_int();
+
+ // Wait for full in the _at buffer
+ do {
+ int len = _at.read_bytes(at_buf + ip_len, 1);
+ if (len <= 0) {
+ tr_error("Socket %d recvfrom addr (len %d)", socket->id, ip_len);
+ return NSAPI_ERROR_DEVICE_ERROR;
+ }
+ ip_len += len;
+ } while (ip_len < ip_address_len && at_buf[ip_len - 2] != '\r' && at_buf[ip_len - 1] != '\n');
+
+ // if (ip_len < sizeof("0.0.0.0:0")) {
+ if (ip_len < sizeof("[]:0")) {
+ tr_error("Socket %d has no address", socket->id);
+ goto sisr_retry;
+ }
+
+ // at_buf contains remote client IP information
+ // in the format ":"\r\n.
+
+ // Terminate the C string at the closing quotation mark
+ at_buf[ip_len - 3] = '\0';
+ // Skip the opening quotation mark
+ memcpy(ip_address, at_buf + 1, ip_len - 4);
+ tr_info("ip_address %s (%d)", ip_address, ip_len - 4);
+ } else {
+ int ip_len = _at.read_string(ip_address, sizeof(ip_address));
+ if (ip_len <= 0) {
+ tr_error("Socket %d recvfrom addr (len %d)", socket->id, ip_len);
+ return NSAPI_ERROR_DEVICE_ERROR;
+ }
+ }
if (address) {
char *ip_start = ip_address;
char *ip_stop;
@@ -473,6 +647,10 @@ nsapi_size_or_error_t GEMALTO_CINTERION_CellularStack::socket_recvfrom_impl(Cell
nsapi_size_or_error_t recv_len = _at.read_bytes((uint8_t *)buffer, len);
+ if (recv_len < len) {
+ goto sisr_retry;
+ }
+
_at.resp_stop();
return (_at.get_last_error() == NSAPI_ERROR_OK) ? (recv_len ? recv_len : NSAPI_ERROR_WOULD_BLOCK) : NSAPI_ERROR_DEVICE_ERROR;
diff --git a/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION_CellularStack.h b/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION_CellularStack.h
index 01c5b71c652..31eee6b945f 100644
--- a/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION_CellularStack.h
+++ b/connectivity/drivers/cellular/GEMALTO/COMPONENT_GEMALTO_CINTERION/GEMALTO_CINTERION_CellularStack.h
@@ -34,6 +34,21 @@ class GEMALTO_CINTERION_CellularStack : public AT_CellularStack {
*/
nsapi_error_t socket_stack_init();
+ /**
+ * @brief Enable GNSS output, if supported by the Cinterion module
+ *
+ * @param gnss_cb Callback which will be called when a new GNSS sentence is received
+ */
+ void beginGNSS(mbed::Callback gnss_cb);
+
+ void enableCmux();
+ void endGNSS();
+ int startGNSS();
+ void stopGNSS();
+
+ /// Set whether Power Save Mode is enabled for the GNSS in the Cinterion module
+ void setGNSS_PSM(bool enable);
+
protected:
virtual nsapi_error_t socket_close_impl(int sock_id);
@@ -48,13 +63,19 @@ class GEMALTO_CINTERION_CellularStack : public AT_CellularStack {
virtual nsapi_error_t socket_connect(nsapi_socket_t handle, const SocketAddress &address);
+#ifdef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES
+ virtual nsapi_error_t gethostbyname(const char *host, SocketAddress *address, nsapi_version_t version, const char *interface_name);
+#endif
+
private:
// socket URC handlers as per Cinterion AT manuals
void urc_sis();
void urc_sisw();
+ void urc_sysstart();
void sisw_urc_handler(int sock_id, int urc_code);
void urc_sisr();
void sisr_urc_handler(int sock_id, int urc_code);
+ void urc_gnss();
// sockets need a connection profile, one profile is enough to support single stack sockets
nsapi_error_t create_connection_profile(int connection_profile_id);
@@ -67,6 +88,14 @@ class GEMALTO_CINTERION_CellularStack : public AT_CellularStack {
const char *_apn;
const char *_user;
const char *_password;
+ bool _engine;
+
+ mbed::Callback _gnss_cb;
+
+#ifdef MBED_CONF_CELLULAR_OFFLOAD_DNS_QUERIES
+ hostbyname_cb_t _dns_callback;
+ nsapi_version_t _dns_version;
+#endif
};
} // namespace mbed
diff --git a/targets/drivers.json5 b/targets/drivers.json5
index fe8a148ea5e..bde03a69640 100644
--- a/targets/drivers.json5
+++ b/targets/drivers.json5
@@ -74,8 +74,8 @@
"friendly_name": "STMod Cellular Modules"
},
"COMPONENT_GEMALTO_CINTERION": {
- "description": "Gemalto Cinterion family of cellular modules (ELS61, BGS2, EMS31, and EHS5-E are supported)",
- "friendly_name": "Gemalto Cinterion"
+ "description": "Telit Cinterion (formerly Thales Cinterion, formerly Gemalto Cinterion) family of cellular modules (TX62, ELS61, BGS2, EMS31, and EHS5-E are supported)",
+ "friendly_name": "Telit/Thales/Gemalto Cinterion"
},
"COMPONENT_GENERIC_AT3GPP": {
"description": "Generic cellular module supporting 3GPP AT command set",