From 0f2d09229f705ab4d7dcf05fdcd30b74732377d7 Mon Sep 17 00:00:00 2001 From: Rodrigo Alfonso Date: Sun, 18 Aug 2024 04:09:43 -0300 Subject: [PATCH] Starting ISP connection --- README.md | 2 +- examples/LinkMobile_demo/src/main.cpp | 48 ++++++++++-------- lib/LinkMobile.hpp | 70 ++++++++++++++++++++++++--- 3 files changed, 92 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 0e79d03..7a2eda8 100644 --- a/README.md +++ b/README.md @@ -447,7 +447,7 @@ Name | Return type | Description `transfer(dataToSend, receivedData)` | **bool** | Requests a data transfer (up to `254` bytes) within a P2P connection and responds the received data. The `receivedData` is a pointer to a `LinkWireless::DataTransfer` struct that will be filled with data. It can point to `dataToSend`. When the transfer is completed, the `completed` field will be `true`. `hangUp()` | **bool** | Hangs up the current P2P call. `readConfiguration(configurationData)` | **bool** | Retrieves the adapter configuration, and puts it in the `configurationData` struct. If the adapter has an active session, the data is already loaded, so it's instantaneous. -`getState()` | **LinkMobile::State** | Returns the current state (one of `LinkMobile::State::NEEDS_RESET`, `LinkMobile::State::PINGING`, `LinkMobile::State::WAITING_TO_START`, `LinkMobile::State::STARTING_SESSION`, `LinkMobile::State::ACTIVATING_SIO32`, `LinkMobile::State::WAITING_32BIT_SWITCH`, `LinkMobile::State::READING_CONFIGURATION`, `LinkMobile::State::SESSION_ACTIVE`, `LinkMobile::State::CALL_REQUESTED`, `LinkMobile::State::CALLING`, `LinkMobile::State::CALL_ESTABLISHED`, `LinkMobile::State::SESSION_ACTIVE_ISP`, `LinkMobile::State::SHUTDOWN_REQUESTED`, `LinkMobile::State::ENDING_SESSION`, `LinkMobile::State::WAITING_8BIT_SWITCH`, or `LinkMobile::State::SHUTDOWN`). +`getState()` | **LinkMobile::State** | Returns the current state (one of `LinkMobile::State::NEEDS_RESET`, `LinkMobile::State::PINGING`, `LinkMobile::State::WAITING_TO_START`, `LinkMobile::State::STARTING_SESSION`, `LinkMobile::State::ACTIVATING_SIO32`, `LinkMobile::State::WAITING_32BIT_SWITCH`, `LinkMobile::State::READING_CONFIGURATION`, `LinkMobile::State::SESSION_ACTIVE`, `LinkMobile::State::CALL_REQUESTED`, `LinkMobile::State::CALLING`, `LinkMobile::State::CALL_ESTABLISHED`, `LinkMobile::State::ISP_CALL_REQUESTED`, `LinkMobile::State::ISP_CALLING`, `LinkMobile::State::ISP_LOGIN`, `LinkMobile::State::ISP_ACTIVE`, `LinkMobile::State::SHUTDOWN_REQUESTED`, `LinkMobile::State::ENDING_SESSION`, `LinkMobile::State::WAITING_8BIT_SWITCH`, or `LinkMobile::State::SHUTDOWN`). `getRole()` | **LinkMobile::Role** | Returns the current role in the P2P connection (one of `LinkMobile::Role::NO_P2P_CONNECTION`, `LinkMobile::Role::CALLER`, or `LinkMobile::Role::RECEIVER`). `isConfigurationValid()` | **int** | Returns whether the adapter has been configured or not. Returns `1` = yes, `0` = no, `-1` = unknown (no session active). `isP2PConnected()` | **bool** | Returns `true` if a P2P call is established (the state is `CALL_ESTABLISHED`). diff --git a/examples/LinkMobile_demo/src/main.cpp b/examples/LinkMobile_demo/src/main.cpp index 95844ed..02a6594 100644 --- a/examples/LinkMobile_demo/src/main.cpp +++ b/examples/LinkMobile_demo/src/main.cpp @@ -85,7 +85,8 @@ start: output += "\n (SELECT = stop)"; } else if (linkMobile->getState() == LinkMobile::State::SESSION_ACTIVE) { output += "\nL = Read Configuration"; - output += "\nR = Call someone\n"; + output += "\nR = Call someone"; + output += "\nSTART = Call the ISP"; output += "\n (A = ok)\n (SELECT = stop)"; } else { if (linkMobile->isP2PConnected()) { @@ -217,23 +218,24 @@ std::string readConfiguration() { if (!linkMobile->readConfiguration(data)) return "Read failed :("; - return ("Magic:\n " + toStr(data.magic, 2) + "\nRegistered:\n $" + - toHex(data.registrationState) + "\nPrimary DNS:\n " + - std::to_string(data.primaryDNS[0]) + "." + - std::to_string(data.primaryDNS[1]) + "." + - std::to_string(data.primaryDNS[2]) + "." + - std::to_string(data.primaryDNS[3]) + "\nSecondary DNS:\n " + - std::to_string(data.secondaryDNS[0]) + "." + - std::to_string(data.secondaryDNS[1]) + "." + - std::to_string(data.secondaryDNS[2]) + "." + - std::to_string(data.secondaryDNS[3]) + "\nLoginID:\n " + - toStr(data.loginID, 10) + "\nEmail:\n " + toStr(data.email, 24) + - "\nSMTP Server:\n " + toStr(data.smtpServer, 20) + - "\nPOP Server:\n " + toStr(data.popServer, 19) + "\nIs Valid:\n " + - std::to_string(linkMobile->isConfigurationValid()) + "\n\nMode: " + - (linkMobile->getDataSize() == LinkSPI::DataSize::SIZE_32BIT - ? "SIO32" - : "SIO8")); + return ( + "Magic:\n " + toStr(data.magic, 2) + ", $" + + toHex(data.registrationState) + "\nPrimary DNS:\n " + + std::to_string(data.primaryDNS[0]) + "." + + std::to_string(data.primaryDNS[1]) + "." + + std::to_string(data.primaryDNS[2]) + "." + + std::to_string(data.primaryDNS[3]) + "\nSecondary DNS:\n " + + std::to_string(data.secondaryDNS[0]) + "." + + std::to_string(data.secondaryDNS[1]) + "." + + std::to_string(data.secondaryDNS[2]) + "." + + std::to_string(data.secondaryDNS[3]) + "\nLoginID:\n " + + toStr(data.loginId, 10) + "\nEmail:\n " + toStr(data.email, 24) + + "\nSMTP Server:\n " + toStr(data.smtpServer, 20) + "\nPOP Server:\n " + + toStr(data.popServer, 19) + "\nISP Number #1:\n " + + std::string(data._ispNumber1) + "\n\nIs Valid: " + + std::to_string(linkMobile->isConfigurationValid()) + "\nMode: " + + (linkMobile->getDataSize() == LinkSPI::DataSize::SIZE_32BIT ? "SIO32" + : "SIO8")); } std::string getNumberInput() { @@ -278,7 +280,7 @@ std::string getNumberInput() { return ""; } if (didPress(KEY_A, a)) { - if (selectedNumber.size() < LINK_MOBILE_MAX_PHONE_NUMBER_SIZE) + if (selectedNumber.size() < LINK_MOBILE_MAX_PHONE_NUMBER_LENGTH) selectedNumber += rows[selectedY][selectedX]; } if (didPress(KEY_SELECT, select)) @@ -329,6 +331,14 @@ std::string getStateString(LinkMobile::State state) { return "CALLING"; case LinkMobile::State::CALL_ESTABLISHED: return "CALL_ESTABLISHED"; + case LinkMobile::State::ISP_CALL_REQUESTED: + return "ISP_CALL_REQUESTED"; + case LinkMobile::State::ISP_CALLING: + return "ISP_CALLING"; + case LinkMobile::State::ISP_LOGIN: + return "ISP_LOGIN"; + case LinkMobile::State::ISP_ACTIVE: + return "ISP_ACTIVE"; case LinkMobile::State::SHUTDOWN_REQUESTED: return "SHUTDOWN_REQUESTED"; case LinkMobile::State::ENDING_SESSION: diff --git a/lib/LinkMobile.hpp b/lib/LinkMobile.hpp index 4c23e24..18dacac 100644 --- a/lib/LinkMobile.hpp +++ b/lib/LinkMobile.hpp @@ -54,7 +54,9 @@ static volatile char LINK_MOBILE_VERSION[] = "LinkMobile/v7.0.0"; #define LINK_MOBILE_MAX_USER_TRANSFER_LENGTH 254 #define LINK_MOBILE_MAX_COMMAND_TRANSFER_LENGTH 255 -#define LINK_MOBILE_MAX_PHONE_NUMBER_SIZE 32 +#define LINK_MOBILE_MAX_PHONE_NUMBER_LENGTH 32 +#define LINK_MOBILE_MAX_LOGIN_ID_LENGTH 32 +#define LINK_MOBILE_MAX_PASSWORD_LENGTH 32 #define LINK_MOBILE_COMMAND_TRANSFER_BUFFER \ (LINK_MOBILE_MAX_COMMAND_TRANSFER_LENGTH + 4) #define LINK_MOBILE_DEFAULT_TIMEOUT (60 * 3) @@ -96,6 +98,7 @@ class LinkMobile { static constexpr int ACK_SENDER = 0; static constexpr int CONFIGURATION_DATA_SIZE = 192; static constexpr int CONFIGURATION_DATA_CHUNK = CONFIGURATION_DATA_SIZE / 2; + static constexpr const char* FALLBACK_ISP_NUMBER = "#9677"; static constexpr int COMMAND_BEGIN_SESSION = 0x10; static constexpr int COMMAND_END_SESSION = 0x11; static constexpr int COMMAND_DIAL_TELEPHONE = 0x12; @@ -137,7 +140,10 @@ class LinkMobile { CALL_REQUESTED, CALLING, CALL_ESTABLISHED, - SESSION_ACTIVE_ISP, + ISP_CALL_REQUESTED, + ISP_CALLING, + ISP_LOGIN, + ISP_ACTIVE, SHUTDOWN_REQUESTED, ENDING_SESSION, WAITING_8BIT_SWITCH, @@ -183,7 +189,7 @@ class LinkMobile { u8 _unused1_; u8 primaryDNS[4]; u8 secondaryDNS[4]; - char loginID[10]; + char loginId[10]; u8 _unused2_[22]; char email[24]; u8 _unused3_[6]; @@ -195,6 +201,8 @@ class LinkMobile { u8 configurationSlot3[24]; u8 checksumHigh; u8 checksumLow; + + char _ispNumber1[16 + 1]; // (parsed from `configurationSlot1`) } __attribute__((packed)); struct DataTransfer { @@ -285,7 +293,39 @@ class LinkMobile { auto request = UserRequest{.type = UserRequest::Type::CALL}; copyString(request.phoneNumber, phoneNumber, - LINK_MOBILE_MAX_PHONE_NUMBER_SIZE); + LINK_MOBILE_MAX_PHONE_NUMBER_LENGTH); + pushRequest(request); + return true; + } + + /** + * @brief Calls the ISP number registered in the adapter configuration, or a + * default number if the adapter hasn't been configured. Then, performs a + * login operation using the provided `password` and `loginId`. If `loginId` + * is empty and the adapter has been configured, it will use the one stored in + * the configuration. + * @param password The password, as a null-terminated string (max `32` + * characters). + * @param loginId The login ID, as a null-terminated string (max `32` + * characters). It can be empty if it's already stored in the configuration. + * \warning Non-blocking. Returns `true` immediately, or `false` + * if there's no active session, no available request slots, or no login ID. + */ + bool callISP(const char* password, const char* loginId = "") { + if (state != SESSION_ACTIVE || userRequests.isFull()) + return false; + + auto request = UserRequest{.type = UserRequest::Type::ISP_LOGIN}; + copyString(request.password, password, LINK_MOBILE_MAX_PASSWORD_LENGTH); + + if (std::strlen(loginId) > 0) + copyString(request.loginId, loginId, LINK_MOBILE_MAX_LOGIN_ID_LENGTH); + else if (adapterConfiguration.isValid()) + copyString(request.loginId, adapterConfiguration.fields._ispNumber1, + LINK_MOBILE_MAX_LOGIN_ID_LENGTH); + else + return false; + pushRequest(request); return true; } @@ -494,12 +534,14 @@ class LinkMobile { enum AdapterType { BLUE, YELLOW, GREEN, RED, UNKNOWN }; struct UserRequest { - enum Type { CALL, TRANSFER, HANG_UP, SHUTDOWN }; + enum Type { CALL, ISP_LOGIN, TRANSFER, HANG_UP, SHUTDOWN }; Type type; - char phoneNumber[LINK_MOBILE_MAX_PHONE_NUMBER_SIZE + 1]; + char phoneNumber[LINK_MOBILE_MAX_PHONE_NUMBER_LENGTH + 1]; DataTransfer send; DataTransfer* receive; + char loginId[LINK_MOBILE_MAX_LOGIN_ID_LENGTH + 1]; + char password[LINK_MOBILE_MAX_PASSWORD_LENGTH + 1]; bool commandSent; u32 timeout; }; @@ -833,11 +875,13 @@ class LinkMobile { adapterConfiguration.bytes[offset + i] = asyncCommand.cmd.data.bytes[1 + i]; - if (offset == 0) + if (offset == 0) { cmdReadConfigurationData(CONFIGURATION_DATA_CHUNK, CONFIGURATION_DATA_CHUNK); - else + } else { + setISPNumber(); setState(SESSION_ACTIVE); + } break; } case SESSION_ACTIVE: { @@ -961,6 +1005,16 @@ class LinkMobile { sendCommandAsync(buildCommand(COMMAND_READ_CONFIGURATION_DATA, true)); } + void setISPNumber() { + static const char BCD[16] = "0123456789#*cde"; + + for (u32 i = 0; i < 8; i++) { + u8 b = adapterConfiguration.fields.configurationSlot1[i]; + adapterConfiguration.fields._ispNumber1[i * 2] = BCD[b >> 4]; + adapterConfiguration.fields._ispNumber1[i * 2 + 1] = BCD[b & 0xF]; + } + } + void pushRequest(UserRequest request) { request.timeout = 0; userRequests.syncPush(request);