M module-apps/application-call/model/CallModel.cpp => module-apps/application-call/model/CallModel.cpp +7 -2
@@ 85,9 85,14 @@ namespace app::call
return succeed;
}
- void CallModel::transmitDtmfTone(const uint32_t &digit)
+ void CallModel::transmitDtmfTone(const uint8_t &digitCode)
{
- CellularServiceAPI::TransmitDtmfTones(application, digit);
+ try {
+ CellularServiceAPI::TransmitDtmfTones(application, DTMFCode(static_cast<char>(digitCode)));
+ }
+ catch (std::out_of_range &e) {
+ LOG_ERROR("Can't send DTMF code for digit: %c", static_cast<char>(digitCode));
+ }
}
utils::PhoneNumber CallModel::getPhoneNumber()
M module-apps/application-call/model/CallModel.hpp => module-apps/application-call/model/CallModel.hpp +2 -2
@@ 59,7 59,7 @@ namespace app::call
virtual void hangUpCall() = 0;
virtual void answerCall() = 0;
virtual bool sendSms(const UTF8 &smsBody) = 0;
- virtual void transmitDtmfTone(const uint32_t &digit) = 0;
+ virtual void transmitDtmfTone(const uint8_t &digitCode) = 0;
virtual void muteCall() = 0;
virtual void unmuteCall() = 0;
virtual void turnLoudspeakerOn() = 0;
@@ 89,7 89,7 @@ namespace app::call
void hangUpCall() final;
void answerCall() final;
bool sendSms(const UTF8 &smsBody) final;
- void transmitDtmfTone(const uint32_t &digit) final;
+ void transmitDtmfTone(const uint8_t &digitCode) final;
void muteCall();
void unmuteCall();
void turnLoudspeakerOn();
M module-apps/application-call/test/mock/CallPresenterMocks.hpp => module-apps/application-call/test/mock/CallPresenterMocks.hpp +1 -1
@@ 98,7 98,7 @@ namespace app::call
{
return true;
}
- void transmitDtmfTone(const uint32_t &digit) override{};
+ void transmitDtmfTone(const uint8_t &digitCode) override{};
void muteCall() override{};
void unmuteCall() override{};
void turnLoudspeakerOn() override{};
M module-bluetooth/Bluetooth/interface/profiles/HFP/HFP.cpp => module-bluetooth/Bluetooth/interface/profiles/HFP/HFP.cpp +6 -1
@@ 319,7 319,12 @@ namespace bluetooth
case HFP_SUBEVENT_TRANSMIT_DTMF_CODES: {
auto digitStr = hfp_subevent_transmit_dtmf_codes_get_dtmf(event);
LOG_DEBUG("Send DTMF Codes: '%s'\n", digitStr);
- cellularInterface->sendDTMFCode(const_cast<sys::Service *>(ownerService), utils::toNumeric(digitStr));
+ try {
+ cellularInterface->sendDTMFCode(const_cast<sys::Service *>(ownerService), DTMFCode(digitStr));
+ }
+ catch (std::out_of_range &e) {
+ LOG_ERROR("Can't send DTMF code for digit: %s", digitStr);
+ }
hfp_ag_send_dtmf_code_done(aclHandle);
} break;
case HFP_SUBEVENT_CALL_ANSWERED:
M module-bluetooth/Bluetooth/interface/profiles/PhoneInterface.cpp => module-bluetooth/Bluetooth/interface/profiles/PhoneInterface.cpp +2 -2
@@ 16,9 16,9 @@ namespace bluetooth
{
return CellularServiceAPI::HangupCall(service);
}
- bool CellularInterfaceImpl::sendDTMFCode(sys::Service *service, uint32_t digit)
+ bool CellularInterfaceImpl::sendDTMFCode(sys::Service *service, DTMFCode code)
{
- auto msg = std::make_shared<CellularDtmfRequestMessage>(digit);
+ auto msg = std::make_shared<CellularDtmfRequestMessage>(code);
service->bus.sendUnicast(std::move(msg), service::name::cellular);
return true;
}
M module-bluetooth/Bluetooth/interface/profiles/PhoneInterface.hpp => module-bluetooth/Bluetooth/interface/profiles/PhoneInterface.hpp +3 -2
@@ 4,6 4,7 @@
#pragma once
#include <Service/ServiceForward.hpp>
+#include <module-services/service-cellular/DTMFCode.hpp>
namespace bluetooth
{
@@ 13,7 14,7 @@ namespace bluetooth
virtual ~CellularInterface() = default;
virtual bool answerIncomingCall(sys::Service *service) = 0;
virtual bool hangupCall(sys::Service *service) = 0;
- virtual bool sendDTMFCode(sys::Service *service, uint32_t digit) = 0;
+ virtual bool sendDTMFCode(sys::Service *service, DTMFCode code) = 0;
virtual bool dialNumber(sys::Service *service, const std::string &number) = 0;
};
@@ 23,7 24,7 @@ namespace bluetooth
bool answerIncomingCall(sys::Service *service) override;
bool hangupCall(sys::Service *service) override;
bool dialNumber(sys::Service *service, const std::string &number) override;
- bool sendDTMFCode(sys::Service *service, uint32_t digit) override;
+ bool sendDTMFCode(sys::Service *service, DTMFCode code) override;
};
class AudioInterface
M module-services/service-cellular/CMakeLists.txt => module-services/service-cellular/CMakeLists.txt +1 -0
@@ 14,6 14,7 @@ set(SOURCES
src/ModemResetHandler.cpp
src/URCCounter.cpp
src/CSQHandler.cpp
+ DTMFCode.cpp
CellularServiceAPI.cpp
CellularUrcHandler.cpp
M module-services/service-cellular/CellularServiceAPI.cpp => module-services/service-cellular/CellularServiceAPI.cpp +3 -3
@@ 1,4 1,4 @@
-// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
#include "service-cellular/CellularMessage.hpp"
@@ 258,9 258,9 @@ bool CellularServiceAPI::GetAntenna(sys::Service *serv, bsp::cellular::antenna &
return false;
}
-bool CellularServiceAPI::TransmitDtmfTones(sys::Service *serv, uint32_t digit)
+bool CellularServiceAPI::TransmitDtmfTones(sys::Service *serv, DTMFCode code)
{
- auto msg = std::make_shared<CellularDtmfRequestMessage>(digit);
+ auto msg = std::make_shared<CellularDtmfRequestMessage>(code);
return serv->bus.sendUnicast(msg, ServiceCellular::serviceName);
}
A module-services/service-cellular/DTMFCode.cpp => module-services/service-cellular/DTMFCode.cpp +46 -0
@@ 0,0 1,46 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include "DTMFCode.hpp"
+#include <Utils.hpp>
+#include <stdexcept>
+
+DTMFCode::DTMFCode(const char digitChar)
+{
+ if ((digitChar >= '0' && digitChar <= '9') || digitChar == '*' || digitChar == '#') {
+ this->digitChar = digitChar;
+ }
+ else {
+ this->digitChar = 0;
+ throw std::out_of_range("DTMF: Invalid number!");
+ }
+}
+DTMFCode::DTMFCode(const char *digitStr)
+{
+ auto digitTmpString = std::string{digitStr};
+ if (digitTmpString == "*" || digitTmpString == "#") {
+ digitChar = digitTmpString[0];
+ }
+ else {
+ try {
+ auto digit = std::stoi(digitTmpString);
+ if (digit > 9) {
+ throw std::out_of_range("DTMF: Invalid number!");
+ }
+ digitChar = digit + '0';
+ }
+ catch (std::invalid_argument &e) {
+ LOG_ERROR("Can't parse digit string to DTMF ASCII code");
+ digitChar = 0;
+ throw std::out_of_range("DTMF: Invalid number!");
+ }
+ }
+}
+auto DTMFCode::getDigitASCIICode() const -> char
+{
+ return digitChar;
+}
+DTMFCode::operator std::string() const
+{
+ return "\"" + std::string(1, getDigitASCIICode()) + "\"";
+}
A module-services/service-cellular/DTMFCode.hpp => module-services/service-cellular/DTMFCode.hpp +24 -0
@@ 0,0 1,24 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#pragma once
+#include <stdint.h>
+#include <string>
+
+class DTMFCode
+{
+ public:
+ /// \brief Creates a DTMFCode instance via passing a digit character (its ASCII code)
+ /// \param digitChar - digit's ASCII code
+ explicit DTMFCode(char digitChar);
+
+ /// \brief Creates a DTMFCode instance via passing a digit C-string
+ /// \param digitChar - C-string containing code's digit
+ explicit DTMFCode(const char *digitString);
+
+ [[nodiscard]] auto getDigitASCIICode() const -> char;
+ operator std::string() const;
+
+ private:
+ char digitChar;
+};
M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +4 -5
@@ 1468,17 1468,16 @@ std::string ServiceCellular::GetScanMode(void)
return {};
}
-bool ServiceCellular::transmitDtmfTone(uint32_t digit)
+bool ServiceCellular::transmitDtmfTone(DTMFCode code)
{
auto channel = cmux->get(CellularMux::Channel::Commands);
at::Result resp;
if (channel) {
auto command = at::factory(at::AT::QLDTMF);
- std::string dtmfString = "\"" + utils::singleDigitToString(digit) + "\"";
- resp = channel->cmd(command.getCmd() + dtmfString);
+ resp = channel->cmd(command.getCmd() + std::string(code));
if (resp) {
command = at::factory(at::AT::VTS);
- resp = channel->cmd(command.getCmd() + dtmfString);
+ resp = channel->cmd(command.getCmd() + std::string(code));
}
}
return resp.code == at::Result::Code::OK;
@@ 2105,7 2104,7 @@ auto ServiceCellular::handleCellularGetAntennaMessage(sys::Message *msg) -> std:
auto ServiceCellular::handleCellularDtmfRequestMessage(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>
{
auto message = static_cast<CellularDtmfRequestMessage *>(msg);
- auto resp = transmitDtmfTone(message->getDigit());
+ auto resp = transmitDtmfTone(message->getDTMFCode());
return std::make_shared<CellularResponseMessage>(resp);
}
auto ServiceCellular::handleCellularUSSDMessage(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>
M module-services/service-cellular/service-cellular/CellularMessage.hpp => module-services/service-cellular/service-cellular/CellularMessage.hpp +5 -4
@@ 25,6 25,7 @@
#include <service-appmgr/data/CallActionsParams.hpp>
#include <service-cellular/api/common.hpp>
+#include <DTMFCode.hpp>
class CellularMessage : public sys::DataMessage
{
@@ 307,15 308,15 @@ class CellularRequestMessage : public CellularMessage
class CellularDtmfRequestMessage : public CellularMessage
{
- uint32_t digit = 0;
+ DTMFCode code;
public:
- CellularDtmfRequestMessage(uint32_t digit) : CellularMessage(Type::TransmitDtmfTones), digit(digit)
+ CellularDtmfRequestMessage(DTMFCode code) : CellularMessage(Type::TransmitDtmfTones), code(code)
{}
- uint32_t getDigit() const
+ DTMFCode getDTMFCode() const
{
- return digit;
+ return code;
}
};
M module-services/service-cellular/service-cellular/CellularServiceAPI.hpp => module-services/service-cellular/service-cellular/CellularServiceAPI.hpp +7 -2
@@ 13,6 13,7 @@
#include <cstdint>
#include <string>
+#include <module-services/service-cellular/DTMFCode.hpp>
class Service;
namespace sys
@@ 88,8 89,12 @@ namespace CellularServiceAPI
bool GetCREG(sys::Service *serv, std::string &response);
bool GetQNWINFO(sys::Service *serv, std::string &response);
bool GetAntenna(sys::Service *serv, bsp::cellular::antenna &response);
-
- bool TransmitDtmfTones(sys::Service *serv, uint32_t digit);
+ /**
+ * @brief Transmits DTMF tone
+ * @param serv
+ * @param code - DTMF code to be sent
+ */
+ bool TransmitDtmfTones(sys::Service *serv, DTMFCode code);
bool USSDRequest(sys::Service *serv, CellularUSSDMessage::RequestType type, std::string data = "");
M module-services/service-cellular/service-cellular/ServiceCellular.hpp => module-services/service-cellular/service-cellular/ServiceCellular.hpp +2 -1
@@ 27,6 27,7 @@
#include <PhoneModes/Observer.hpp>
#include <service-db/DBServiceName.hpp>
#include <service-db/DBNotificationMessage.hpp>
+#include <DTMFCode.hpp>
#include <optional> // for optional
#include <memory> // for unique_ptr, allocator, make_unique, shared_ptr
@@ 203,7 204,7 @@ class ServiceCellular : public sys::Service
[[nodiscard]] bool receiveAllMessages();
/// @}
- bool transmitDtmfTone(uint32_t digit);
+ bool transmitDtmfTone(DTMFCode digit);
/// Handle message CellularGetChannelMessage
void handle_CellularGetChannelMessage();
M module-services/service-cellular/tests/CMakeLists.txt => module-services/service-cellular/tests/CMakeLists.txt +8 -0
@@ 75,3 75,11 @@ add_catch2_executable(
LIBS
module-cellular
)
+add_catch2_executable(
+ NAME
+ DTMFCode
+ SRCS
+ unittest_DTMFCode.cpp
+ LIBS
+ module-cellular
+)
A module-services/service-cellular/tests/unittest_DTMFCode.cpp => module-services/service-cellular/tests/unittest_DTMFCode.cpp +79 -0
@@ 0,0 1,79 @@
+// Copyright (c) 2017-2022, Mudita Sp. z.o.o. All rights reserved.
+// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md
+
+#include <catch2/catch.hpp>
+#include "DTMFCode.hpp"
+
+TEST_CASE("DTMFCode")
+{
+ SECTION("Parse from char")
+ {
+ auto code = DTMFCode('0');
+ REQUIRE(code.getDigitASCIICode() == '0');
+ REQUIRE(std::string(code) == "\"0\"");
+ }
+ SECTION("Parse from char 2")
+ {
+ auto code = DTMFCode('9');
+ REQUIRE(code.getDigitASCIICode() == '9');
+ REQUIRE(std::string(code) == "\"9\"");
+ }
+ SECTION("Parse from char 3")
+ {
+ auto code = DTMFCode('*');
+ REQUIRE(code.getDigitASCIICode() == '*');
+ REQUIRE(std::string(code) == "\"*\"");
+ }
+ SECTION("Parse from char 4")
+ {
+ auto code = DTMFCode('#');
+ REQUIRE(code.getDigitASCIICode() == '#');
+ REQUIRE(std::string(code) == "\"#\"");
+ }
+
+ SECTION("Parse from string")
+ {
+ auto code = DTMFCode("0");
+ REQUIRE(code.getDigitASCIICode() == '0');
+ REQUIRE(std::string(code) == "\"0\"");
+ }
+ SECTION("Parse from string 2")
+ {
+ auto code = DTMFCode("9");
+ REQUIRE(code.getDigitASCIICode() == '9');
+ REQUIRE(std::string(code) == "\"9\"");
+ }
+ SECTION("Parse from string 3")
+ {
+ auto code = DTMFCode("*");
+ REQUIRE(code.getDigitASCIICode() == '*');
+ REQUIRE(std::string(code) == "\"*\"");
+ }
+ SECTION("Parse from string 4")
+ {
+ auto code = DTMFCode("#");
+ REQUIRE(code.getDigitASCIICode() == '#');
+ REQUIRE(std::string(code) == "\"#\"");
+ }
+
+ SECTION("Parse from char - incorrect input")
+ {
+ REQUIRE_THROWS_AS(DTMFCode('a'), std::out_of_range);
+ }
+ SECTION("Parse from char - incorrect input 2")
+ {
+ REQUIRE_THROWS_AS(DTMFCode('!'), std::out_of_range);
+ }
+ SECTION("Parse from string - incorrect input 1")
+ {
+ REQUIRE_THROWS_AS(DTMFCode("a"), std::out_of_range);
+ }
+ SECTION("Parse from string - incorrect input 2")
+ {
+ REQUIRE_THROWS_AS(DTMFCode("!"), std::out_of_range);
+ }
+ SECTION("Parse from string - incorrect input 3")
+ {
+ REQUIRE_THROWS_AS(DTMFCode("12"), std::out_of_range);
+ }
+}
M module-utils/utility/Utils.hpp => module-utils/utility/Utils.hpp +0 -20
@@ 23,26 23,6 @@ namespace utils
std::string bytesToHex(const std::vector<std::uint8_t> &bytes);
std::vector<std::uint8_t> hexToBytes(const std::string &hex);
- template <typename T> inline char singleDigitToChar(T digit)
- {
- static_assert(std::is_integral<T>::value, "Integral number required.");
-
- if (digit > 9 || digit < 0) {
- return '\0';
- }
- // converting digit to ASCII code
- return static_cast<char>(digit + '0');
- }
-
- template <typename T> inline std::string singleDigitToString(T digit)
- {
- auto charDigit = singleDigitToChar(digit);
- if (charDigit == '\0') {
- return std::string();
- }
- return std::string(1, charDigit);
- }
-
template <typename T> std::string numToHex(T c)
{
std::stringstream s;
M module-utils/utility/tests/unittest_utils.cpp => module-utils/utility/tests/unittest_utils.cpp +0 -35
@@ 446,38 446,3 @@ TEST_CASE("Generate random Id")
REQUIRE((ret.size() == expectedSize));
}
}
-
-TEST_CASE("singleDigitToString test")
-{
-
- SECTION("proper input")
- {
- uint8_t digit = 5;
- auto str = utils::singleDigitToString(digit);
- REQUIRE(str == "5");
- }
- SECTION("proper input 2")
- {
- int digit = 9;
- auto str = utils::singleDigitToString(digit);
- REQUIRE(str == "9");
- }
- SECTION("improper input - not a single digit")
- {
- int digit = 15;
- auto str = utils::singleDigitToString(digit);
- REQUIRE(str.empty());
- }
- SECTION("improper input - negative number")
- {
- int digit = -10;
- auto str = utils::singleDigitToString(digit);
- REQUIRE(str.empty());
- }
- SECTION("improper input - not an integer-related type")
- {
- char digit = '6';
- auto str = utils::singleDigitToString(digit);
- REQUIRE(str.empty());
- }
-}