~aleteoryx/muditaos

c88c82ae86917cad91f41aa7a0af1224a4b1b5ad — Maciej Janicki 5 years ago afa71c7
[EGD-6319] Refactor cellular modem directory

- Removed not used files from old implementations.
- Renamed some classes to follow naming convention.
- Renamed methods to use consistent styling.
- Restructured code.
109 files changed, 689 insertions(+), 2090 deletions(-)

M module-bsp/board/linux/cellular/linux_cellular.cpp
M module-bsp/board/linux/cellular/linux_cellular.hpp
M module-cellular/CMakeLists.txt
D module-cellular/Modem/TS0710/TS0710_CLOSE.cpp
D module-cellular/Modem/TS0710/TS0710_CLOSE.h
D module-cellular/Modem/TS0710/TS0710_CONTROL.cpp
D module-cellular/Modem/TS0710/TS0710_CONTROL.h
D module-cellular/Modem/TS0710/TS0710_DLC_ESTABL.cpp
D module-cellular/Modem/TS0710/TS0710_DLC_ESTABL.h
D module-cellular/Modem/TS0710/TS0710_DLC_RELEASE.cpp
D module-cellular/Modem/TS0710/TS0710_DLC_RELEASE.h
D module-cellular/Modem/TS0710/TS0710_FLOW.cpp
D module-cellular/Modem/TS0710/TS0710_FLOW.h
D module-cellular/Modem/TS0710/TS0710_PARNEG.cpp
D module-cellular/Modem/TS0710/TS0710_PARNEG.h
D module-cellular/Modem/TS0710/TS0710_PORTNEG.cpp
D module-cellular/Modem/TS0710/TS0710_PORTNEG.h
D module-cellular/Modem/TS0710/TS0710_SERVNEG.cpp
D module-cellular/Modem/TS0710/TS0710_SERVNEG.h
D module-cellular/Modem/TS0710/TS0710_SLEEP.cpp
D module-cellular/Modem/TS0710/TS0710_SLEEP.h
D module-cellular/Modem/TS0710/TS0710_START.cpp
D module-cellular/Modem/TS0710/TS0710_START.h
D module-cellular/Modem/TS0710/TS0710_TEST.cpp
D module-cellular/Modem/TS0710/TS0710_TEST.h
D module-cellular/Modem/TS0710/TS0710_WAKEUP.cpp
D module-cellular/Modem/TS0710/TS0710_WAKEUP.h
D module-cellular/Modem/TS0710/tests/test-TS0710_CLOSE.cpp
D module-cellular/Modem/TS0710/tests/test-TS0710_CONTROL.cpp
D module-cellular/Modem/TS0710/tests/test-TS0710_DLC_RELEASE.cpp
D module-cellular/Modem/TS0710/tests/test-TS0710_FLOW.cpp
D module-cellular/Modem/TS0710/tests/test-TS0710_PARNEG.cpp
D module-cellular/Modem/TS0710/tests/test-TS0710_PORTNEG.cpp
D module-cellular/Modem/TS0710/tests/test-TS0710_SERVNEG.cpp
D module-cellular/Modem/TS0710/tests/test-TS0710_SLEEP.cpp
D module-cellular/Modem/TS0710/tests/test-TS0710_TEST.cpp
D module-cellular/Modem/TS0710/tests/test-TS0710_WAKEUP.cpp
R module-cellular/{Modem => modem}/ATCommon.cpp
R module-cellular/{Modem => modem}/ATCommon.hpp
R module-cellular/{Modem => modem}/ATParser.cpp
R module-cellular/{Modem => modem}/ATParser.hpp
R module-cellular/{Modem => modem}/ATStream.cpp
R module-cellular/{Modem => modem}/ATStream.hpp
R module-cellular/{Modem => modem}/ATURCStream.cpp
R module-cellular/{Modem => modem}/ATURCStream.hpp
R module-cellular/{Modem => modem}/BaseChannel.hpp
R module-cellular/{Modem => modem}/README.md
R module-cellular/{Modem => modem}/doc/ATStream.md
R module-cellular/{Modem => modem}/doc/Images/at_mode.svg
R module-cellular/{Modem => modem}/doc/Images/at_mode.uml
R module-cellular/{Modem => modem}/doc/Images/atstream.png
R module-cellular/{Modem => modem}/doc/Images/cellular_mux_read.png
R module-cellular/{Modem => modem}/doc/Images/cellular_result_struct.png
R module-cellular/{Modem => modem}/doc/Images/cellular_result_struct.uml
R module-cellular/{Modem => modem}/doc/Images/class_channel.png
R module-cellular/{Modem => modem}/doc/Images/cmx_mode.uml
R module-cellular/{Modem => modem}/doc/Images/current_volte_on.png
R module-cellular/{Modem => modem}/doc/Images/dma_result_struct.png
R module-cellular/{Modem => modem}/doc/Images/dma_result_struct.uml
R module-cellular/{Modem => modem}/doc/Images/mudita_logo.png
R module-cellular/{Modem => modem}/doc/Images/mux_mode.svg
R module-cellular/{Modem => modem}/doc/Images/single_cmd.uml
R module-cellular/{Modem => modem}/doc/Images/single_cmd_transmission.png
R module-cellular/{Modem => modem}/doc/Images/volte_on.png
R module-cellular/{Modem => modem}/doc/scripts/atstream.pu
R module-cellular/{Modem => modem}/doc/scripts/class_channel.pu
R module-cellular/{Modem/TS0710/TS0710 => modem/mux/CellularMux}.cpp
R module-cellular/{Modem/TS0710/TS0710 => modem/mux/CellularMux}.h
R module-cellular/{Modem/TS0710/TS0710_DATA => modem/mux/CellularMuxData}.cpp
R module-cellular/{Modem/TS0710/TS0710_DATA => modem/mux/CellularMuxData}.h
R module-cellular/{Modem/TS0710/TS0710_Frame => modem/mux/CellularMuxFrame}.h
R module-cellular/{Modem/TS0710/TS0710_types => modem/mux/CellularMuxTypes}.h
R module-cellular/{Modem/TS0710/DLC_channel => modem/mux/DLCChannel}.cpp
R module-cellular/{Modem/TS0710/DLC_channel => modem/mux/DLCChannel}.h
A module-cellular/modem/mux/MuxParameters.hpp
R module-cellular/{Modem/TS0710/tests/test-DLC_channel => modem/mux/tests/test-DLCChannel}.cpp
R module-cellular/{Modem/TS0710 => modem/mux}/tests/test-TS0710.cpp
R module-cellular/{Modem/TS0710 => modem/mux}/tests/test-TS0710_DATA.cpp
R module-cellular/{Modem/TS0710 => modem/mux}/tests/test-TS0710_DLC_ESTABL.cpp
R module-cellular/{Modem/TS0710 => modem/mux}/tests/test-TS0710_START.cpp
M module-cellular/test/mock/AtCommon_channel.hpp
M module-cellular/test/unittest_ATStream.cpp
M module-cellular/test/unittest_ATURCStream.cpp
M module-cellular/test/unittest_CellularResult.cpp
M module-cellular/test/unittest_URC.cpp
M module-cellular/test/unittest_cmux.cpp
M module-services/service-cellular/CellularServiceAPI.cpp
M module-services/service-cellular/CellularUrcHandler.cpp
M module-services/service-cellular/NetworkSettings.cpp
M module-services/service-cellular/PacketData.cpp
M module-services/service-cellular/PacketData.hpp
M module-services/service-cellular/QMBNManager.hpp
M module-services/service-cellular/ServiceCellular.cpp
M module-services/service-cellular/SimCard.cpp
M module-services/service-cellular/checkSmsCenter.cpp
M module-services/service-cellular/connection-manager/ConnectionManagerCellularCommands.cpp
M module-services/service-cellular/doc/call_request_handling.puml
M module-services/service-cellular/doc/call_request_handling.svg
M module-services/service-cellular/handler/RawATHandler.cpp
M module-services/service-cellular/service-cellular/CellularMessage.hpp
M module-services/service-cellular/service-cellular/CellularServiceAPI.hpp
M module-services/service-cellular/service-cellular/RequestFactory.hpp
M module-services/service-cellular/service-cellular/ServiceCellular.hpp
M module-services/service-cellular/tests/CMakeLists.txt
M module-services/service-cellular/tests/unittest_datatransfer.cpp
M module-services/service-cellular/tests/unittest_simcard.cpp
M module-services/service-fota/ServiceFota.cpp
M module-services/service-fota/service-fota/ServiceFota.hpp
M module-utils/log/Logger.cpp
M module-bsp/board/linux/cellular/linux_cellular.cpp => module-bsp/board/linux/cellular/linux_cellular.cpp +2 -2
@@ 156,8 156,8 @@ namespace bsp
        auto timeoutTicks = pdMS_TO_TICKS(timeoutMs.count());

        uint32_t currentTime   = cpp_freertos::Ticks::GetTicks();
        uint32_t timeoutNeeded = currentTime + timeoutTicks;
        uint32_t timeElapsed   = currentTime;
        uint64_t timeoutNeeded = currentTime + timeoutTicks;
        uint64_t timeElapsed   = currentTime;

        for (;;) {
            if (timeElapsed >= timeoutNeeded) {

M module-bsp/board/linux/cellular/linux_cellular.hpp => module-bsp/board/linux/cellular/linux_cellular.hpp +2 -10
@@ 8,9 8,9 @@

#include <cstring>
#include <sys/epoll.h>
#include "termios.h"
#include <termios.h>
#include <sys/ioctl.h>
#include "mutex.hpp"
#include <mutex.hpp>

namespace bsp
{


@@ 24,25 24,18 @@ namespace bsp
        ~LinuxCellular();

        void powerUp() override final;

        void powerDown() override final;

        void restart() override final;

        uint32_t wait(std::chrono::milliseconds timeoutMs) override final;

        ssize_t read(void *buf, size_t nbytes, std::chrono::milliseconds timeoutMs) override final;

        ssize_t write(void *buf, size_t nbytes) override final;

        void informModemHostAsleep() override final;

        void informModemHostWakeup() override final;

        void enterSleep() override final;

        void exitSleep() override final;

        void setSpeed(uint32_t portSpeed) override final;

        void setSendingAllowed(bool state) override final


@@ 55,7 48,6 @@ namespace bsp
        }

        void selectAntenna(bsp::cellular::antenna antenna) override final;

        bsp::cellular::antenna getAntenna() override final;

      private:

M module-cellular/CMakeLists.txt => module-cellular/CMakeLists.txt +7 -19
@@ 8,25 8,13 @@ include(SerialPort)
module_is_test_entity()

set(SOURCES
        ${CMAKE_CURRENT_SOURCE_DIR}/Modem/ATParser.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/Modem/ATStream.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/Modem/ATURCStream.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/Modem/ATCommon.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/Modem/TS0710/DLC_channel.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/Modem/TS0710/TS0710.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/Modem/TS0710/TS0710_CLOSE.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/Modem/TS0710/TS0710_CONTROL.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/Modem/TS0710/TS0710_DATA.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/Modem/TS0710/TS0710_DLC_ESTABL.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/Modem/TS0710/TS0710_DLC_RELEASE.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/Modem/TS0710/TS0710_FLOW.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/Modem/TS0710/TS0710_PARNEG.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/Modem/TS0710/TS0710_PORTNEG.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/Modem/TS0710/TS0710_SERVNEG.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/Modem/TS0710/TS0710_SLEEP.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/Modem/TS0710/TS0710_START.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/Modem/TS0710/TS0710_TEST.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/Modem/TS0710/TS0710_WAKEUP.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/modem/ATParser.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/modem/ATStream.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/modem/ATURCStream.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/modem/ATCommon.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/modem/mux/DLCChannel.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/modem/mux/CellularMux.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/modem/mux/CellularMuxData.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/at/src/Urc.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcQind.cpp
        ${CMAKE_CURRENT_SOURCE_DIR}/at/src/UrcCusd.cpp

D module-cellular/Modem/TS0710/TS0710_CLOSE.cpp => module-cellular/Modem/TS0710/TS0710_CLOSE.cpp +0 -18
@@ 1,18 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**
 * Project Untitled
 */

#include "TS0710_CLOSE.h"

/**
 * TS0710_CLOSE implementation
 */

void TS0710_CLOSE::request()
{}

void TS0710_CLOSE::indication()
{}
\ No newline at end of file

D module-cellular/Modem/TS0710/TS0710_CLOSE.h => module-cellular/Modem/TS0710/TS0710_CLOSE.h +0 -30
@@ 1,30 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**
 * Project Untitled
 * @brief When the request primitive is passed to the TS 0710 layer of the transmitting device close down of the
 * multiplexer mode is initiated and a close down command is sent to the receiving device. On reception of the close
 * down command the TS 0710 layer of the receiving device sends the indication primitive to the upper layer and the
 * multiplexer mode is terminated.
 */

#ifndef _TS0710_CLOSE_H
#define _TS0710_CLOSE_H

// control channel - Multiplexer close down (CLD)
class TS0710_CLOSE
{
  public:
    TS0710_CLOSE()
    {}
    ~TS0710_CLOSE()
    {}

  private:
    void request();

    void indication();
};

#endif //_TS0710_CLOSE_H
\ No newline at end of file

D module-cellular/Modem/TS0710/TS0710_CONTROL.cpp => module-cellular/Modem/TS0710/TS0710_CONTROL.cpp +0 -40
@@ 1,40 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**
 * Project Untitled
 */

#include "TS0710_CONTROL.h"

/**
 * TS0710_CONTROL implementation
 */

/**
 * @param DLC
 * @param Control_parameters
 */
void TS0710_CONTROL::request(DLCI_t DLC, ControlParameters_t Control_parameters)
{}

/**
 * @param DLC
 * @param Control_parameters
 */
void TS0710_CONTROL::indication(DLCI_t DLC, ControlParameters_t Control_parameters)
{}

/**
 * @param DLC
 * @param Control_parameters
 */
void TS0710_CONTROL::response(DLCI_t DLC, ControlParameters_t Control_parameters)
{}

/**
 * @param DLC
 * @param Control_parameters
 */
void TS0710_CONTROL::confirm(DLCI_t DLC, ControlParameters_t Control_parameters)
{}
\ No newline at end of file

D module-cellular/Modem/TS0710/TS0710_CONTROL.h => module-cellular/Modem/TS0710/TS0710_CONTROL.h +0 -88
@@ 1,88 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**
 * Project Untitled
 * @brief The request primitive is used to convey control information to the remote port. The indication is sent to
 * the other port emulation entity. The remote port emulation entity replies with a response which is sent to the
 * originating 07.10 entity. A confirm is sent back to the port emulation entity.
 */

#ifndef _TS0710_CONTROL_H
#define _TS0710_CONTROL_H

#include "TS0710_PARNEG.h"
#include "TS0710_SERVNEG.h"
#include "TS0710_PORTNEG.h"
#include "TS0710_CONTROL.h"

// control channel - Modem Status Command (MSC)

class TS0710_CONTROL
{
  private:
    TS0710_PARNEG *parneg;   // control channel - DLC parameter negotiation (PN)
    TS0710_SERVNEG *servneg; // control channel - Service Negotiation Command (SNC)
    TS0710_PORTNEG *portneg; // control channel - Remote Port Negotiation Command (RPN)
                             // control channel - Remote Line Status Command(RLS)
    TS0710_CONTROL *control; // control channel - Modem Status Command (MSC)

  public:
    enum ModemSignal_e
    {
        DTR_DSR,
        RTS_CTS,
        RI,
        DCD
    };
    enum Buffers_e
    {
        DNDiscard,
        Discard
    };
    enum BreakSigSeq_e
    {
        ASAP,
        INSEQ
    };

    struct ControlParameters_t
    {
        ModemSignal_e ModemSignal; //!< Modem Signal [DTR/DSR | RTS/CTS | RI | DCD ]
        int BreakSignal;           //!< Break Signal [0—3 s in steps of 200 ms, default 0ms ]
        Buffers_e Buffers;         //!< Buffers [do not discard buffers, discard buffer default: do not discard buffers]
        BreakSigSeq_e BreakSigSeq; //!< Break signal sequence [ as soon as possible | in sequence, default: in sequence]
    };

    TS0710_CONTROL()
    {}
    ~TS0710_CONTROL()
    {}

  private:
    /**
     * @param DLC
     * @param Control_parameters
     */
    void request(DLCI_t DLC, ControlParameters_t Control_parameters);

    /**
     * @param DLC
     * @param Control_parameters
     */
    void indication(DLCI_t DLC, ControlParameters_t Control_parameters);

    /**
     * @param DLC
     * @param Control_parameters
     */
    void response(DLCI_t DLC, ControlParameters_t Control_parameters);

    /**
     * @param DLC
     * @param Control_parameters
     */
    void confirm(DLCI_t DLC, ControlParameters_t Control_parameters);
};

#endif //_TS0710_CONTROL_H
\ No newline at end of file

D module-cellular/Modem/TS0710/TS0710_DLC_ESTABL.cpp => module-cellular/Modem/TS0710/TS0710_DLC_ESTABL.cpp +0 -147
@@ 1,147 0,0 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**
 * Project Untitled
 */

#include "TS0710_DLC_ESTABL.h"

#if defined(__cplusplus)
extern "C"
{
#endif
//#include "uart.h"
#if defined(__cplusplus)
}
#endif

#include "TS0710_Frame.h"
#include "TS0710_types.h"
#include "log/log.hpp"
#include "FreeRTOS.h"

#include <bsp/cellular/CellularResult.hpp>

/**
 * TS0710_DLC_ESTABL implementation
 */
TS0710_DLC_ESTABL::TS0710_DLC_ESTABL(DLCI_t DLCI, bsp::Cellular *cellular)
{
    DLC_ESTABL_SystemParameters_t system_parameters;
    system_parameters.TypeOfFrame             = TypeOfFrame_e::UIH;
    system_parameters.ConvergenceLayer        = 1;
    system_parameters.Priority                = 1;
    system_parameters.AckTime                 = 100; // 100ms default
    system_parameters.MaxFrameSize            = 128;
    system_parameters.MaxNumOfRetransmissions = 3; // default 3
    system_parameters.ErrRecovWindowSize      = 2; // default 2

    pv_DLCI             = DLCI;
    pv_SystemParameters = system_parameters;

    pv_cellular = cellular;

    active = request(DLCI, system_parameters);
}

/**
 * @param DLCI
 * @param system_parameters
 */
bool TS0710_DLC_ESTABL::request(DLCI_t DLCI, DLC_ESTABL_SystemParameters_t system_parameters)
{
    /*
    TE requests to establish control channel DLCI 0 by SABM frame
        TE→MS   F9 03 3F 01 1C F9     SABM Frame
    MS feeds back UA for receiving SABM and accepts to create DLCI 0
        TE←MS   F9 03 73 01 D7 F9     UA Frame
    */

    /*
    [send data]
         |<--------------
         V              |
     -(is resp.)-       |
     |T        F|       |
     |     -(is t-out)- |
     |     |T        F|-|
     |     |
     |     V
     V {no resp.}
   {resp.}
    */

    /* data flow :
      TX: (data) -> queue[i] -> [ass. frame] -> [send to UART - mutex protected]
          - frame type depends of data source - control/data[dlci]
      RX: [receive from UART] -> [analyze frame] -> queue[i] -> (data)
          - data sent to different queues - control/data[dlci]
    */
    LOG_DEBUG("Sending %s frame to DLCI %i", TypeOfFrame_text[system_parameters.TypeOfFrame].c_str(), DLCI);
    TS0710_Frame::frame_t frame;
    frame.Address = static_cast<uint8_t>(DLCI << 2) | (1 << 1); // set C/R = 1 - command
    frame.Control = static_cast<uint8_t>(system_parameters.TypeOfFrame);
    TS0710_Frame frame_c(frame);
    pv_cellular->write(static_cast<void *>(frame_c.getSerData().data()), frame_c.getSerData().size());
    // return true;
    int retries = system_parameters.MaxNumOfRetransmissions;
    while (retries--) {
        // UartSend(frame_c.getSerData().data(), frame_c.getSerData().size());
        pv_cellular->write(static_cast<void *>(frame_c.getSerData().data()), frame_c.getSerData().size());
        vTaskDelay(system_parameters.AckTime);
        if (response(DLCI, system_parameters)) {
            LOG_DEBUG("Got response");
            return true;
        }
    }

    LOG_ERROR("Sending frame failed");
    return false;
}

/**
 * @param DLCI
 * @param system_parameters
 */
void TS0710_DLC_ESTABL::indication(DLCI_t DLCI, DLC_ESTABL_SystemParameters_t system_parameters)
{}

/**
 * @param DLCI
 * @param system_parameters
 * @param accept
 */
bool TS0710_DLC_ESTABL::response(DLCI_t DLCI, DLC_ESTABL_SystemParameters_t system_parameters)
{
    constexpr size_t size = 256;
    bsp::cellular::CellularDMAResultStruct result{};

    ssize_t len = pv_cellular->read(&result, size, std::chrono::milliseconds{0});
    LOG_DEBUG("RX length = %d", static_cast<int>(len));

    if (len > 0) {
        std::vector<uint8_t> v(result.data, result.data + result.dataSize);
        TS0710_Frame frame_c(v);
        TS0710_Frame::frame_t frame = frame_c.getFrame();

        if (((frame.Address & 0xFC) == (DLCI << 2)) &&
            (frame.Control == (static_cast<uint8_t>(TypeOfFrame_e::UA) & ~(1 << 4)))) {
            LOG_DEBUG("Frame correct");
            return true;
        }
    }

    LOG_DEBUG("ERROR - discarding frame !");
    return false;
}

/**
 * @param DLCI
 * @param system_parameters
 * @param accept
 */
bool TS0710_DLC_ESTABL::confirm(DLCI_t DLCI, DLC_ESTABL_SystemParameters_t system_parameters)
{
    return false;
}

D module-cellular/Modem/TS0710/TS0710_DLC_ESTABL.h => module-cellular/Modem/TS0710/TS0710_DLC_ESTABL.h +0 -77
@@ 1,77 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#ifndef _TS0710_DLC_ESTABL_H
#define _TS0710_DLC_ESTABL_H

#include "TS0710.h"

class TS0710_DLC_ESTABL
{
  public:
    // DLC_ESTABL_SystemParameters passed to Port Negotiation frame in control channel

  private:
    DLC_ESTABL_SystemParameters_t pv_SystemParameters;
    DLCI_t pv_DLCI;
    bool active = false;
    bsp::Cellular *pv_cellular;

  public:
    TS0710_DLC_ESTABL(DLCI_t DLCI, bsp::Cellular *cellular);
    TS0710_DLC_ESTABL(DLCI_t DLCI, DLC_ESTABL_SystemParameters_t system_parameters, bsp::Cellular *cellular)
    {
        pv_DLCI             = DLCI;
        pv_SystemParameters = system_parameters;
        pv_cellular         = cellular;
        active              = request(DLCI, system_parameters);
    };
    ~TS0710_DLC_ESTABL()
    {}

    bool getResponse()
    {
        return active;
    }
    DLC_ESTABL_SystemParameters_t getParams()
    {
        return pv_SystemParameters;
    }

  private:
    /**
     * @param DLCI
     * @param system_parameters
     * @brief The transmitting device uses the request primitive initiate the establishment of a new DLC with a desired
     * set of system parameters on the multiplexer channel.
     */
    bool request(DLCI_t DLCI, DLC_ESTABL_SystemParameters_t system_parameters);

    /**
     * @param DLCI
     * @param system_parameters
     * @brief The indication primitive is passed to the upper layer by the TS 0710 layer of the receiving device on
     * reception of the DLC establishment request.
     */
    void indication(DLCI_t DLCI, DLC_ESTABL_SystemParameters_t system_parameters);

    /**
     * @param DLCI
     * @param system_parameters
     * @return accept
     * @brief The receiving device uses the response primitive to either accept or reject the proposed DLCI with its
     * system parameters.
     */
    bool response(DLCI_t DLCI, DLC_ESTABL_SystemParameters_t system_parameters);

    /**
     * @param DLCI
     * @param system_parameters
     * @return accept
     * @brief The confirm primitive is passed to the upper layer of the transmitting device on reception of the response
     * from the receiving device.
     */
    bool confirm(DLCI_t DLCI, DLC_ESTABL_SystemParameters_t system_parameters);
};

#endif //_TS0710_DLC_ESTABL_H

D module-cellular/Modem/TS0710/TS0710_DLC_RELEASE.cpp => module-cellular/Modem/TS0710/TS0710_DLC_RELEASE.cpp +0 -31
@@ 1,31 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**
 * Project Untitled
 */

#include "TS0710_DLC_RELEASE.h"

/**
 * TS0710_DLC_RELEASE implementation
 */

/**
 * @param DLCI
 */
void TS0710_DLC_RELEASE::request(DLCI_t DLCI)
{
    /*
    TE sends DISC frame to request for closing down DLC 1
        TE→MS  F9 07 53 01 3f F9
    MS feeds back UA frame to accept
        TE←MS  F9 07 73 01 15 F9
    */
}

/**
 * @param DLCI
 */
void TS0710_DLC_RELEASE::indication(DLCI_t DLCI)
{}
\ No newline at end of file

D module-cellular/Modem/TS0710/TS0710_DLC_RELEASE.h => module-cellular/Modem/TS0710/TS0710_DLC_RELEASE.h +0 -38
@@ 1,38 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**
 * Project Untitled
 * @brief The request primitive is used by the upper layer in the transmitting device to initiate close down of the
 * selected DLC in TS 0710. The TS 0710 layer of the receiving device uses the indication primitive to inform the upper
 * layer that the DLC has been closed down.
 */

#ifndef _TS0710_DLC_RELEASE_H
#define _TS0710_DLC_RELEASE_H

#include "TS0710.h"

class TS0710_DLC_RELEASE
{
  public:
    TS0710_DLC_RELEASE(DLCI_t DLCI)
    {
        request(DLCI);
    };
    ~TS0710_DLC_RELEASE()
    {}

  private:
    /**
     * @param DLCI
     */
    void request(DLCI_t DLCI);

    /**
     * @param DLCI
     */
    void indication(DLCI_t DLCI);
};

#endif //_TS0710_DLC_RELEASE_H
\ No newline at end of file

D module-cellular/Modem/TS0710/TS0710_FLOW.cpp => module-cellular/Modem/TS0710/TS0710_FLOW.cpp +0 -26
@@ 1,26 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**
 * Project Untitled
 */

#include "TS0710_FLOW.h"

/**
 * TS0710_FLOW implementation
 */

/**
 * @param DLCI
 * @param State
 */
void TS0710_FLOW::request(DLCI_t DLCI, State_e State)
{}

/**
 * @param DLCI
 * @param State
 */
void TS0710_FLOW::indication(DLCI_t DLCI, State_e State)
{}
\ No newline at end of file

D module-cellular/Modem/TS0710/TS0710_FLOW.h => module-cellular/Modem/TS0710/TS0710_FLOW.h +0 -38
@@ 1,38 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#ifndef _TS0710_FLOW_H
#define _TS0710_FLOW_H

#include "TS0710.h"
// control channel

class TS0710_FLOW
{
  public:
    enum State_e
    {
        enable,
        disable
    };

    TS0710_FLOW()
    {}
    ~TS0710_FLOW()
    {}

  private:
    /**
     * @param DLCI
     * @param State
     */
    void request(DLCI_t DLCI, State_e State);

    /**
     * @param DLCI
     * @param State
     */
    void indication(DLCI_t DLCI, State_e State);
};

#endif //_TS0710_FLOW_H

D module-cellular/Modem/TS0710/TS0710_PARNEG.cpp => module-cellular/Modem/TS0710/TS0710_PARNEG.cpp +0 -42
@@ 1,42 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**
 * Project Untitled
 */

#include "TS0710_PARNEG.h"

/**
 * TS0710_PARNEG implementation
 */

/**
 * @param DLC
 * @param DLC_parameters
 */
void TS0710_PARNEG::request(DLCI_t DLC, DLCParameters_t DLC_parameters)
{}

/**
 * @param DLC
 * @param DLC_parameters
 */
void TS0710_PARNEG::indication(DLCI_t DLC, DLCParameters_t DLC_parameters)
{}

/**
 * @param DLC
 * @param DLC_parameters
 * @param accept
 */
void TS0710_PARNEG::response(DLCI_t DLC, DLCParameters_t DLC_parameters, bool accept)
{}

/**
 * @param DLC
 * @param DLC_parameters
 * @param accept
 */
void TS0710_PARNEG::confirm(DLCI_t DLC, DLCParameters_t DLC_parameters, bool accept)
{}
\ No newline at end of file

D module-cellular/Modem/TS0710/TS0710_PARNEG.h => module-cellular/Modem/TS0710/TS0710_PARNEG.h +0 -67
@@ 1,67 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**
 * Project Untitled
 * @brief The request primitive is used to request that the remote 07.10 entity changes a specific DLC connection
 * parameters. An indication is sent to the remote port emulation entity. The remote emulation entity replies with a
 * response witch is forwarded as an confirmation to the originating port emulating entity.
 */

#ifndef _TS0710_PARNEG_H
#define _TS0710_PARNEG_H

#include "TS0710.h"
// control channel - DLC parameter negotiation (PN)

class TS0710_PARNEG
{
  public:
    struct DLCParameters_t
    {
        TypeOfFrame_e TypeOfFrame; //!< Type of frame [UIH | UI | I, default: UIH]
        int ConvergenceLayer;      //!< Convergence layer [1 - 4, default: 1]
        int Priority;              //!< Priority [0-63], default according to table in subclause 5.6
        int AckTime;               //!< Acknowledgement Timer [10 ms - 25.5 sec, deault: 100 ms]
        int MaxFrameSize; //!< Maximum Frame Size [1 – 32768, default: 31 for the basic option and 64 for the advanced
                          //!< option]
        int MaxNumOfRetransmissions; //!< Maximum number of retransmissions [0 – 100, default : 3]
        int MuxCtrlRespTime;    //!< Response timer for the multiplexor control channel [0,01s-2,55s, default: 0,3s]
        int WakeUpRespTime;     //!< Wake up response timer [1s – 255s, default 10s]
        int ErrRecovWindowSize; //!< Window size for error recovery mode [1 – 7, default : 2]
    };

    TS0710_PARNEG()
    {}
    ~TS0710_PARNEG()
    {}

  private:
    /**
     * @param DLC
     * @param DLC_parameters
     */
    void request(DLCI_t DLC, DLCParameters_t DLC_parameters);

    /**
     * @param DLC
     * @param DLC_parameters
     */
    void indication(DLCI_t DLC, DLCParameters_t DLC_parameters);

    /**
     * @param DLC
     * @param DLC_parameters
     * @param accept
     */
    void response(DLCI_t DLC, DLCParameters_t DLC_parameters, bool accept);

    /**
     * @param DLC
     * @param DLC_parameters
     * @param accept
     */
    void confirm(DLCI_t DLC, DLCParameters_t DLC_parameters, bool accept);
};

#endif //_TS0710_PARNEG_H
\ No newline at end of file

D module-cellular/Modem/TS0710/TS0710_PORTNEG.cpp => module-cellular/Modem/TS0710/TS0710_PORTNEG.cpp +0 -56
@@ 1,56 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**
 * Project Untitled
 */

#include "TS0710_PORTNEG.h"

/**
 * TS0710_PORTNEG implementation
 */

/**
 * @param DLC
 * @param Port_parameters
 */
void TS0710_PORTNEG::request(DLCI_t DLC, PortParameters_t Port_parameters)
{}

/**
 * @param DLC
 * @param Port_parameters
 */
void TS0710_PORTNEG::indication(DLCI_t DLC, PortParameters_t Port_parameters)
{}

/**
 * @param DLC
 * @param Port_parameters
 * @param accept
 */
void TS0710_PORTNEG::response(DLCI_t DLC, PortParameters_t Port_parameters, bool accept)
{}

/**
 * @param DLC
 * @param Port_parameters
 * @param accept
 */
void TS0710_PORTNEG::confirm(DLCI_t DLC, PortParameters_t Port_parameters, bool accept)
{}

/**
 * @param DLC
 * @param LineStatusParameter
 */
void TS0710_PORTNEG::request(DLCI_t DLC, LineStatusParameter_e LineStatusParameter)
{}

/**
 * @param DLC
 * @param LineStatusParameter
 */
void TS0710_PORTNEG::indication(DLCI_t DLC, LineStatusParameter_e LineStatusParameter)
{}
\ No newline at end of file

D module-cellular/Modem/TS0710/TS0710_PORTNEG.h => module-cellular/Modem/TS0710/TS0710_PORTNEG.h +0 -120
@@ 1,120 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**
 * Project Untitled
 * @brief The request primitive is used to request that the remote port changes its parameters. The indication is sent
 * to the other port emulation entity. The remote port emulation entity replies with a response. A confirm is sent to
 * the originating port entity.
 */

#ifndef _TS0710_PORTNEG_H
#define _TS0710_PORTNEG_H

#include "TS0710_types.h"

// control channel - Remote Port Negotiation Command (RPN)
// control channel - Remote Line Status Command(RLS)

class TS0710_PORTNEG
{
  public:
    enum DataBits_e
    {
        DB5,
        DB6,
        DB7,
        DB8
    };
    enum PortSpeed_e
    {
        PS2400,
        PS4800,
        PS7200,
        PS9600,
        PS19200,
        PS38400,
        PS57600,
        PS115200,
        PS230400
    };
    enum Parity_e
    {
        NoParity,
        Parity
    };
    enum ParityType_e
    {
        odd,
        even,
        mark,
        space
    };
    enum StopBits_e
    {
        SB1,
        SB15
    };
    enum LineStatusParameter_e
    {
        NoErrors,
        OverrunErr,
        ParityErr,
        FramingErr
    }; //!< Port speed [no errors, overrun error, parity error, framing error]

    struct PortParameters_t
    {
        PortSpeed_e PortSpeed;
        DataBits_e DataBits;
        StopBits_e StopBits;
        Parity_e Parity;
        ParityType_e ParityType;
    };

    TS0710_PORTNEG()
    {}
    ~TS0710_PORTNEG()
    {}

  private:
    /**
     * @param DLC
     * @param Port_parameters
     */
    void request(DLCI_t DLC, PortParameters_t Port_parameters);

    /**
     * @param DLC
     * @param Port_parameters
     */
    void indication(DLCI_t DLC, PortParameters_t Port_parameters);

    /**
     * @param DLC
     * @param Port_parameters
     * @param accept
     */
    void response(DLCI_t DLC, PortParameters_t Port_parameters, bool accept);

    /**
     * @param DLC
     * @param Port_parameters
     * @param accept
     */
    void confirm(DLCI_t DLC, PortParameters_t Port_parameters, bool accept);

    /**
     * @param DLC
     * @param LineStatusParameter
     */
    void request(DLCI_t DLC, LineStatusParameter_e LineStatusParameter);

    /**
     * @param DLC
     * @param LineStatusParameter
     */
    void indication(DLCI_t DLC, LineStatusParameter_e LineStatusParameter);
};

#endif //_TS0710_PORTNEG_H
\ No newline at end of file

D module-cellular/Modem/TS0710/TS0710_SERVNEG.cpp => module-cellular/Modem/TS0710/TS0710_SERVNEG.cpp +0 -42
@@ 1,42 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**
 * Project Untitled
 */

#include "TS0710_SERVNEG.h"

/**
 * TS0710_SERVNEG implementation
 */

/**
 * @param DLC
 * @param Service_parameters
 */
void TS0710_SERVNEG::request(DLCI_t DLC, ServiceParameters_t Service_parameters)
{}

/**
 * @param DLC
 * @param Service_parameters
 */
void TS0710_SERVNEG::indication(DLCI_t DLC, ServiceParameters_t Service_parameters)
{}

/**
 * @param DLC
 * @param Service_parameters
 * @param accept
 */
void TS0710_SERVNEG::response(DLCI_t DLC, ServiceParameters_t Service_parameters, bool accept)
{}

/**
 * @param DLC
 * @param Service_parameters
 * @param accept
 */
void TS0710_SERVNEG::confirm(DLCI_t DLC, ServiceParameters_t Service_parameters, bool accept)
{}
\ No newline at end of file

D module-cellular/Modem/TS0710/TS0710_SERVNEG.h => module-cellular/Modem/TS0710/TS0710_SERVNEG.h +0 -69
@@ 1,69 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#ifndef _TS0710_SERVNEG_H
#define _TS0710_SERVNEG_H

#include "TS0710_types.h"

// control channel - Service Negotiation Command (SNC)

class TS0710_SERVNEG
{
  public:
    enum Service_e
    {
        data,
        voice,
        reserved1,
        reserved2
    };
    enum VoiceCodec_e
    {
        GSM0621,
        PCM64k,
        ADPCM32k,
        CodedHalfRate,
        PCM128k,
        reserved
    };
    struct ServiceParameters_t
    {
        Service_e Service;
        VoiceCodec_e VoiceCodec;
    };

    TS0710_SERVNEG()
    {}
    ~TS0710_SERVNEG()
    {}

  private:
    /**
     * @param DLC
     * @param Service_parameters
     */
    void request(DLCI_t DLC, ServiceParameters_t Service_parameters);

    /**
     * @param DLC
     * @param Service_parameters
     */
    void indication(DLCI_t DLC, ServiceParameters_t Service_parameters);

    /**
     * @param DLC
     * @param Service_parameters
     * @param accept
     */
    void response(DLCI_t DLC, ServiceParameters_t Service_parameters, bool accept);

    /**
     * @param DLC
     * @param Service_parameters
     * @param accept
     */
    void confirm(DLCI_t DLC, ServiceParameters_t Service_parameters, bool accept);
};

#endif //_TS0710_SERVNEG_H

D module-cellular/Modem/TS0710/TS0710_SLEEP.cpp => module-cellular/Modem/TS0710/TS0710_SLEEP.cpp +0 -21
@@ 1,21 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**
 * Project Untitled
 */

#include "TS0710_SLEEP.h"

/**
 * TS0710_SLEEP implementation
 */

void TS0710_SLEEP::request()
{}

void TS0710_SLEEP::indication()
{}

void TS0710_SLEEP::confirm()
{}
\ No newline at end of file

D module-cellular/Modem/TS0710/TS0710_SLEEP.h => module-cellular/Modem/TS0710/TS0710_SLEEP.h +0 -33
@@ 1,33 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**
 * @brief The request primitive is used to advice the receiving device that the transmitter wishes to enter a low
 * power state. The TS 0710 layer of the receiving unit sends an indication primitive to the upper layer in order to
 * inform that the transmitting unit has entered the power saving state. The TS 0710 layer will automatically transmit
 * an acknowledge message to the transmitting device, thus no response primitive is required. The confirm primitive is
 * sent to the upper layer of the transmitting device when the low power request has been received, and indicates that
 * the TS 0710 layer has entered the low power mode. Note that the Receiving device is not required to enter a low power
 * mode, but it will be considered to have done so by the TS 07.10 layer.
 */

#ifndef _TS0710_SLEEP_H
#define _TS0710_SLEEP_H

class TS0710_SLEEP
{
  public:
    TS0710_SLEEP()
    {}
    ~TS0710_SLEEP()
    {}

  private:
    void request();

    void indication();

    void confirm();
};

#endif //_TS0710_SLEEP_H

D module-cellular/Modem/TS0710/TS0710_START.cpp => module-cellular/Modem/TS0710/TS0710_START.cpp +0 -72
@@ 1,72 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**
 * Project Untitled
 */

#include "TS0710_START.h"
#include "DLC_channel.h"
#include "log/log.hpp"

/**
 * TS0710_START implementation
 */

TS0710_START::TS0710_START(Mode_e mode, START_SystemParameters_t system_parameters, bsp::Cellular *cellular)
{
    pv_mode              = mode;
    pv_system_parameters = system_parameters;
    pv_cellular          = cellular;

    // assemble frame, send request, report connection status
    request(pv_mode, pv_system_parameters);
}

TS0710_START::~TS0710_START()
{}

/**
 * @param mode
 * @param system_parameters
 */
void TS0710_START::request(Mode_e mode, START_SystemParameters_t system_parameters)
{
    // 1. start CMUX by AT command AT+CMUX=...(with given parameters) & get response
    /*
    AT+CMUX=<mode>[,<subset>[,<portspeed>[,<N1>[,<T1>[,<N2>[,<T2>[,<T3>[,<k>]]]]]]]]
    <mode> 0 Basic option.
    <subset> This parameter defines the way in which the MUX control channel is set up.
        Virtual channel may subsequently be set up differently, but in the absence of any
        negotiation for the settings of a virtual channel, it shall be set up according to thecontrol channel <subset>
    setting. 0 UIH frames used only. 1 UI frames used only. 2 I frames used only. <portspeed> 1 9600bit/s 2 19200bit/s
        3 38400bit/s
        4 57600bit/s
        5 115200bit/s
        6 230400bit/s
        7 460800bit/s
    <N1> Maximum frame size, the range is 1-32768, 127 is the default value for basic option (see <mode>).
    <T1> The time UE waits for an acknowledgement before resorting to other action (e.g.
        transmitting a frame).The step size is ten milliseconds, the range is 1-255. The default value is 100ms.
    <N2> Maximum number of re-transmissions, the range is 0-255, the default value is 3.
    <T2> Response timer for MUX control channel, the step size is ten milliseconds, the range is 2-255, 30 is the
    default value. <T3> Wake up response timer in seconds. The range is 1-255, 10 is the default value. <k> Window size
    (It is not supported for UC20)

    PortSpeed_e PortSpeed;          //!< Port speed
    int MaxFrameSize;               //!< Maximum Frame Size [ 1-128 in Basic mode, 1-512 in HDLC modes, default: 31 for
    basic option & 64 for advanced ] int AckTimer;                   //!< Acknowledgement Timer [0,01s-2,55s, default:
    0,1s] int MaxNumOfRetransmissions;    //!< Maximum number of retransmissions [0-100, default: 3] int
    MaxCtrlRespTime;            //!< Response timer for the multiplexer control channel [0,01s-2,55s, default: 0,3s] int
    WakeUpRespTime;             //!< Wake up response timer [1s-255s, default: 10s] int ErrRecovWindowSize;         //!<
    Window size for error recovery mode [1-7, default: 2]
    */

    // 2. Create channel DLCI0 - control
    ctrlChannel = new DLC_channel(0, std::string("Control"), pv_cellular);

    // wait & check for active flag in channel
    if (ctrlChannel->getActive()) {
        connStatus = true;
    }
}

D module-cellular/Modem/TS0710/TS0710_START.h => module-cellular/Modem/TS0710/TS0710_START.h +0 -95
@@ 1,95 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#ifndef _TS0710_START_H
#define _TS0710_START_H

#include <tuple>
#include <map>
#include "DLC_channel.h"

class TS0710_START
{
  public:
    enum class Mode_e
    {
        Basic,
        HDLC_UIH_frames,
        HDLC_UI_frames,
        HDLC_frames
    };

    struct START_SystemParameters_t
    {
        PortSpeed_e PortSpeed; //!< Port speed
        int MaxFrameSize;      //!< Maximum Frame Size [ 1-128 in Basic mode, 1-512 in HDLC modes, default: 31 for basic
                               //!< option & 64 for advanced ]
        int AckTimer;          //!< Acknowledgement Timer [0,01s-2,55s, default: 0,1s]
        int MaxNumOfRetransmissions; //!< Maximum number of retransmissions [0-100, default: 3]
        int MaxCtrlRespTime;    //!< Response timer for the multiplexer control channel [0,01s-2,55s, default: 0,3s]
        int WakeUpRespTime;     //!< Wake up response timer [1s-255s, default: 10s]
        int ErrRecovWindowSize; //!< Window size for error recovery mode [1-7, default: 2]
    };

  private:
    Mode_e pv_mode;
    START_SystemParameters_t pv_system_parameters;
    bool connStatus = false; //!< Connection status - false: GSM0710 not started, true: client responded
    DLC_channel *ctrlChannel;
    bsp::Cellular *pv_cellular;

  public:
    TS0710_START(Mode_e mode, START_SystemParameters_t system_parameters, bsp::Cellular *cellular);
    ~TS0710_START();

  private:
    /**
     * @param mode
     * @param system_parameters
     * @brief The request primitive is used to request that the multiplexer mode to be turned on in the desired mode and
     * system parameters.
     */
    void request(Mode_e mode, START_SystemParameters_t system_parameters);

    /**
     * @param mode
     * @param system_parameters
     * @brief The indication primitive transfers the request to start multiplexer operation along with the desired mode
     * and system parameters to the upper layer of the target device.
     */
    // void indication(Mode_e mode, START_SystemParameters_t system_parameters);

    /**
     * @param mode
     * @param system_parameters
     * @param accept
     * @brief If the target device accepts the request by issuing an affirmative response primitive, the suggested mode
     * and system parameters will become valid. \
     * A successful establishment of the multiplexer mode is indicated by the accept parameter being set to “true”. \
     * If the accept parameter is set to “false” the returned values for the other parameters are those suggested by the
     * responding device.
     */
    // void response(Mode_e mode, START_SystemParameters_t system_parameters, bool accept);

    /**
     * @param mode
     * @param system_parameters
     * @param accept
     * @brief The confirm primitive is returned to the upper layer of the requesting device. \
     * A successful establishment of the multiplexer mode is indicated by the accept parameter being set to “true”. \
     * If the accept parameter is set to “false” the returned values for the other parameters are those suggested by the
     * responding device.
     */
    // void confirm(Mode_e mode, START_SystemParameters_t system_parameters, bool accept);
  public:
    bool ConnectionStatus()
    {
        return connStatus;
    }
    DLC_channel *getCtrlChannel()
    {
        return ctrlChannel;
    }
};

#endif //_TS0710_START_H

D module-cellular/Modem/TS0710/TS0710_TEST.cpp => module-cellular/Modem/TS0710/TS0710_TEST.cpp +0 -24
@@ 1,24 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**
 * Project Untitled
 */

#include "TS0710_TEST.h"

/**
 * TS0710_TEST implementation
 */

/**
 * @param TestData
 */
void TS0710_TEST::request(std::vector<uint8_t> TestData)
{}

/**
 * @param TestData
 */
void TS0710_TEST::confirm(std::vector<uint8_t> TestData)
{}
\ No newline at end of file

D module-cellular/Modem/TS0710/TS0710_TEST.h => module-cellular/Modem/TS0710/TS0710_TEST.h +0 -31
@@ 1,31 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#ifndef _TS0710_TEST_H
#define _TS0710_TEST_H

#include <vector>
#include "stdint.h"
// control channel - Test Command (Test)

class TS0710_TEST
{
  public:
    TS0710_TEST()
    {}
    ~TS0710_TEST()
    {}

  private:
    /**
     * @param TestData
     */
    void request(std::vector<uint8_t> TestData);

    /**
     * @param TestData
     */
    void confirm(std::vector<uint8_t> TestData);
};

#endif //_TS0710_TEST_H

D module-cellular/Modem/TS0710/TS0710_WAKEUP.cpp => module-cellular/Modem/TS0710/TS0710_WAKEUP.cpp +0 -18
@@ 1,18 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**
 * Project Untitled
 */

#include "TS0710_WAKEUP.h"

/**
 * TS0710_WAKEUP implementation
 */

void TS0710_WAKEUP::indication()
{}

void TS0710_WAKEUP::response()
{}
\ No newline at end of file

D module-cellular/Modem/TS0710/TS0710_WAKEUP.h => module-cellular/Modem/TS0710/TS0710_WAKEUP.h +0 -31
@@ 1,31 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**
 * Project Untitled
 * @brief The indication primitive is sent to the upper layer when the TS 0710 layer of the receiving unit receives a
 * request to wake up from the power saving state. When the receiving device is ready to resume operation on the
 * multiplexer channel this is indicated to the TS 0710 layer in the receiving unit by means of the response primitive.
 * Sins the wakeup routine is initiated by the transmitting device attempting to communicate, neither request nor
 * confirm primitives are provided for the wakeup service. The transmitting device instead uses the Data services
 * described below.
 */

#ifndef _TS0710_WAKEUP_H
#define _TS0710_WAKEUP_H

class TS0710_WAKEUP
{
  public:
    TS0710_WAKEUP()
    {}
    ~TS0710_WAKEUP()
    {}

  private:
    void indication();

    void response();
};

#endif //_TS0710_WAKEUP_H
\ No newline at end of file

D module-cellular/Modem/TS0710/tests/test-TS0710_CLOSE.cpp => module-cellular/Modem/TS0710/tests/test-TS0710_CLOSE.cpp +0 -11
@@ 1,11 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "catch.hpp"
#include "TS0710_CLOSE.h"
TEST_CASE("test-TS0710_CLOSE")
{
    TS0710_CLOSE *_class = new TS0710_CLOSE();

    delete _class;
}

D module-cellular/Modem/TS0710/tests/test-TS0710_CONTROL.cpp => module-cellular/Modem/TS0710/tests/test-TS0710_CONTROL.cpp +0 -11
@@ 1,11 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "catch.hpp"
#include "TS0710_CONTROL.h"
TEST_CASE("test-TS0710_CONTROL")
{
    TS0710_CONTROL *_class = new TS0710_CONTROL();

    delete _class;
}

D module-cellular/Modem/TS0710/tests/test-TS0710_DLC_RELEASE.cpp => module-cellular/Modem/TS0710/tests/test-TS0710_DLC_RELEASE.cpp +0 -11
@@ 1,11 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "catch.hpp"
#include "TS0710_DLC_RELEASE.h"
TEST_CASE("test-TS0710_DLC_RELEASE")
{
    TS0710_DLC_RELEASE *_class = new TS0710_DLC_RELEASE(0);

    delete _class;
}

D module-cellular/Modem/TS0710/tests/test-TS0710_FLOW.cpp => module-cellular/Modem/TS0710/tests/test-TS0710_FLOW.cpp +0 -11
@@ 1,11 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "catch.hpp"
#include "TS0710_FLOW.h"
TEST_CASE("test-TS0710_FLOW")
{
    TS0710_FLOW *_class = new TS0710_FLOW();

    delete _class;
}

D module-cellular/Modem/TS0710/tests/test-TS0710_PARNEG.cpp => module-cellular/Modem/TS0710/tests/test-TS0710_PARNEG.cpp +0 -11
@@ 1,11 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "catch.hpp"
#include "TS0710_PARNEG.h"
TEST_CASE("test-TS0710_PARNEG")
{
    TS0710_PARNEG *_class = new TS0710_PARNEG();

    delete _class;
}

D module-cellular/Modem/TS0710/tests/test-TS0710_PORTNEG.cpp => module-cellular/Modem/TS0710/tests/test-TS0710_PORTNEG.cpp +0 -11
@@ 1,11 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "catch.hpp"
#include "TS0710_PORTNEG.h"
TEST_CASE("test-TS0710_PORTNEG")
{
    TS0710_PORTNEG *_class = new TS0710_PORTNEG();

    delete _class;
}

D module-cellular/Modem/TS0710/tests/test-TS0710_SERVNEG.cpp => module-cellular/Modem/TS0710/tests/test-TS0710_SERVNEG.cpp +0 -11
@@ 1,11 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "catch.hpp"
#include "TS0710_SERVNEG.h"
TEST_CASE("test-TS0710_SERVNEG")
{
    TS0710_SERVNEG *_class = new TS0710_SERVNEG();

    delete _class;
}

D module-cellular/Modem/TS0710/tests/test-TS0710_SLEEP.cpp => module-cellular/Modem/TS0710/tests/test-TS0710_SLEEP.cpp +0 -11
@@ 1,11 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "catch.hpp"
#include "TS0710_SLEEP.h"
TEST_CASE("test-TS0710_SLEEP")
{
    TS0710_SLEEP *_class = new TS0710_SLEEP();

    delete _class;
}

D module-cellular/Modem/TS0710/tests/test-TS0710_TEST.cpp => module-cellular/Modem/TS0710/tests/test-TS0710_TEST.cpp +0 -11
@@ 1,11 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "catch.hpp"
#include "TS0710_TEST.h"
TEST_CASE("test-TS0710_TEST")
{
    TS0710_TEST *_class = new TS0710_TEST();

    delete _class;
}

D module-cellular/Modem/TS0710/tests/test-TS0710_WAKEUP.cpp => module-cellular/Modem/TS0710/tests/test-TS0710_WAKEUP.cpp +0 -11
@@ 1,11 0,0 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "catch.hpp"
#include "TS0710_WAKEUP.h"
TEST_CASE("test-TS0710_WAKEUP")
{
    TS0710_WAKEUP *_class = new TS0710_WAKEUP();

    delete _class;
}

R module-cellular/Modem/ATCommon.cpp => module-cellular/modem/ATCommon.cpp +5 -6
@@ 7,13 7,12 @@
#include <functional>
#include <log/log.hpp>
#include <string>
#include <ticks.hpp>
#include <inttypes.h> // for PRIu32
#include <Utils.hpp>
#include "ATStream.hpp"
#include <at/ATFactory.hpp>

using namespace at;
using namespace std::chrono_literals;

const std::string Channel::OK         = "OK";
const std::string Channel::ERROR      = "ERROR";


@@ 66,9 65,9 @@ Result Channel::cmd(const std::string &cmd, std::chrono::milliseconds timeout, s

    awaitingResponseFlag.set();

    cmd_init();
    cmdInit();
    std::string cmdFixed = formatCommand(cmd);
    cmd_send(cmdFixed);
    cmdSend(cmdFixed);

    auto startTime = std::chrono::steady_clock::now();
    auto endTime   = startTime + timeout;


@@ 79,7 78,7 @@ Result Channel::cmd(const std::string &cmd, std::chrono::milliseconds timeout, s
            break;
        }

        if (size_t bytesRead = cmd_receive(receiveBuffer.get(), std::chrono::milliseconds{0}); bytesRead > 0) {
        if (size_t bytesRead = cmdReceive(receiveBuffer.get(), 0ms); bytesRead > 0) {
            auto cellularResult = bsp::cellular::CellularResult{receiveBuffer.get(), bytesRead};

            if (result = checkResult(cellularResult.getResultCode()); result.code != at::Result::Code::OK) {


@@ 97,7 96,7 @@ Result Channel::cmd(const std::string &cmd, std::chrono::milliseconds timeout, s

    awaitingResponseFlag.clear();

    cmd_post();
    cmdPost();
    cmdLog(cmdFixed, result, timeout);

    return result;

R module-cellular/Modem/ATCommon.hpp => module-cellular/modem/ATCommon.hpp +0 -0
R module-cellular/Modem/ATParser.cpp => module-cellular/modem/ATParser.cpp +11 -8
@@ 6,17 6,20 @@
#include "bsp/cellular/bsp_cellular.hpp"
#include <service-cellular/CellularMessage.hpp>
#include "ticks.hpp"
#include <Utils.hpp>
#include <utility>
#include <vector>

using namespace std::chrono_literals;

ATParser::ATParser(bsp::Cellular *cellular) : Channel{new uint8_t[at::defaultReceiveBufferSize]}, cellular(cellular)
{
    assert(cellular != nullptr);

    responseBuffer = xMessageBufferCreate(at::defaultMessageBufferSize);
}

/// plz see 12.7 summary of urc in documentation
std::vector<ATParser::Urc> ATParser::ParseURC()
std::vector<ATParser::Urc> ATParser::parseUrc()
{
    size_t maxPos = 0, pos = 0;



@@ 56,7 59,7 @@ std::vector<ATParser::Urc> ATParser::ParseURC()
    return resp;
}

at::Result ATParser::ProcessNewData(sys::Service *service, bsp::cellular::CellularResult &cellularResult)
at::Result ATParser::processNewData(sys::Service *service, const bsp::cellular::CellularResult &cellularResult)
{
    at::Result result;



@@ 65,7 68,7 @@ at::Result ATParser::ProcessNewData(sys::Service *service, bsp::cellular::Cellul
        urcBuffer.append(cellularResult.getDataAsString());
    }

    auto ret = ParseURC();
    auto ret = parseUrc();

    if (awaitingResponseFlag.state()) {
        if (!xMessageBufferSend(responseBuffer,


@@ 109,23 112,23 @@ at::Result ATParser::ProcessNewData(sys::Service *service, bsp::cellular::Cellul
    return result;
}

void ATParser::cmd_init()
void ATParser::cmdInit()
{
    cpp_freertos::LockGuard lock(mutex);
    urcBuffer.erase();
}

void ATParser::cmd_send(std::string cmd)
void ATParser::cmdSend(std::string cmd)
{
    cellular->write(const_cast<char *>(cmd.c_str()), cmd.size());
}

size_t ATParser::cmd_receive(std::uint8_t *buffer, std::chrono::milliseconds timeout = std::chrono::milliseconds{0})
size_t ATParser::cmdReceive(std::uint8_t *buffer, std::chrono::milliseconds timeout = 0ms)
{
    return xMessageBufferReceive(responseBuffer, buffer, 256, pdMS_TO_TICKS(timeout.count()));
}

void ATParser::cmd_post()
void ATParser::cmdPost()
{
    cpp_freertos::LockGuard lock(mutex);
    urcBuffer.erase();

R module-cellular/Modem/ATParser.hpp => module-cellular/modem/ATParser.hpp +6 -6
@@ 37,15 37,15 @@ class ATParser : public at::Channel
    ATParser(bsp::Cellular *cellular);
    virtual ~ATParser() = default;

    at::Result ProcessNewData(sys::Service *service, bsp::cellular::CellularResult &cellularResult);
    at::Result processNewData(sys::Service *service, const bsp::cellular::CellularResult &cellularResult);

    virtual void cmd_init() override final;
    virtual void cmd_send(std::string cmd) override final;
    virtual size_t cmd_receive(std::uint8_t *buffer, std::chrono::milliseconds timeout) override final;
    virtual void cmd_post() override final;
    virtual void cmdInit() override final;
    virtual void cmdSend(std::string cmd) override final;
    virtual size_t cmdReceive(std::uint8_t *buffer, std::chrono::milliseconds timeout) override final;
    virtual void cmdPost() override final;

  private:
    std::vector<Urc> ParseURC();
    std::vector<Urc> parseUrc();
    bsp::Cellular *cellular              = nullptr;
    MessageBufferHandle_t responseBuffer = nullptr;
    std::string urcBuffer                = {};

R module-cellular/Modem/ATStream.cpp => module-cellular/modem/ATStream.cpp +1 -1
@@ 143,7 143,7 @@ namespace at
                 * the wrong one may result in returning incorrect / incomplete values.
                 * It only applies to a group of specific commands like AT + QPING, in which the result (OK)
                 * is returned at the beginning, followed by information. This could happen only if we not fit
                 * in one return of cmd_receive return.
                 * in one return of cmdReceive return.
                 */
                if (rxCount == 0) {
                    return true;

R module-cellular/Modem/ATStream.hpp => module-cellular/modem/ATStream.hpp +0 -0
R module-cellular/Modem/ATURCStream.cpp => module-cellular/modem/ATURCStream.cpp +0 -0
R module-cellular/Modem/ATURCStream.hpp => module-cellular/modem/ATURCStream.hpp +0 -0
R module-cellular/Modem/BaseChannel.hpp => module-cellular/modem/BaseChannel.hpp +4 -4
@@ 31,10 31,10 @@ namespace at
        /// {
        virtual void cmdLog(std::string cmd, const Result &result, std::chrono::milliseconds timeout)
        {}
        virtual void cmd_init()                                                               = 0;
        virtual void cmd_send(std::string cmd)                                                = 0;
        virtual size_t cmd_receive(std::uint8_t *buffer, std::chrono::milliseconds timeoutMs) = 0;
        virtual void cmd_post()                                                               = 0;
        virtual void cmdInit()                                                               = 0;
        virtual void cmdSend(std::string cmd)                                                = 0;
        virtual size_t cmdReceive(std::uint8_t *buffer, std::chrono::milliseconds timeoutMs) = 0;
        virtual void cmdPost()                                                               = 0;
        /// }
    };
} // namespace at

R module-cellular/Modem/README.md => module-cellular/modem/README.md +0 -5
@@ 9,11 9,6 @@
5. [Cellular result structures](#result)
6. [Error codes](#errors)

## History <a name="history"></a>
| Authors           | Change description        | Status | Modification date |
| ----------------- | ------------------------- | ------ | ----------------- |
| Maciej Janicki    | Initial version           | Draft  | 2021.03.24        |

## Modes <a name="modes"></a>
Cellular operates in three modes:
 - AT,

R module-cellular/Modem/doc/ATStream.md => module-cellular/modem/doc/ATStream.md +0 -0
R module-cellular/Modem/doc/Images/at_mode.svg => module-cellular/modem/doc/Images/at_mode.svg +0 -0
R module-cellular/Modem/doc/Images/at_mode.uml => module-cellular/modem/doc/Images/at_mode.uml +0 -0
R module-cellular/Modem/doc/Images/atstream.png => module-cellular/modem/doc/Images/atstream.png +0 -0
R module-cellular/Modem/doc/Images/cellular_mux_read.png => module-cellular/modem/doc/Images/cellular_mux_read.png +0 -0
R module-cellular/Modem/doc/Images/cellular_result_struct.png => module-cellular/modem/doc/Images/cellular_result_struct.png +0 -0
R module-cellular/Modem/doc/Images/cellular_result_struct.uml => module-cellular/modem/doc/Images/cellular_result_struct.uml +0 -0
R module-cellular/Modem/doc/Images/class_channel.png => module-cellular/modem/doc/Images/class_channel.png +0 -0
R module-cellular/Modem/doc/Images/cmx_mode.uml => module-cellular/modem/doc/Images/cmx_mode.uml +0 -0
R module-cellular/Modem/doc/Images/current_volte_on.png => module-cellular/modem/doc/Images/current_volte_on.png +0 -0
R module-cellular/Modem/doc/Images/dma_result_struct.png => module-cellular/modem/doc/Images/dma_result_struct.png +0 -0
R module-cellular/Modem/doc/Images/dma_result_struct.uml => module-cellular/modem/doc/Images/dma_result_struct.uml +0 -0
R module-cellular/Modem/doc/Images/mudita_logo.png => module-cellular/modem/doc/Images/mudita_logo.png +0 -0
R module-cellular/Modem/doc/Images/mux_mode.svg => module-cellular/modem/doc/Images/mux_mode.svg +0 -0
R module-cellular/Modem/doc/Images/single_cmd.uml => module-cellular/modem/doc/Images/single_cmd.uml +0 -0
R module-cellular/Modem/doc/Images/single_cmd_transmission.png => module-cellular/modem/doc/Images/single_cmd_transmission.png +0 -0
R module-cellular/Modem/doc/Images/volte_on.png => module-cellular/modem/doc/Images/volte_on.png +0 -0
R module-cellular/Modem/doc/scripts/atstream.pu => module-cellular/modem/doc/scripts/atstream.pu +0 -0
R module-cellular/Modem/doc/scripts/class_channel.pu => module-cellular/modem/doc/scripts/class_channel.pu +2 -2
@@ 6,7 6,7 @@ BaseChannel <|-- Channel

Channel ..> ATStream: Channel use ATStream

Channel <|-- DLC_channel
Channel <|-- DLCChannel
Channel <|-- ATParser

@enduml
\ No newline at end of file
@enduml

R module-cellular/Modem/TS0710/TS0710.cpp => module-cellular/modem/mux/CellularMux.cpp +225 -127
@@ 1,18 1,22 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "TS0710.h"
#include "CellularMux.h"

#include <at/ATFactory.hpp>
#include <at/Cmd.hpp>
#include "bsp/cellular/bsp_cellular.hpp"
#include "bsp/cellular/CellularResult.hpp"
#include "projdefs.h"
#include <service-cellular/ServiceCellular.hpp>

#include <bsp/cellular/bsp_cellular.hpp>
#include <bsp/cellular/CellularResult.hpp>
#include <projdefs.h>

#include <service-cellular/SignalStrength.hpp>
#include <service-cellular/CellularMessage.hpp>
#include <cassert>

#include <RTOSWrapper/include/ticks.hpp>

#include <gsl/gsl_util>
#include <memory>
#include <module-os/RTOSWrapper/include/ticks.hpp>
#include <sstream>
#include <SystemManager/messages/DeviceRegistrationMessage.hpp>



@@ 47,33 51,33 @@ std::map<PortSpeed_e, int> ATPortSpeeds_text          = {{PortSpeed_e::PS9600, 9

static constexpr std::uint16_t threadSizeWords = 2048;

TS0710::TS0710(PortSpeed_e portSpeed, sys::Service *parent)
CellularMux::CellularMux(PortSpeed_e portSpeed, sys::Service *parent)
{
    Init(portSpeed, parent);
    init(portSpeed, parent);
}

TS0710::~TS0710()
CellularMux::~CellularMux()
{
    for (auto it : channels) {
        delete it;
    }
    channels.clear();
    TS0710_CLOSE pv_TS0710_Close = TS0710_CLOSE();
    mode                         = Mode::AT;
    if (taskHandle) {

    if (taskHandle != nullptr) {
        vTaskDelete(taskHandle);
    }
    mode = Mode::AT;

    delete parser;
}

void TS0710::Init(PortSpeed_e portSpeed, sys::Service *parent)
void CellularMux::init(PortSpeed_e portSpeed, sys::Service *parent)
{
    SetStartParams(portSpeed);
    setStartParams(portSpeed);

    pv_cellular = bsp::Cellular::create(SERIAL_PORT, portSpeed).value_or(nullptr);
    parser      = new ATParser(pv_cellular.get());
    pv_parent   = parent;
    cellular      = bsp::Cellular::create(SERIAL_PORT, portSpeed).value_or(nullptr);
    parser        = new ATParser(cellular.get());
    parentService = parent;

    if (auto flushed = flushReceiveData(); flushed > 0) {
        LOG_INFO("Discarded initial %lu bytes sent by modem",


@@ 83,17 87,17 @@ void TS0710::Init(PortSpeed_e portSpeed, sys::Service *parent)
        LOG_DEBUG("Nothing to discard");
    }

    constexpr auto workerName = "TS0710Worker";
    constexpr auto workerName = "CellularMux";

    BaseType_t task_error =
    BaseType_t taskError =
        xTaskCreate(workerTaskFunction, workerName, threadSizeWords, this, taskPriority, &taskHandle);
    if (task_error != pdPASS) {
    if (taskError != pdPASS) {
        LOG_ERROR("Failed to start %s task", workerName);
        return;
    }
}

void TS0710::SetStartParams(PortSpeed_e portSpeed)
void CellularMux::setStartParams(PortSpeed_e portSpeed)
{
    startParams.PortSpeed               = portSpeed;
    startParams.MaxFrameSize            = 127; // maximum for Basic mode


@@ 104,9 108,9 @@ void TS0710::SetStartParams(PortSpeed_e portSpeed)
    startParams.ErrRecovWindowSize      = 2;   // 2 default
}

TS0710_Frame::frame_t createCMUXExitFrame()
CellularMuxFrame::frame_t createCMUXExitFrame()
{
    TS0710_Frame::frame_t frame;
    CellularMuxFrame::frame_t frame;
    frame.Address = 0 | static_cast<unsigned char>(MuxDefines ::GSM0710_CR);
    frame.Control = TypeOfFrame_e::UIH;
    frame.data.push_back(static_cast<uint8_t>(MuxDefines::GSM0710_CONTROL_CLD) |


@@ 140,7 144,7 @@ const char *c_str(BaudTestStep step)
    }
}

bool BaudDetectTestAT(ATParser *parser, BaudTestStep &step, BaudTestStep nextStep)
bool baudDetectTestAT(ATParser *parser, BaudTestStep &step, BaudTestStep nextStep)
{
    if (parser != nullptr) {
        LOG_DEBUG("=> Baud detection step: %s -> %s", c_str(step), c_str(nextStep));


@@ 152,20 156,20 @@ bool BaudDetectTestAT(ATParser *parser, BaudTestStep &step, BaudTestStep nextSte
    return false;
}

void CloseCmux(std::unique_ptr<bsp::Cellular> &pv_cellular)
void closeCMux(std::unique_ptr<bsp::Cellular> &pv_cellular)
{
    LOG_INFO("Closing mux mode");
    TS0710_Frame::frame_t frame = createCMUXExitFrame();
    pv_cellular->write((void *)frame.serialize().data(), frame.serialize().size());
    CellularMuxFrame::frame_t frame = createCMUXExitFrame();
    pv_cellular->write(static_cast<void *>(frame.serialize().data()), frame.serialize().size());
    vTaskDelay(1000); // GSM module needs some time to close multiplexer
}

void TS0710::setMode(TS0710::Mode mode)
void CellularMux::setMode(CellularMux::Mode newMode)
{
    this->mode = mode;
    this->mode = newMode;
}

TS0710::ConfState TS0710::BaudDetectOnce()
CellularMux::ConfState CellularMux::baudDetectOnce()
{
    bool result           = false;
    BaudTestStep lastStep = BaudTestStep::baud_NotFound;


@@ 174,27 178,27 @@ TS0710::ConfState TS0710::BaudDetectOnce()
    while (!result) {
        switch (step) {
        case BaudTestStep::baud460800_NoCmux:
            pv_cellular->setSpeed(ATPortSpeeds_text[PortSpeed_e::PS460800]);
            cellular->setSpeed(ATPortSpeeds_text[PortSpeed_e::PS460800]);
            lastStep = step;
            result   = BaudDetectTestAT(parser, step, BaudTestStep::baud460800_Cmux);
            result   = baudDetectTestAT(parser, step, BaudTestStep::baud460800_Cmux);
            break;
        case BaudTestStep::baud460800_Cmux:
            CloseCmux(pv_cellular);
            closeCMux(cellular);
            lastStep = step;
            result   = BaudDetectTestAT(parser, step, BaudTestStep::baud115200_NoCmux);
            result   = baudDetectTestAT(parser, step, BaudTestStep::baud115200_NoCmux);
            break;
        case BaudTestStep::baud115200_NoCmux:
            pv_cellular->setSpeed(ATPortSpeeds_text[PortSpeed_e::PS115200]);
            cellular->setSpeed(ATPortSpeeds_text[PortSpeed_e::PS115200]);
            lastStep = step;
            result   = BaudDetectTestAT(parser, step, BaudTestStep::baud115200_Cmux);
            result   = baudDetectTestAT(parser, step, BaudTestStep::baud115200_Cmux);
            break;
        case BaudTestStep::baud115200_Cmux:
            CloseCmux(pv_cellular);
            closeCMux(cellular);
            lastStep = step;
            result   = BaudDetectTestAT(parser, step, BaudTestStep::baud_NotFound);
            result   = baudDetectTestAT(parser, step, BaudTestStep::baud_NotFound);
            break;
        case BaudTestStep::baud_NotFound:
            pv_cellular->setSpeed(ATPortSpeeds_text[PortSpeed_e::PS115200]); // set port speed to default 115200
            cellular->setSpeed(ATPortSpeeds_text[PortSpeed_e::PS115200]); // set port speed to default 115200
            LOG_ERROR("No Baud found for modem.");
            return ConfState::Failure;
            break;


@@ 204,29 208,29 @@ TS0710::ConfState TS0710::BaudDetectOnce()
    return ConfState::Success;
}

TS0710::ConfState TS0710::BaudDetectProcedure(uint16_t timeout_s)
CellularMux::ConfState CellularMux::baudDetectProcedure(uint16_t timeout_s)
{
    at::Result ret;
    bool timed_out     = false;
    auto timeout_ticks = cpp_freertos::Ticks::GetTicks() + pdMS_TO_TICKS(timeout_s * 1000);
    bool timedOut     = false;
    auto timeoutTicks = cpp_freertos::Ticks::GetTicks() + pdMS_TO_TICKS(timeout_s * 1000);

    while (!timed_out) {
        auto baud_result = BaudDetectOnce();
        timed_out        = cpp_freertos::Ticks::GetTicks() > timeout_ticks;
    while (!timedOut) {
        auto baud_result = baudDetectOnce();
        timedOut         = cpp_freertos::Ticks::GetTicks() > timeoutTicks;
        if (baud_result == ConfState::Success) {
            return ConfState::Success;
        }
    }
    pv_cellular->setSpeed(ATPortSpeeds_text[PortSpeed_e::PS115200]); // set port speed to default 115200
    cellular->setSpeed(ATPortSpeeds_text[PortSpeed_e::PS115200]); // set port speed to default 115200
    LOG_ERROR("No Baud found.");
    return ConfState::Failure;
}

TS0710::ConfState TS0710::ConfProcedure()
CellularMux::ConfState CellularMux::confProcedure()
{
    LOG_DEBUG("Configuring modem...");

    auto flowCmd = hardwareControlFlowEnable ? (at::AT::FLOW_CTRL_ON) : (at::AT::FLOW_CTRL_OFF);
    auto flowCmd = (at::AT::FLOW_CTRL_ON);
    if (!parser->cmd(flowCmd)) {
        return ConfState::Failure;
    }


@@ 260,17 264,18 @@ TS0710::ConfState TS0710::ConfProcedure()
        }
    }

    bool timed_out                 = false;
    constexpr uint32_t qsclkTmeout = 30;
    const auto qsclkTmeoutTicks =
        cpp_freertos::Ticks::GetTicks() + pdMS_TO_TICKS(qsclkTmeout * utils::time::milisecondsInSecond);
    while (!timed_out) {
    bool timedOut                   = false;
    constexpr uint32_t qsclkTimeout = 30;
    const auto qsclkTimeoutTicks =
        cpp_freertos::Ticks::GetTicks() + pdMS_TO_TICKS(qsclkTimeout * utils::time::milisecondsInSecond);

    while (!timedOut) {
        if (parser->cmd(at::AT::QSCLK_ON)) {
            break;
        }
        vTaskDelay(pdMS_TO_TICKS(utils::time::milisecondsInSecond));
        timed_out = cpp_freertos::Ticks::GetTicks() > qsclkTmeoutTicks;
        if (timed_out) {
        timedOut = cpp_freertos::Ticks::GetTicks() > qsclkTimeoutTicks;
        if (timedOut) {
            return ConfState::Failure;
        }
    }


@@ 278,7 283,7 @@ TS0710::ConfState TS0710::ConfProcedure()
    return ConfState ::Success;
}

TS0710::ConfState TS0710::AudioConfProcedure()
CellularMux::ConfState CellularMux::audioConfProcedure()
{
    auto ret = parser->cmd(at::AT::QDAI);
    // There is possibility for SendATCommand to capture invalid response (it can be ERROR or async URC)


@@ 287,7 292,7 @@ TS0710::ConfState TS0710::AudioConfProcedure()
    if (!ret) {
        return ConfState::Failure;
    }
    else if (ret.response[0].compare("+QDAI: 1,0,0,3,0,1,1,1") == 0) {
    else if (ret.response[0] == "+QDAI: 1,0,0,3,0,1,1,1") {
        if (!parser->cmd(at::AT::QRXGAIN)) {
            return ConfState::Failure;
        }


@@ 304,14 309,14 @@ TS0710::ConfState TS0710::AudioConfProcedure()
            return ConfState::Failure;
        }
        else {
            pv_cellular->restart();
            cellular->restart();
            LOG_DEBUG("GSM module first run, performing reset...");
            return ConfState::ModemNeedsReset;
        }
    }
}

TS0710::ConfState TS0710::StartMultiplexer()
CellularMux::ConfState CellularMux::startMultiplexer()
{
    LOG_DEBUG("Configuring multiplexer...");



@@ 366,11 371,7 @@ TS0710::ConfState TS0710::StartMultiplexer()

    mode = Mode::CMUX_SETUP;

    TS0710_START TS0710_Start{TS0710_START::Mode_e::Basic, startParams, pv_cellular.get()};
    // wait for confirmation
    if (TS0710_Start.ConnectionStatus()) {
        channels.push_back(TS0710_Start.getCtrlChannel()); // store control channel
    }
    openChannel(Channel::Control);

    controlCallback = [this](std::string &data) {
        auto frameData = data;


@@ 382,36 383,40 @@ TS0710::ConfState TS0710::StartMultiplexer()
        switch (frameData[0]) {
        case 0xE3: { // MSC
            LOG_PRINTF("[MSC ch #%i] ", frameData[2] >> 2);
            if (frameData[3] & 0x80)
            if ((frameData[3] & static_cast<uint8_t>(ControlSignal::DataValid)) != 0) {
                LOG_PRINTF("DV ");
            if (frameData[3] & 0x40)
            }
            if ((frameData[3] & static_cast<uint8_t>(ControlSignal::IncomingCallIndicator)) != 0) {
                LOG_PRINTF("IC ");
            if (frameData[3] & 0x08)
            }
            if ((frameData[3] & static_cast<uint8_t>(ControlSignal::ReadyToReceive)) != 0) {
                LOG_PRINTF("RTR ");
            if (frameData[3] & 0x04) {
            }
            if ((frameData[3] & static_cast<uint8_t>(ControlSignal::ReadyToCommunicate)) != 0) {
                LOG_PRINTF("RTC ");
                this->getCellular()->setSendingAllowed(true);
            }
            else
            else {
                this->getCellular()->setSendingAllowed(false);
            if (frameData[3] & 0x02)
            }
            if ((frameData[3] & static_cast<uint8_t>(ControlSignal::FlowControl)) != 0) {
                LOG_PRINTF("FC ");

            }
            LOG_PRINTF("\n");
        } break;
        }
    };

    OpenChannel(Channel::Commands);
    OpenChannel(Channel::Notifications);
    OpenChannel(Channel::Data);
    LOG_DEBUG("[TS0710] Channels open");
    openChannel(Channel::Commands);
    openChannel(Channel::Notifications);
    openChannel(Channel::Data);
    LOG_DEBUG("Channels open");

    mode = Mode::CMUX;

    if (auto channel = get(Channel::Commands); channel != nullptr) {
        // Route URCs to second (Notifications) MUX channel
        LOG_DEBUG("[TS0710] Setting URC Channel");
        LOG_DEBUG("Setting URC Channel");
        channel->cmd(at::AT::SET_URC_CHANNEL);
        LOG_DEBUG("Sending test ATI");
        auto res = channel->cmd(at::AT::SW_INFO);


@@ 420,8 425,8 @@ TS0710::ConfState TS0710::StartMultiplexer()
        }
        res = channel->cmd(at::AT::CSQ);
        if (res) {
            auto beg       = res.response[0].find(" ");
            auto end       = res.response[0].find(",", 1);
            auto beg       = res.response[0].find(' ');
            auto end       = res.response[0].find(',', 1);
            auto input_val = res.response[0].substr(beg + 1, end - beg - 1);
            auto strength  = 0;
            try {


@@ 435,7 440,7 @@ TS0710::ConfState TS0710::StartMultiplexer()
            if (signalStrength.isValid()) {
                Store::GSM::get()->setSignalStrength(signalStrength.data);
                auto msg = std::make_shared<CellularSignalStrengthUpdateNotification>();
                pv_parent->bus.sendMulticast(msg, sys::BusChannel::ServiceCellularNotifications);
                parentService->bus.sendMulticast(std::move(msg), sys::BusChannel::ServiceCellularNotifications);
            }
        }
        else {


@@ 447,13 452,13 @@ TS0710::ConfState TS0710::StartMultiplexer()
        return ConfState::Failure;
    }

    LOG_DEBUG("[TS0710] Mux started");
    LOG_DEBUG("Mux started");
    return ConfState::Success;
}

void TS0710::sendFrameToChannel(bsp::cellular::CellularResult &resultStruct)
void CellularMux::sendFrameToChannel(bsp::cellular::CellularResult &resultStruct)
{
    auto frame = TS0710_Frame{resultStruct.getData()};
    auto frame = CellularMuxFrame{resultStruct.getData()};

    for (auto chan : getChannels()) {
        if (frame.getFrameDLCI() == chan->getDLCI()) {


@@ 465,23 470,23 @@ void TS0710::sendFrameToChannel(bsp::cellular::CellularResult &resultStruct)
                resultStruct.setData(frame.getData());
            }

            if (frame.getFrameStatus() != TS0710_Frame::OK) {
            if (frame.getFrameStatus() != CellularMuxFrame::OK) {
                resultStruct.setResultCode(bsp::cellular::CellularResultCode::CMUXFrameError);
            }

            chan->ParseInputData(&resultStruct);
            chan->parseInputData(&resultStruct);
            return;
        }
    }
}

void TS0710::parseCellularResultCMUX(bsp::cellular::CellularDMAResultStruct &result)
void CellularMux::parseCellularResultCMUX(bsp::cellular::CellularDMAResultStruct &result)
{
    static std::vector<uint8_t> currentFrame;
    static bool frameStartDetected = false;

    for (auto i = 0U; i < result.dataSize; ++i) {
        uint8_t character = result.data[i];
        uint8_t character = gsl::at(result.data, i);
        if (frameStartDetected || character == TS0710_FLAG) {
            currentFrame.push_back(character);



@@ 490,7 495,7 @@ void TS0710::parseCellularResultCMUX(bsp::cellular::CellularDMAResultStruct &res
                if (currentFrame.size() == 2) {
                    currentFrame.erase(currentFrame.begin());
                }
                if (TS0710_Frame::isComplete(currentFrame)) {
                if (CellularMuxFrame::isComplete(currentFrame)) {
                    frameStartDetected = false;
                    bsp::cellular::CellularResult cellularResult{{result.resultCode, currentFrame}};
                    sendFrameToChannel(cellularResult);


@@ 504,36 509,36 @@ void TS0710::parseCellularResultCMUX(bsp::cellular::CellularDMAResultStruct &res
    }
}

size_t TS0710::flushReceiveData()
size_t CellularMux::flushReceiveData()
{
    auto flushed                = 0U;
    constexpr auto flushTimeout = std::chrono::milliseconds{20};
    bsp::cellular::CellularDMAResultStruct dummyResult;
    do {
        flushed += pv_cellular->read(&dummyResult, dummyResult.getMaxSize(), flushTimeout);
        flushed += cellular->read(&dummyResult, bsp::cellular::CellularDMAResultStruct::getMaxSize(), flushTimeout);
    } while (dummyResult.resultCode == bsp::cellular::CellularResultCode::ReceivedAndFull);
    return flushed;
}

void TS0710::processError(bsp::cellular::CellularDMAResultStruct &result)
void CellularMux::processError(bsp::cellular::CellularDMAResultStruct &result)
{
    bsp::cellular::CellularResult cellularResult{{result.resultCode, {}}};

    if (mode == TS0710::Mode::AT) {
        parser->ProcessNewData(pv_parent, cellularResult);
    if (mode == CellularMux::Mode::AT) {
        parser->processNewData(parentService, cellularResult);
    }
    else if (mode == TS0710::Mode::CMUX || mode == TS0710::Mode::CMUX_SETUP) {
    else if (mode == CellularMux::Mode::CMUX || mode == CellularMux::Mode::CMUX_SETUP) {
        sendFrameToChannel(cellularResult);
    }
}

void TS0710::processData(bsp::cellular::CellularDMAResultStruct &result)
void CellularMux::processData(bsp::cellular::CellularDMAResultStruct &result)
{
    if (mode == TS0710::Mode::AT) {
    if (mode == CellularMux::Mode::AT) {
        bsp::cellular::CellularResult cellularResult{result};
        parser->ProcessNewData(pv_parent, cellularResult);
        parser->processNewData(parentService, cellularResult);
    }
    else if (mode == TS0710::Mode::CMUX || mode == TS0710::Mode::CMUX_SETUP) {
    else if (mode == CellularMux::Mode::CMUX || mode == CellularMux::Mode::CMUX_SETUP) {
        parseCellularResultCMUX(result);
    }
}


@@ 542,14 547,15 @@ void TS0710::processData(bsp::cellular::CellularDMAResultStruct &result)
{
    LOG_DEBUG("Worker start");

    constexpr auto readTimeout = std::chrono::minutes{3600};
    TS0710 *inst               = static_cast<TS0710 *>(ptr);
    constexpr auto readTimeout = std::chrono::seconds{1};
    CellularMux *inst          = static_cast<CellularMux *>(ptr);

    bsp::cellular::CellularDMAResultStruct result{};

    while (true) {
        result.resultCode = bsp::cellular::CellularResultCode::ReceivedNoData;

        inst->pv_cellular->read(&result, bsp::cellular::CellularDMAResultStruct::getMaxSize(), readTimeout);
        inst->cellular->read(&result, bsp::cellular::CellularDMAResultStruct::getMaxSize(), readTimeout);

        switch (result.resultCode) {
        case bsp::cellular::CellularResultCode::ReceivedAndFull:


@@ 577,68 583,68 @@ void TS0710::processData(bsp::cellular::CellularDMAResultStruct &result)
    }
}

void TS0710::SelectAntenna(bsp::cellular::antenna antenna)
void CellularMux::selectAntenna(bsp::cellular::antenna antenna)
{
    pv_cellular->selectAntenna(antenna);
    cellular->selectAntenna(antenna);
}

bsp::cellular::antenna TS0710::GetAntenna()
bsp::cellular::antenna CellularMux::getAntenna()
{
    return pv_cellular->getAntenna();
    return cellular->getAntenna();
}

void TS0710::InformModemHostWakeup(void)
void CellularMux::informModemHostWakeup(void)
{
    return pv_cellular->informModemHostWakeup();
    return cellular->informModemHostWakeup();
}

bool TS0710::IsModemActive(void)
bool CellularMux::isModemActive(void)
{
    return bsp::cellular::status::getStatus() == bsp::cellular::status::value::ACTIVE;
}

void TS0710::TurnOnModem(void)
void CellularMux::turnOnModem(void)
{
    return pv_cellular->powerUp();
    return cellular->powerUp();
}

void TS0710::ResetModem(void)
void CellularMux::resetModem(void)
{
    return pv_cellular->restart();
    return cellular->restart();
}

void TS0710::TurnOffModem(void)
void CellularMux::turnOffModem(void)
{
    return pv_cellular->powerDown();
    return cellular->powerDown();
}

void TS0710::EnterSleepMode(void)
void CellularMux::enterSleepMode(void)
{
    return pv_cellular->enterSleep();
    return cellular->enterSleep();
}

void TS0710::ExitSleepMode(void)
void CellularMux::exitSleepMode(void)
{
    return pv_cellular->exitSleep();
    return cellular->exitSleep();
}

void TS0710::RegisterCellularDevice(void)
void CellularMux::registerCellularDevice(void)
{
    auto deviceRegistrationMsg = std::make_shared<sys::DeviceRegistrationMessage>(pv_cellular->getCellularDevice());
    pv_parent->bus.sendUnicast(std::move(deviceRegistrationMsg), service::name::system_manager);
    auto deviceRegistrationMsg = std::make_shared<sys::DeviceRegistrationMessage>(cellular->getCellularDevice());
    parentService->bus.sendUnicast(std::move(deviceRegistrationMsg), service::name::system_manager);
}

[[nodiscard]] auto TS0710::getLastCommunicationTimestamp() const noexcept -> TickType_t
[[nodiscard]] auto CellularMux::getLastCommunicationTimestamp() const noexcept -> TickType_t
{
    return pv_cellular->getLastCommunicationTimestamp();
    return cellular->getLastCommunicationTimestamp();
}

[[nodiscard]] auto TS0710::isCellularInSleepMode() const noexcept -> bool
[[nodiscard]] auto CellularMux::isCellularInSleepMode() const noexcept -> bool
{
    return pv_cellular->isCellularInSleepMode();
    return cellular->isCellularInSleepMode();
}

TS0710::ConfState TS0710::setupEchoCanceller(EchoCancellerStrength strength)
CellularMux::ConfState CellularMux::setupEchoCanceller(EchoCancellerStrength strength)
{

    switch (strength) {


@@ 758,7 764,99 @@ TS0710::ConfState TS0710::setupEchoCanceller(EchoCancellerStrength strength)
        if (!parser->cmd(at::factory(at::AT::QEEC) + "33,896")) {
            return ConfState::Failure;
        }
    };
    }

    return ConfState::Success;
}

DLCChannel *CellularMux::get(Channel selectedChannel)
{
    for (auto channel : channels) {
        if (channel != nullptr && static_cast<Channel>(channel->getDLCI()) == selectedChannel) {
            return channel;
        }
    }
    return nullptr;
}

std::vector<DLCChannel *> &CellularMux::getChannels()
{
    return channels;
}

bool CellularMux::openChannel(Channel channelIndex)
{
    auto channel = new DLCChannel(static_cast<DLCI_t>(channelIndex), name(channelIndex), cellular.get());
    channels.push_back(channel);

    if (!channel->init()) {
        channels.pop_back();
        delete channel;
        return false;
    }

    return true;
}

void CellularMux::closeChannels()
{
    for (auto &it : channels) {
        delete it;
    }
    channels.clear();
    mode = Mode::AT;
}

bool CellularMux::searchATCommandResponse(const std::vector<std::string> &response,
                                          const std::string &str,
                                          size_t numberOfExpectedTokens,
                                          logger_level level)
{
    const size_t numberOfTokens = response.size();
    if (searchForString(response, str) && (numberOfExpectedTokens == 0 || numberOfTokens == numberOfExpectedTokens)) {
        return true;
    }

    std::string resp;
    for (const std::string &s : response) {
        resp.append(s);
    }

    LOG_CUSTOM(level, "Invalid response: %s", resp.c_str());
    // numberOfExpectedTokens == 0, means do not validate number of tokens
    LOG_CUSTOM(level,
               " - Number of tokens %u, number of expected tokens %u",
               static_cast<unsigned int>(numberOfTokens),
               static_cast<unsigned int>(numberOfExpectedTokens));
    return false;
}

bool CellularMux::searchForString(const std::vector<std::string> &response, const std::string &str)
{
    for (const auto &s : response) {
        if (s == str) {
            return true;
        }
    }
    return false;
}

MuxParameters CellularMux::getStartParams() const noexcept
{
    return startParams;
}

bsp::Cellular *CellularMux::getCellular()
{
    return cellular.get();
}

ATParser *CellularMux::getParser()
{
    return parser;
}

bool CellularMux::checkATCommandPrompt(const std::vector<std::string> &response, logger_level level)
{
    return searchATCommandResponse(response, ">", 0, level);
}

R module-cellular/Modem/TS0710/TS0710.h => module-cellular/modem/mux/CellularMux.h +82 -158
@@ 191,18 191,14 @@ repeated until a response is obtained or action is taken by a higher layer.
#include <vector>
#include <queue>
#include <string>
#include <module-bsp/bsp/cellular/bsp_cellular.hpp>

#include "TS0710_START.h"
#include "TS0710_CLOSE.h"
#include "TS0710_SLEEP.h"
#include "TS0710_TEST.h"
#include "TS0710_WAKEUP.h"
#include "TS0710_types.h"
#include "TS0710_Frame.h"

#include "DLC_channel.h"
#include "Modem/ATParser.hpp"
#include <bsp/cellular/bsp_cellular.hpp>

#include "CellularMuxTypes.h"
#include "CellularMuxFrame.h"
#include "MuxParameters.hpp"

#include "DLCChannel.h"
#include "modem/ATParser.hpp"
#include "Service/Service.hpp"

#include <message_buffer.h>


@@ 224,75 220,53 @@ namespace bsp

[[noreturn]] void workerTaskFunction(void *ptr);

class TS0710
class CellularMux
{
  public:
    enum class Channel : unsigned char
    {
        None          = 0,
        Control       = 0,
        Commands      = 1,
        Notifications = 2,
        Data          = 3,
        None          = 4,
    };

    static std::string name(enum Channel name)
    {
        switch (name) {
        case Channel::None:
            return "None";
        case Channel::Commands:
            return "Commands";
        case Channel::Notifications:
            return "Notifications";
        case Channel::Data:
            return "Data";
        }
        return "";
    }

    enum class Mode
    {
        AT,         /// AT raw text mode
        CMUX_SETUP, /// Modem is switching from AT to CMUX
        CMUX        /// multiplexer mode enabled
    };

    enum class ConfState
    {
        Success,
        Failure,
        ModemNeedsReset,
        PowerUp
    };

    void setMode(Mode mode);
    enum class ControlSignal : uint8_t
    {
        FlowControl           = 0x02,
        ReadyToCommunicate    = 0x04,
        ReadyToReceive        = 0x08,
        IncomingCallIndicator = 0x40,
        DataValid             = 0x80,
    };

  private:
    Mode mode = Mode::AT;
    std::vector<DLC_channel *> channels;

    MuxParameters startParams;
    sys::Service *parentService{};
    std::unique_ptr<bsp::Cellular> cellular;
    ATParser *parser{};

    const uint32_t taskPriority = 0;
    xTaskHandle taskHandle      = nullptr;

    std::unique_ptr<bsp::Cellular> pv_cellular;
    ATParser *parser;
    std::vector<DLCChannel *> channels;
    DLCChannel::Callback_t controlCallback = nullptr;

    int CloseMultiplexer();
    static constexpr auto hardwareControlFlowEnable = true;

    bool searchForString(const std::vector<std::string> &response, std::string str)
    {
        for (std::string s : response) {
            if (s == str)
                return true;
        }
        return false;
    }

    TS0710_START::START_SystemParameters_t startParams;
    sys::Service *pv_parent;

    DLC_channel::Callback_t controlCallback = nullptr;
    friend void workerTaskFunction(void *ptr);

    enum class EchoCancellerStrength
    {


@@ 304,6 278,7 @@ class TS0710

    friend void workerTaskFunction(void *ptr);
    ConfState setupEchoCanceller(EchoCancellerStrength strength);

    void parseCellularResultCMUX(bsp::cellular::CellularDMAResultStruct &result);
    size_t flushReceiveData();
    void processData(bsp::cellular::CellularDMAResultStruct &result);


@@ 311,71 286,33 @@ class TS0710
    void sendFrameToChannel(bsp::cellular::CellularResult &resultStruct);

  public:
    CellularMux(PortSpeed_e portSpeed, sys::Service *parent);
    CellularMux() = delete;

    ~CellularMux();

    void init(PortSpeed_e portSpeed, sys::Service *parent);
    void setStartParams(PortSpeed_e portSpeed);
    void setMode(Mode mode);

    /// @brief get Channel by index
    /// @param channel enum Channel
    /// @return pointer to channel or nullptr if such channel doesn't exist (nullptr return should never happen how -
    /// because all channels are opened once on start)
    DLC_channel *get(Channel chanel_enum)
    {
        for (auto channel : channels) {
            if (channel != nullptr && static_cast<Channel>(channel->getDLCI()) == chanel_enum) {
                return channel;
            }
        }
        return nullptr;
    }

    std::vector<DLC_channel *> &getChannels()
    {
        return channels;
    }
    DLCChannel *get(Channel selectedChannel);
    std::vector<DLCChannel *> &getChannels();
    bool openChannel(Channel channelIndex);
    void closeChannels();

    DLC_channel *OpenChannel(Channel channelIndex)
    {
        auto *channel = new DLC_channel(static_cast<DLCI_t>(channelIndex), name(channelIndex), pv_cellular.get());
        channels.push_back(channel);

        if (!channel->init()) {
            channels.pop_back();
            delete channel;
        }
    ConfState baudDetectOnce();
    ConfState baudDetectProcedure(uint16_t timeout_s = 30);
    ConfState confProcedure();
    ConfState audioConfProcedure();
    ConfState startMultiplexer();

        return channels.back();
    }

    void CloseChannels()
    {
        for (auto &it : channels) {
            delete it;
        }
        channels.clear();
        TS0710_CLOSE pv_TS0710_Close = TS0710_CLOSE();
        mode                         = Mode::AT;
    }

    DLCI_t GetLastDLCI()
    {
        return static_cast<DLCI_t>(channels.size() == 0 ? 0 : channels.size() - 1);
    }

    ConfState BaudDetectOnce();
    ConfState BaudDetectProcedure(uint16_t timeout_s = 30);
    ConfState ConfProcedure();
    ConfState AudioConfProcedure();
    ConfState StartMultiplexer();

    bsp::Cellular *getCellular()
    {
        return pv_cellular.get();
    }
    TS0710_START::START_SystemParameters_t getStartParams()
    {
        return startParams;
    }
    ATParser *getParser()
    {
        return parser;
    }
    MuxParameters getStartParams() const noexcept;
    bsp::Cellular *getCellular();
    ATParser *getParser();

    /// @brief It is searching the resposne for a string
    ///


@@ 384,31 321,11 @@ class TS0710
    /// @param numberOfExpectedTokens - number of expected tokens, 0 means do not validate number of tokens
    /// @param level - determine how the errors are logged
    /// @return true - "OK" string is found, false - otherwise
    bool SearchATCommandResponse(const std::vector<std::string> &response,
    bool searchATCommandResponse(const std::vector<std::string> &response,
                                 const std::string &str,
                                 size_t numberOfExpectedTokens,
                                 logger_level level)
    {
        const size_t numberOfTokens = response.size();
        if (searchForString(response, str) &&
            (numberOfExpectedTokens == 0 || numberOfTokens == numberOfExpectedTokens)) {
            return true;
        }
        else {
            std::string resp;
            for (std::string s : response) {
                resp.append(s);
            }

            LOG_CUSTOM(level, "Invalid response: %s", resp.c_str());
            // numberOfExpectedTokens == 0, means do not validate number of tokens
            LOG_CUSTOM(level,
                       " - Number of tokens %u, number of expected tokens %u",
                       static_cast<unsigned int>(numberOfTokens),
                       static_cast<unsigned int>(numberOfExpectedTokens));
            return false;
        }
    }
                                 logger_level level);
    bool searchForString(const std::vector<std::string> &response, const std::string &str);

    /// @brief It is serching the resposne for ">" string
    ///


@@ 417,30 334,37 @@ class TS0710
    /// @param response - tokenized resposne
    /// @param level - determine how the errors are logged
    /// @return true - str string is found, false - otherwise
    bool CheckATCommandPrompt(const std::vector<std::string> &response, logger_level level = LOGERROR)
    {
        return SearchATCommandResponse(response, ">", 0, level);
    }
    bool checkATCommandPrompt(const std::vector<std::string> &response, logger_level level = LOGERROR);

    void selectAntenna(bsp::cellular::antenna antenna);
    [[nodiscard]] bsp::cellular::antenna getAntenna();

    void informModemHostWakeup();
    bool isModemActive();
    void turnOnModem();
    void resetModem();
    void turnOffModem();
    void enterSleepMode();
    void exitSleepMode();
    void registerCellularDevice();

    TS0710(PortSpeed_e portSpeed, sys::Service *parent);
    TS0710() = delete;
    ~TS0710();
    void Init(PortSpeed_e portSpeed, sys::Service *parent);
    void SetStartParams(PortSpeed_e portSpeed);
    void SelectAntenna(bsp::cellular::antenna antenna);
    bsp::cellular::antenna GetAntenna();
    // Add error handling - only for Advanced mode. Leave for now
    // Add callback for received frame (after error handling)
    // Add frame routing to different channels

    void InformModemHostWakeup(void); // damn, it should be in ServiceCellular
    bool IsModemActive(void);
    void TurnOnModem(void);
    void ResetModem(void);
    void TurnOffModem(void);
    void EnterSleepMode(void);
    void ExitSleepMode(void);
    void RegisterCellularDevice(void);
    [[nodiscard]] auto getLastCommunicationTimestamp() const noexcept -> TickType_t;
    [[nodiscard]] auto isCellularInSleepMode() const noexcept -> bool;

    static std::string name(enum Channel name)
    {
        switch (name) {
        case Channel::None:
            return "None";
        case Channel::Control:
            return "Control";
        case Channel::Commands:
            return "Commands";
        case Channel::Notifications:
            return "Notifications";
        case Channel::Data:
            return "Data";
        }
        return "";
    }
};

R module-cellular/Modem/TS0710/TS0710_DATA.cpp => module-cellular/modem/mux/CellularMuxData.cpp +27 -43
@@ 1,42 1,28 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**
 * Project Untitled
 */

#include "TS0710_DATA.h"
#include "TS0710_Frame.h"
#include "CellularMuxData.h"
#include "CellularMuxFrame.h"
#include <cassert>

#if defined(__cplusplus)
extern "C"
{
#endif
//#include "uart.h"
#if defined(__cplusplus)
}
#endif

/**
 * TS0710_DATA implementation
 */
TS0710_DATA::TS0710_DATA(DLCI_t DLCI,
                         DLC_ESTABL_SystemParameters_t sysParams,
                         std::vector<uint8_t> &User_data,
                         bsp::Cellular *cellular)
CellularMuxData::CellularMuxData(DLCI_t DLCI,
                                 DLC_ESTABL_SystemParameters_t sysParams,
                                 const std::vector<uint8_t> &userData,
                                 bsp::Cellular *cellular)
{
    assert(cellular != nullptr);

    pv_cellular = cellular;
    pvCellular = cellular;

    request(DLCI, sysParams, User_data);
    request(DLCI, sysParams, userData);
}
/**
 * @param DLCI
 * @param User_data
 * @param userData
 */
void TS0710_DATA::request(DLCI_t DLCI, DLC_ESTABL_SystemParameters_t sysParams, std::vector<uint8_t> User_data)
void CellularMuxData::request(DLCI_t DLCI,
                              DLC_ESTABL_SystemParameters_t sysParams,
                              const std::vector<uint8_t> &userData)
{
    /*
    TE sends AT command "ATI<CR>" through DLC 1


@@ 53,31 39,29 @@ void TS0710_DATA::request(DLCI_t DLCI, DLC_ESTABL_SystemParameters_t sysParams, 
                4C 44 30 33 0D 0A 0D 0A 47 F9   UIH Frame
*/
    auto constexpr maximumFrameLength = 127;
    TS0710_Frame::frame_t frame;
    CellularMuxFrame::frame_t frame;
    frame.Address = static_cast<uint8_t>(DLCI << 2) /*| (1 << 1)*/; // set C/R = 1 - command
    frame.Control = static_cast<uint8_t>(TypeOfFrame_e::UIH);

    if (User_data.size() <= static_cast<size_t>(maximumFrameLength)) {
        frame.data = User_data;
        TS0710_Frame frame_c(frame);
    if (userData.size() <= static_cast<size_t>(maximumFrameLength)) {
        frame.data = userData;
        CellularMuxFrame frame_c(frame);
        // UartSend(frame_c.getSerData().data(), frame_c.getSerData().size());
        pv_cellular->write(static_cast<void *>(frame_c.getSerData().data()), frame_c.getSerData().size());
        pvCellular->write(static_cast<void *>(frame_c.getSerData().data()), frame_c.getSerData().size());
    }
    else { // if data size > max frame size
        int dataLeft                     = User_data.size();
        std::vector<uint8_t>::iterator i = User_data.begin();
        uint32_t parts                   = User_data.size() / maximumFrameLength + 1; // add reminder
        int dataLeft   = userData.size();
        auto i         = userData.begin();
        uint32_t parts = userData.size() / maximumFrameLength + 1; // add reminder
        LOG_DEBUG("SENDING %" PRIu32 " parts", parts);
        while (parts--) {
            std::vector<uint8_t>::iterator last =
                i + (dataLeft <= maximumFrameLength ? dataLeft : maximumFrameLength); // distinguish reminder

        while ((parts--) != 0u) {
            auto last  = i + (dataLeft <= maximumFrameLength ? dataLeft : maximumFrameLength); // distinguish reminder
            frame.data = std::vector<uint8_t>(i, last);
            i          = last;
            TS0710_Frame frame_c(frame);
            // UartSend(frame_c.getSerData().data(), frame_c.getSerData().size());
            // while(!pv_cellular->GetSendingAllowed());
            pv_cellular->write(static_cast<void *>(frame_c.getSerData().data()), frame_c.getSerData().size());
            // vTaskDelay(1);

            CellularMuxFrame frame_c(frame);
            pvCellular->write(static_cast<void *>(frame_c.getSerData().data()), frame_c.getSerData().size());
            dataLeft -= (dataLeft <= maximumFrameLength ? dataLeft : maximumFrameLength);
        }
    }


@@ 87,5 71,5 @@ void TS0710_DATA::request(DLCI_t DLCI, DLC_ESTABL_SystemParameters_t sysParams, 
 * @param DLCI
 * @param User_data
 */
void TS0710_DATA::indication(DLCI_t DLCI, std::vector<uint8_t> User_data)
void CellularMuxData::indication(DLCI_t DLCI, std::vector<uint8_t> User_data)
{}

R module-cellular/Modem/TS0710/TS0710_DATA.h => module-cellular/modem/mux/CellularMuxData.h +12 -16
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**


@@ 9,27 9,25 @@
 * take care of all mechanisms involved in the error checking and thus deliver data error free.
 */

#ifndef _TS0710_DATA_H
#define _TS0710_DATA_H
#pragma once

#include <vector>
#include "TS0710.h"
#include "CellularMux.h"

class TS0710_DATA
class CellularMuxData
{
  public:
    TS0710_DATA(DLCI_t DLCI,
                DLC_ESTABL_SystemParameters_t sysParams,
                std::vector<uint8_t> &User_data,
                bsp::Cellular *cellular);
    ~TS0710_DATA()
    {}
    CellularMuxData(DLCI_t DLCI,
                    DLC_ESTABL_SystemParameters_t sysParams,
                    const std::vector<uint8_t> &userData,
                    bsp::Cellular *cellular);

  private:
    /**
     * @param DLCI
     * @param User_data
     * @param userData
     */
    void request(DLCI_t DLCI, DLC_ESTABL_SystemParameters_t sysParams, std::vector<uint8_t> User_data);
    void request(DLCI_t DLCI, DLC_ESTABL_SystemParameters_t sysParams, const std::vector<uint8_t> &userData);

    /**
     * @param DLCI


@@ 38,7 36,5 @@ class TS0710_DATA
     */
    void indication(DLCI_t DLCI, std::vector<uint8_t> User_data);

    bsp::Cellular *pv_cellular;
    bsp::Cellular *pvCellular;
};

#endif //_TS0710_DATA_H
\ No newline at end of file

R module-cellular/Modem/TS0710/TS0710_Frame.h => module-cellular/modem/mux/CellularMuxFrame.h +7 -10
@@ 1,10 1,9 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#ifndef _TS0710_FRAME_H
#define _TS0710_FRAME_H
#pragma once

#include "TS0710_types.h"
#include "CellularMuxTypes.h"
#include <inttypes.h>
#include <vector>
#include <iostream>


@@ 13,7 12,7 @@
#define TS0710_FLAG          0xF9
#define TS0710_FRAME_HDR_LEN 6 // without extended address byte

class TS0710_Frame
class CellularMuxFrame
{
  private:
    static constexpr unsigned char crctable[256] = { // reversed, 8-bit, poly=0x07


@@ 187,27 186,27 @@ class TS0710_Frame
    std::vector<uint8_t> pv_serData;

  public:
    explicit TS0710_Frame(frame_t frame)
    explicit CellularMuxFrame(frame_t frame)
    {
        // LOG_DEBUG("Serializing given frame");
        pv_serData = frame.serialize();
        pv_frame   = frame;
    }

    explicit TS0710_Frame(const std::vector<uint8_t> &serData)
    explicit CellularMuxFrame(const std::vector<uint8_t> &serData)
    {
        // LOG_DEBUG("Deserializing serData");
        pv_frame.deserialize(serData);
        pv_serData = serData;
    }

    TS0710_Frame()
    CellularMuxFrame()
    {
        LOG_DEBUG("Deserializing pv_serData");
        pv_frame.deserialize(pv_serData);
    }

    ~TS0710_Frame()
    ~CellularMuxFrame()
    {
        pv_serData.clear();
        pv_frame.data.clear();


@@ 283,5 282,3 @@ class TS0710_Frame
        return pv_frame.frameStatus;
    }
};

#endif /*_TS0710_FRAME_H*/

R module-cellular/Modem/TS0710/TS0710_types.h => module-cellular/modem/mux/CellularMuxTypes.h +1 -3
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#ifndef _TS0710_TYPES_H


@@ 32,8 32,6 @@ struct DLC_ESTABL_SystemParameters_t
    int ErrRecovWindowSize;      //!< Window size for error recovery mode [1 – 7, default : 2]
};

#define TS0710_MAX_CHANNEL_NUM 4

enum PortSpeed_e
{
    PS2400,

R module-cellular/Modem/TS0710/DLC_channel.cpp => module-cellular/modem/mux/DLCChannel.cpp +34 -47
@@ 1,25 1,23 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "DLC_channel.h"
#include "DLCChannel.h"

#include "TS0710_DATA.h"
#include "TS0710_DLC_RELEASE.h"
#include "TS0710_Frame.h"
#include "CellularMuxData.h"
#include "CellularMuxFrame.h"

#include <module-utils/log/log.hpp>
#include <ticks.hpp>
#include <Utils.hpp>

#include <magic_enum.hpp>

DLC_channel::DLC_channel(DLCI_t DLCI, const std::string &name, bsp::Cellular *cellular, const Callback_t &callback)
    : Channel{new uint8_t[at::defaultReceiveBufferSize]}, pv_name{name}, pv_DLCI{DLCI}, pv_cellular{cellular}
DLCChannel::DLCChannel(DLCI_t DLCI, const std::string &name, bsp::Cellular *cellular, const Callback_t &callback)
    : Channel{new uint8_t[at::defaultReceiveBufferSize]}, name{name}, DLCI{DLCI}, pvCellular{cellular}
{
    LOG_DEBUG("Creating DLCI %i channel \"%s\"", DLCI, name.c_str());

    if (callback != nullptr) {
        pv_callback = callback;
        pvCallback = callback;
    }

    chanParams.TypeOfFrame             = TypeOfFrame_e::SABM;


@@ 33,37 31,32 @@ DLC_channel::DLC_channel(DLCI_t DLCI, const std::string &name, bsp::Cellular *ce
    responseBuffer = xMessageBufferCreate(at::defaultMessageBufferSize);
}

bool DLC_channel::init()
bool DLCChannel::init()
{
    active = establish();
    LOG_INFO("create channel %s: %s", pv_name.c_str(), active ? "TRUE" : "FALSE");
    LOG_INFO("create channel %s: %s", name.c_str(), active ? "TRUE" : "FALSE");

    return active;
}

DLC_channel::~DLC_channel()
void DLCChannel::sendData(std::vector<uint8_t> &data)
{
    TS0710_DLC_RELEASE release = TS0710_DLC_RELEASE(pv_DLCI);
    CellularMuxData(DLCI, chanParams, data, pvCellular);
}

void DLC_channel::SendData(std::vector<uint8_t> &data)
bool DLCChannel::establish()
{
    TS0710_DATA _data = TS0710_DATA(pv_DLCI, chanParams, data, pv_cellular);
}
    LOG_DEBUG("Sending %s frame to DLCI %i", TypeOfFrame_text[chanParams.TypeOfFrame].c_str(), DLCI);

bool DLC_channel::establish()
{
    LOG_DEBUG("Sending %s frame to DLCI %i", TypeOfFrame_text[chanParams.TypeOfFrame].c_str(), pv_DLCI);

    TS0710_Frame frame_c(TS0710_Frame::frame_t(static_cast<uint8_t>(pv_DLCI << 2) | (1 << 1),
                                               static_cast<uint8_t>(chanParams.TypeOfFrame)));
    CellularMuxFrame frame_c(CellularMuxFrame::frame_t(static_cast<uint8_t>(DLCI << 2) | (1 << 1),
                                                       static_cast<uint8_t>(chanParams.TypeOfFrame)));

    awaitingResponseFlag.set();

    bool result = false;

    for (int retries = 0; retries < chanParams.MaxNumOfRetransmissions; ++retries) {
        pv_cellular->write(static_cast<void *>(frame_c.getSerData().data()), frame_c.getSerData().size());
        pvCellular->write(static_cast<void *>(frame_c.getSerData().data()), frame_c.getSerData().size());

        auto startTime = std::chrono::steady_clock::now();
        auto endTime   = startTime + std::chrono::milliseconds{300};


@@ 74,7 67,7 @@ bool DLC_channel::establish()
                break;
            }

            if (size_t bytesRead = cmd_receive(receiveBuffer.get(), std::chrono::milliseconds{0}); bytesRead > 0) {
            if (size_t bytesRead = cmdReceive(receiveBuffer.get(), std::chrono::milliseconds{0}); bytesRead > 0) {
                auto cellularResult = bsp::cellular::CellularResult{receiveBuffer.get(), bytesRead};
                if (evaluateEstablishResponse(cellularResult)) {
                    result = true;


@@ 89,55 82,50 @@ bool DLC_channel::establish()
    return result;
}

void DLC_channel::cmd_init()
void DLCChannel::cmdInit()
{}

void DLC_channel::cmd_send(std::string cmd)
void DLCChannel::cmdSend(std::string cmd)
{
    std::vector<uint8_t> data(cmd.begin(), cmd.end());
    SendData(data);
    sendData(data);
}

size_t DLC_channel::cmd_receive(uint8_t *result, std::chrono::milliseconds timeout)
size_t DLCChannel::cmdReceive(uint8_t *result, std::chrono::milliseconds timeout)
{
    return xMessageBufferReceive(responseBuffer, result, 2 * chanParams.MaxFrameSize, pdMS_TO_TICKS(timeout.count()));
}

void DLC_channel::cmd_post()
void DLCChannel::cmdPost()
{}

std::vector<std::string> DLC_channel::SendCommandPrompt(const char *cmd,
                                                        size_t rxCount,
                                                        std::chrono::milliseconds timeout)
std::vector<std::string> DLCChannel::sendCommandPrompt(const char *cmd,
                                                       size_t rxCount,
                                                       std::chrono::milliseconds timeout)
{
    std::vector<std::string> tokens;

    LOG_DEBUG("SendCommandPrompt start");

    awaitingResponseFlag.set();

    at::Result result;

    cmd_init();
    cmdInit();
    std::string cmdFixed = formatCommand(cmd);
    cmd_send(cmdFixed);
    cmdSend(cmdFixed);

    auto startTime = std::chrono::steady_clock::now();
    auto endTime   = startTime + timeout;

    LOG_DEBUG("SendCommandPrompt cmd sent");
    // Wait for response:
    while (true) {
        if (std::chrono::steady_clock::now() > endTime) {
            result.code = at::Result::Code::TIMEOUT;
            LOG_DEBUG("SendCommandPrompt cmd timeout");
            break;
        }

        if (size_t bytesRead = cmd_receive(receiveBuffer.get(), std::chrono::milliseconds{0}); bytesRead > 0) {
        if (size_t bytesRead = cmdReceive(receiveBuffer.get(), std::chrono::milliseconds{0}); bytesRead > 0) {
            auto cellularResult = bsp::cellular::CellularResult{receiveBuffer.get(), bytesRead};
            auto str            = cellularResult.getDataAsString();
            LOG_DEBUG("SendCommandPrompt got response");

            auto cellResult = checkResult(cellularResult.getResultCode());
            if (cellResult.code != at::Result::Code::OK) {


@@ 158,16 146,15 @@ std::vector<std::string> DLC_channel::SendCommandPrompt(const char *cmd,
        }
    }

    LOG_DEBUG("SendCommandPrompt end");
    cmdLog(cmdFixed, result, timeout);
    cmd_post();
    cmdPost();

    awaitingResponseFlag.clear();

    return tokens;
}

at::Result DLC_channel::ParseInputData(bsp::cellular::CellularResult *cellularResult)
at::Result DLCChannel::parseInputData(bsp::cellular::CellularResult *cellularResult)
{
    at::Result result;



@@ 180,9 167,9 @@ at::Result DLC_channel::ParseInputData(bsp::cellular::CellularResult *cellularRe
            result.code = at::Result::Code::FULL_MSG_BUFFER;
        }
    }
    else if (pv_callback != nullptr) {
    else if (pvCallback != nullptr) {
        std::string receivedData = cellularResult->getDataAsString();
        pv_callback(receivedData);
        pvCallback(receivedData);
    }
    else {
        result.code = at::Result::Code::DATA_NOT_USED;


@@ 191,9 178,9 @@ at::Result DLC_channel::ParseInputData(bsp::cellular::CellularResult *cellularRe
    return result;
}

bool DLC_channel::evaluateEstablishResponse(bsp::cellular::CellularResult &response) const
bool DLCChannel::evaluateEstablishResponse(bsp::cellular::CellularResult &response) const
{
    auto frame = TS0710_Frame{response.getData()};
    return (frame.getFrameDLCI() == pv_DLCI &&
    auto frame = CellularMuxFrame{response.getData()};
    return (frame.getFrameDLCI() == DLCI &&
            (frame.getFrame().Control == (static_cast<uint8_t>(TypeOfFrame_e::UA) & ~(1 << 4))));
}

R module-cellular/Modem/TS0710/DLC_channel.h => module-cellular/modem/mux/DLCChannel.h +40 -49
@@ 1,86 1,77 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

/**
 * Project Untitled
 */

#ifndef _DLC_CHANNEL_H
#define _DLC_CHANNEL_H
#pragma once

#include <string>
#include <utility>
#include <vector>
#include <functional>

#include "Modem/ATCommon.hpp"
#include "TS0710_types.h"
#include <bsp/cellular/CellularResult.hpp>
#include <FreeRTOS.h>
#include <task.h>
#include <message_buffer.h>

class DLC_channel : public at::Channel
#include <bsp/cellular/CellularResult.hpp>

#include "modem/ATCommon.hpp"
#include "CellularMuxTypes.h"

class DLCChannel : public at::Channel
{
  public:
    using Callback_t = std::function<void(std::string &data)>;

  private:
    std::string pv_name;
    DLCI_t pv_DLCI;
    std::string name;
    DLCI_t DLCI = -1;
    bool active = false;
    DLC_ESTABL_SystemParameters_t chanParams{};
    Callback_t pv_callback;
    bsp::Cellular *pv_cellular{};
    Callback_t pvCallback;
    bsp::Cellular *pvCellular = nullptr;

  public:
    DLC_channel(DLCI_t DLCI, const std::string &name, bsp::Cellular *cellular, const Callback_t &callback = nullptr);
    DLC_channel() : Channel{nullptr}, pv_name{"none"}, pv_DLCI{-1}
    {}

    virtual ~DLC_channel();
    DLCChannel(DLCI_t DLCI, const std::string &name, bsp::Cellular *cellular, const Callback_t &callback = nullptr);
    DLCChannel() : Channel{nullptr}, name{"none"}, DLCI{-1} {};
    virtual ~DLCChannel() = default;

    bool init();
    bool establish();
    void sendData(std::vector<uint8_t> &data);

    void SendData(std::vector<uint8_t> &data);
    virtual void cmdInit() override final;
    virtual void cmdSend(std::string cmd) override final;
    virtual size_t cmdReceive(std::uint8_t *result, std::chrono::milliseconds timeout) override final;
    virtual void cmdPost() override final;

    DLCI_t getDLCI()
    std::vector<std::string> sendCommandPrompt(const char *cmd,
                                               size_t rxCount,
                                               std::chrono::milliseconds timeout = std::chrono::milliseconds{300});

    at::Result parseInputData(bsp::cellular::CellularResult *cellularResult);

    bool evaluateEstablishResponse(bsp::cellular::CellularResult &response) const;

    void callback(std::string &data)
    {
        return pv_DLCI;
        pvCallback(data);
    }
    std::string getName()

    DLCI_t getDLCI() const noexcept
    {
        return pv_name;
        return DLCI;
    }
    bool getActive()
    std::string getName() const
    {
        return active;
        return name;
    }

    void setCallback(Callback_t callback)
    bool getActive() const noexcept
    {
        LOG_DEBUG("[%s] Setting up callback for channel", pv_name.c_str());
        pv_callback = callback;
        return active;
    }

    virtual void cmd_init() override final;
    virtual void cmd_send(std::string cmd) override final;
    virtual size_t cmd_receive(std::uint8_t *result,
                               std::chrono::milliseconds timeout = std::chrono::milliseconds{300}) override final;
    virtual void cmd_post() override final;

    std::vector<std::string> SendCommandPrompt(const char *cmd,
                                               size_t rxCount,
                                               std::chrono::milliseconds timeout = std::chrono::milliseconds{300});

    at::Result ParseInputData(bsp::cellular::CellularResult *cellularResult);

    bool evaluateEstablishResponse(bsp::cellular::CellularResult &response) const;

    void callback(std::string &data)
    void setCallback(Callback_t callback)
    {
        pv_callback(data);
        LOG_DEBUG("[%s] Setting up callback for channel", name.c_str());
        pvCallback = std::move(callback);
    }
};

#endif //_DLC_CHANNEL_H

A module-cellular/modem/mux/MuxParameters.hpp => module-cellular/modem/mux/MuxParameters.hpp +16 -0
@@ 0,0 1,16 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#pragma once

struct MuxParameters
{
    PortSpeed_e PortSpeed{}; //!< Port speed
    int MaxFrameSize{};      //!< Maximum Frame Size [ 1-128 in Basic mode, 1-512 in HDLC modes, default: 31 for basic
    //!< option & 64 for advanced ]
    int AckTimer{};                //!< Acknowledgement Timer [0,01s-2,55s, default: 0,1s]
    int MaxNumOfRetransmissions{}; //!< Maximum number of retransmissions [0-100, default: 3]
    int MaxCtrlRespTime{};         //!< Response timer for the multiplexer control channel [0,01s-2,55s, default: 0,3s]
    int WakeUpRespTime{};          //!< Wake up response timer [1s-255s, default: 10s]
    int ErrRecovWindowSize{};      //!< Window size for error recovery mode [1-7, default: 2]
};

R module-cellular/Modem/TS0710/tests/test-DLC_channel.cpp => module-cellular/modem/mux/tests/test-DLCChannel.cpp +2 -2
@@ 7,11 7,11 @@

TEST_CASE("test-DLC_channel")
{
    DLC_channel *_class = new DLC_channel();
    DLCChannel *_class = new DLC_channel();
    REQUIRE(_class->getName() == "none");
    delete _class;

    _class = new DLC_channel(2, "Test2");
    _class = new DLCChannel(2, "Test2");
    REQUIRE(_class->getName() == "Test2");
    REQUIRE(_class->getDLCI() == 2);
    std::vector<uint8_t> v;

R module-cellular/Modem/TS0710/tests/test-TS0710.cpp => module-cellular/modem/mux/tests/test-TS0710.cpp +0 -0
R module-cellular/Modem/TS0710/tests/test-TS0710_DATA.cpp => module-cellular/modem/mux/tests/test-TS0710_DATA.cpp +0 -0
R module-cellular/Modem/TS0710/tests/test-TS0710_DLC_ESTABL.cpp => module-cellular/modem/mux/tests/test-TS0710_DLC_ESTABL.cpp +0 -0
R module-cellular/Modem/TS0710/tests/test-TS0710_START.cpp => module-cellular/modem/mux/tests/test-TS0710_START.cpp +0 -0
M module-cellular/test/mock/AtCommon_channel.hpp => module-cellular/test/mock/AtCommon_channel.hpp +6 -6
@@ 3,8 3,8 @@

#pragma once

#include "Modem/ATCommon.hpp"
#include "Modem/BaseChannel.hpp"
#include "modem/ATCommon.hpp"
#include "modem/BaseChannel.hpp"

namespace at
{


@@ 32,16 32,16 @@ namespace at
            return ResultMock();
        }

        void cmd_init() override
        void cmdInit() override
        {}

        void cmd_send(std::string cmd) override
        void cmdSend(std::string cmd) override
        {}

        void cmd_post() override
        void cmdPost() override
        {}

        size_t cmd_receive(std::uint8_t *buffer, std::chrono::milliseconds timeoutMs) override
        size_t cmdReceive(std::uint8_t *buffer, std::chrono::milliseconds timeoutMs) override
        {
            return {};
        }

M module-cellular/test/unittest_ATStream.cpp => module-cellular/test/unittest_ATStream.cpp +1 -1
@@ 5,7 5,7 @@
#define CATCH_CONFIG_MAIN

#include <catch2/catch.hpp>
#include "Modem/ATStream.hpp"
#include "modem/ATStream.hpp"
#include "Result.hpp"

TEST_CASE("Channel Test- AT return parser")

M module-cellular/test/unittest_ATURCStream.cpp => module-cellular/test/unittest_ATURCStream.cpp +1 -1
@@ 5,7 5,7 @@
#define CATCH_CONFIG_MAIN

#include <catch2/catch.hpp>
#include "Modem/ATURCStream.hpp"
#include "modem/ATURCStream.hpp"

TEST_CASE("URC AT Stream Parser")
{

M module-cellular/test/unittest_CellularResult.cpp => module-cellular/test/unittest_CellularResult.cpp +1 -1
@@ 4,7 4,7 @@
#define CATCH_CONFIG_MAIN

#include <catch2/catch.hpp>
#include <module-bsp/bsp/cellular/CellularResult.hpp>
#include <bsp/cellular/CellularResult.hpp>

TEST_CASE("CellularResult")
{

M module-cellular/test/unittest_URC.cpp => module-cellular/test/unittest_URC.cpp +1 -1
@@ 8,7 8,7 @@
#define CATCH_CONFIG_MAIN

#include <catch2/catch.hpp>
#include <module-utils/time/time_conversion.hpp>
#include <time/time_conversion.hpp>

#include "UrcQind.hpp"
#include "UrcCusd.hpp"

M module-cellular/test/unittest_cmux.cpp => module-cellular/test/unittest_cmux.cpp +8 -8
@@ 4,8 4,8 @@
#define CATCH_CONFIG_MAIN

#include <catch2/catch.hpp>
#include <Modem/TS0710/TS0710_Frame.h>
#include <Modem/TS0710/TS0710_types.h>
#include <modem/mux/CellularMuxFrame.h>
#include <modem/mux/CellularMuxTypes.h>
#include <bsp/cellular/bsp_cellular.hpp>

TEST_CASE("TS0170 frame")


@@ 19,12 19,12 @@ TEST_CASE("TS0170 frame")
        std::string command("AT\r");
        std::vector<uint8_t> commandData(command.begin(), command.end());

        TS0710_Frame::frame_t tempFrame;
        CellularMuxFrame::frame_t tempFrame;
        tempFrame.Address = static_cast<uint8_t>(DLCI << 2);
        tempFrame.Control = static_cast<uint8_t>(TypeOfFrame_e::UIH);
        tempFrame.data    = commandData;

        TS0710_Frame frame(tempFrame);
        CellularMuxFrame frame(tempFrame);

        REQUIRE(frame.isComplete(frame.getSerData()) == true);
        REQUIRE(frame.isMyChannel(DLCI) == true);


@@ 37,7 37,7 @@ TEST_CASE("TS0170 frame")
        std::vector<uint8_t> tempFrame{0xf9, 0x09, 0xef, 0x07, 0x41, 0x54, 0x0d, 0x35, 0xf9};
        auto DLCI = 2;

        TS0710_Frame frame(tempFrame);
        CellularMuxFrame frame(tempFrame);
        auto deserialisedFrame = frame.getFrame();

        REQUIRE(frame.getFrameDLCI(frame.getSerData()) == DLCI);


@@ 53,7 53,7 @@ TEST_CASE("TS0170 frame")
        std::vector<uint8_t> tempFrame{0xf9, 0x09, 0xef, 0x07, 0x41, 0x54, 0x0d, 0x35};
        auto DLCI = 2;

        TS0710_Frame frame(tempFrame);
        CellularMuxFrame frame(tempFrame);

        REQUIRE(frame.getFrameDLCI(frame.getSerData()) == DLCI);
        REQUIRE(frame.isComplete(frame.getSerData()) == false);


@@ 64,7 64,7 @@ TEST_CASE("TS0170 frame")
        std::vector<uint8_t> tempFrame{0xf9, 0x09, 0xef, 0x07, 0x54, 0x0d, 0x35, 0xf9};
        auto DLCI = 2;

        TS0710_Frame frame(tempFrame);
        CellularMuxFrame frame(tempFrame);

        REQUIRE(frame.getFrameDLCI(frame.getSerData()) == DLCI);
        REQUIRE(frame.isComplete(frame.getSerData()) == false);


@@ 75,7 75,7 @@ TEST_CASE("TS0170 frame")
        std::vector<uint8_t> tempFrame{0xf9, 0x09, 0xef, 0x09, 0x41, 0x54, 0x0d, 0x35, 0xf9};
        auto DLCI = 2;

        TS0710_Frame frame(tempFrame);
        CellularMuxFrame frame(tempFrame);

        REQUIRE(frame.getFrameDLCI(frame.getSerData()) == DLCI);
        REQUIRE(frame.isComplete(frame.getSerData()) == false);

M module-services/service-cellular/CellularServiceAPI.cpp => module-services/service-cellular/CellularServiceAPI.cpp +3 -3
@@ 6,7 6,7 @@
#include "service-cellular/ServiceCellular.hpp"

#include <MessageType.hpp>
#include <Modem/TS0710/TS0710.h>
#include <modem/mux/CellularMux.h>
#include <PhoneNumber.hpp>
#include <Service/Common.hpp>
#include <bsp/cellular/bsp_cellular.hpp>


@@ 185,7 185,7 @@ bool CellularServiceAPI::GetFirmwareVersion(sys::Service *serv, std::string &res
    return false;
}

bool CellularServiceAPI::GetChannel(sys::Service *serv, TS0710::Channel channel)
bool CellularServiceAPI::GetChannel(sys::Service *serv, CellularMux::Channel channel)
{
    std::shared_ptr<CellularGetChannelMessage> msg = std::make_shared<CellularGetChannelMessage>(channel);
    return serv->bus.sendUnicast(std::move(msg), ServiceCellular::serviceName);


@@ 193,7 193,7 @@ bool CellularServiceAPI::GetChannel(sys::Service *serv, TS0710::Channel channel)

bool CellularServiceAPI::GetDataChannel(sys::Service *serv)
{
    return GetChannel(serv, TS0710::Channel::Data);
    return GetChannel(serv, CellularMux::Channel::Data);
}

bool CellularServiceAPI::GetCSQ(sys::Service *serv, std::string &response)

M module-services/service-cellular/CellularUrcHandler.cpp => module-services/service-cellular/CellularUrcHandler.cpp +1 -1
@@ 133,7 133,7 @@ void CellularUrcHandler::Handle(Qind &urc)
        std::string httpSuccess = "0";
        if (urc.getFotaStage() == Qind::FotaStage::HTTPEND && urc.getFotaParameter() == httpSuccess) {
            LOG_DEBUG("Fota UPDATE, switching to AT mode");
            cellularService.cmux->setMode(TS0710::Mode::AT);
            cellularService.cmux->setMode(CellularMux::Mode::AT);
            urc.setHandled(true);
        }
    }

M module-services/service-cellular/NetworkSettings.cpp => module-services/service-cellular/NetworkSettings.cpp +13 -13
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "NetworkSettings.hpp"


@@ 8,7 8,7 @@

std::string NetworkSettings::getCurrentOperator() const
{
    auto channel = cellularService.cmux->get(TS0710::Channel::Commands);
    auto channel = cellularService.cmux->get(CellularMux::Channel::Commands);
    if (channel) {
        at::Cmd buildCmd = at::factory(at::AT::COPS) + "?";
        auto resp        = channel->cmd(buildCmd);


@@ 26,7 26,7 @@ std::string NetworkSettings::getCurrentOperator() const
std::vector<std::string> NetworkSettings::scanOperators(bool fullInfoList)
{
    std::vector<std::string> operatorNames;
    auto channel = cellularService.cmux->get(TS0710::Channel::Commands);
    auto channel = cellularService.cmux->get(CellularMux::Channel::Commands);
    if (channel) {
        at::Cmd buildCmd = at::factory(at::AT::COPS) + "=?";



@@ 75,7 75,7 @@ std::vector<std::string> NetworkSettings::scanOperators(bool fullInfoList)

bool NetworkSettings::setOperatorAutoSelect()
{
    auto channel = cellularService.cmux->get(TS0710::Channel::Commands);
    auto channel = cellularService.cmux->get(CellularMux::Channel::Commands);
    if (!channel) {
        return false;
    }


@@ 89,7 89,7 @@ bool NetworkSettings::setOperator(at::response::cops::CopsMode mode,
                                  at::response::cops::NameFormat format,
                                  const std::string &name)
{
    auto channel = cellularService.cmux->get(TS0710::Channel::Commands);
    auto channel = cellularService.cmux->get(CellularMux::Channel::Commands);
    if (!channel) {
        return false;
    }


@@ 103,7 103,7 @@ bool NetworkSettings::setOperator(at::response::cops::CopsMode mode,

at::Result::Code NetworkSettings::getPreferredVoiceDomain(VoiceDomainPreference &pref)
{
    auto channel = cellularService.cmux->get(TS0710::Channel::Commands);
    auto channel = cellularService.cmux->get(CellularMux::Channel::Commands);
    if (!channel) {
        return at::Result::Code::ERROR;
    }


@@ 120,7 120,7 @@ at::Result::Code NetworkSettings::getPreferredVoiceDomain(VoiceDomainPreference 

at::Result::Code NetworkSettings::setPreferredVoiceDomain(VoiceDomainPreference pref)
{
    auto channel = cellularService.cmux->get(TS0710::Channel::Commands);
    auto channel = cellularService.cmux->get(CellularMux::Channel::Commands);
    if (!channel) {
        return at::Result::Code::ERROR;
    }


@@ 132,7 132,7 @@ at::Result::Code NetworkSettings::setPreferredVoiceDomain(VoiceDomainPreference 

at::Result::Code NetworkSettings::getPreferredSMSDomain(SMSDomainPreference &pref)
{
    auto channel = cellularService.cmux->get(TS0710::Channel::Commands);
    auto channel = cellularService.cmux->get(CellularMux::Channel::Commands);
    if (!channel) {
        return at::Result::Code::ERROR;
    }


@@ 149,7 149,7 @@ at::Result::Code NetworkSettings::getPreferredSMSDomain(SMSDomainPreference &pre

at::Result::Code NetworkSettings::setPreferredSMSDomain(SMSDomainPreference pref)
{
    auto channel = cellularService.cmux->get(TS0710::Channel::Commands);
    auto channel = cellularService.cmux->get(CellularMux::Channel::Commands);
    if (!channel) {
        return at::Result::Code::ERROR;
    }


@@ 162,7 162,7 @@ at::Result::Code NetworkSettings::setPreferredSMSDomain(SMSDomainPreference pref
at::Result::Code NetworkSettings::setIMSState(at::response::qcfg_ims::IMSState state)
{
    std::vector<std::string> operatorNames;
    auto channel = cellularService.cmux->get(TS0710::Channel::Commands);
    auto channel = cellularService.cmux->get(CellularMux::Channel::Commands);
    if (!channel) {
        return at::Result::Code::ERROR;
    }


@@ 175,7 175,7 @@ std::optional<std::pair<at::response::qcfg_ims::IMSState, at::response::qcfg_ims
    getIMSState()
{
    std::vector<std::string> operatorNames;
    auto channel = cellularService.cmux->get(TS0710::Channel::Commands);
    auto channel = cellularService.cmux->get(CellularMux::Channel::Commands);
    if (channel) {

        at::Cmd buildCmd = at::factory(at::AT::QCFG_IMS);


@@ 209,7 209,7 @@ at::Result::Code NetworkSettings::setVoLTEState(VoLTEState state)
     * 3) Reboot
     */

    auto channel = cellularService.cmux->get(TS0710::Channel::Commands);
    auto channel = cellularService.cmux->get(CellularMux::Channel::Commands);
    if (!channel) {
        return at::Result::Code::ERROR;
    }


@@ 250,7 250,7 @@ VoLTEState NetworkSettings::getVoLTEState()
std::string NetworkSettings::printVoLTEDebug()
{

    auto channel = cellularService.cmux->get(TS0710::Channel::Commands);
    auto channel = cellularService.cmux->get(CellularMux::Channel::Commands);
    if (channel) {
        auto resp = channel->cmd("AT+QVOLTEDBG");
        if (resp.code == at::Result::Code::OK) {

M module-services/service-cellular/PacketData.cpp => module-services/service-cellular/PacketData.cpp +1 -1
@@ 106,7 106,7 @@ namespace packet_data

    PDPContext::PDPContext(ServiceCellular &cellularService) : cellularService(cellularService)
    {
        channel = cellularService.cmux->get(TS0710::Channel::Commands);
        channel = cellularService.cmux->get(CellularMux::Channel::Commands);
    }

    std::shared_ptr<APN::Config> PDPContext::getConfiguration(std::uint8_t contextId)

M module-services/service-cellular/PacketData.hpp => module-services/service-cellular/PacketData.hpp +1 -2
@@ 5,7 5,6 @@

#include <string>
#include <unordered_map>
#include "PacketData.hpp"

#include "service-cellular/PacketDataTypes.hpp"
#include "service-cellular/ServiceCellular.hpp"


@@ 34,7 33,7 @@ namespace packet_data

      private:
        ServiceCellular &cellularService;
        DLC_channel *channel = nullptr;
        DLCChannel *channel = nullptr;

      public:
        explicit PDPContext(ServiceCellular &cellularService);

M module-services/service-cellular/QMBNManager.hpp => module-services/service-cellular/QMBNManager.hpp +3 -2
@@ 5,6 5,7 @@

#include "Result.hpp"
#include "service-cellular/ServiceCellular.hpp"

namespace nv_paths
{



@@ 53,10 54,10 @@ namespace at
class QMBNManager
{
  private:
    DLC_channel *channel = nullptr;
    DLCChannel *channel = nullptr;

  public:
    explicit QMBNManager(DLC_channel *channel) : channel(channel)
    explicit QMBNManager(DLCChannel *channel) : channel(channel)
    {}

    at::Result::Code list(std::vector<at::response::qmbncfg::MBNConfig> &ret);

M module-services/service-cellular/ServiceCellular.cpp => module-services/service-cellular/ServiceCellular.cpp +86 -87
@@ 12,7 12,7 @@
#include "service-cellular/State.hpp"
#include "service-cellular/USSD.hpp"
#include "service-cellular/MessageConstants.hpp"
#include <service-cellular/connection-manager/ConnectionManagerCellularCommands.hpp>
#include "service-cellular/connection-manager/ConnectionManagerCellularCommands.hpp"
#include "SimCard.hpp"
#include "NetworkSettings.hpp"
#include "service-cellular/RequestFactory.hpp"


@@ 27,18 27,16 @@
#include <Common/Common.hpp>
#include <Common/Query.hpp>
#include <MessageType.hpp>
#include <Modem/ATCommon.hpp>
#include <Modem/ATCommon.hpp>
#include <Modem/ATParser.hpp>
#include <Modem/TS0710/DLC_channel.h>
#include <Modem/TS0710/TS0710.h>
#include <Modem/TS0710/TS0710_START.h>
#include <modem/ATCommon.hpp>
#include <modem/ATParser.hpp>
#include <modem/mux/DLCChannel.h>
#include <modem/mux/CellularMux.h>
#include <NotificationsRecord.hpp>
#include <PhoneNumber.hpp>
#include <Result.hpp>
#include <Service/Message.hpp>
#include <Service/Service.hpp>
#include <module-sys/Timers/TimerFactory.hpp>
#include <Timers/TimerFactory.hpp>
#include <Tables/CalllogTable.hpp>
#include <Tables/Record.hpp>
#include <Utils.hpp>


@@ 57,9 55,9 @@
#include <common_data/EventStore.hpp>
#include <country.hpp>
#include <log/log.hpp>
#include <module-cellular/at/UrcFactory.hpp>
#include <module-db/queries/messages/sms/QuerySMSSearchByType.hpp>
#include <module-db/queries/notifications/QueryNotificationsIncrement.hpp>
#include <at/UrcFactory.hpp>
#include <queries/messages/sms/QuerySMSSearchByType.hpp>
#include <queries/notifications/QueryNotificationsIncrement.hpp>
#include <projdefs.h>
#include <service-antenna/AntennaMessage.hpp>
#include <service-antenna/AntennaServiceAPI.hpp>


@@ 80,8 78,8 @@
#include <ucs2/UCS2.hpp>
#include <utf8/UTF8.hpp>

#include <module-db/queries/messages/sms/QuerySMSUpdate.hpp>
#include <module-db/queries/messages/sms/QuerySMSAdd.hpp>
#include <queries/messages/sms/QuerySMSUpdate.hpp>
#include <queries/messages/sms/QuerySMSAdd.hpp>

#include <algorithm>
#include <bits/exception.h>


@@ 94,7 92,7 @@
#include <vector>
#include "checkSmsCenter.hpp"
#include <service-desktop/Constants.hpp>
#include <module-utils/gsl/gsl_util>
#include <gsl/gsl_util>
#include <ticks.hpp>

const char *ServiceCellular::serviceName = "ServiceCellular";


@@ 270,7 268,7 @@ void ServiceCellular::SleepTimerHandler()

    if (!ongoingCall.isValid() && state.get() == cellular::State::ST::Ready &&
        timeOfInactivity >= constants::enterSleepModeTime.count()) {
        cmux->EnterSleepMode();
        cmux->enterSleepMode();
        cpuSentinel->ReleaseMinimumFrequency();
    }
}


@@ 302,7 300,7 @@ sys::ReturnCodes ServiceCellular::InitHandler()
    auto sentinelRegistrationMsg = std::make_shared<sys::SentinelRegistrationMessage>(cpuSentinel);
    bus.sendUnicast(sentinelRegistrationMsg, service::name::system_manager);

    cmux->RegisterCellularDevice();
    cmux->registerCellularDevice();

    return sys::ReturnCodes::Success;
}


@@ 324,11 322,11 @@ sys::ReturnCodes ServiceCellular::SwitchPowerModeHandler(const sys::ServicePower

    switch (mode) {
    case sys::ServicePowerMode ::Active:
        cmux->ExitSleepMode();
        cmux->exitSleepMode();
        break;
    case sys::ServicePowerMode ::SuspendToRAM:
    case sys::ServicePowerMode ::SuspendToNVM:
        cmux->EnterSleepMode();
        cmux->enterSleepMode();
        break;
    }



@@ 459,7 457,7 @@ void ServiceCellular::registerMessageHandlers()
    connect(typeid(sdesktop::developerMode::DeveloperModeRequest), [&](sys::Message *request) -> sys::MessagePointer {
        auto msg = static_cast<sdesktop::developerMode::DeveloperModeRequest *>(request);
        if (typeid(*msg->event.get()) == typeid(sdesktop::developerMode::CellularHotStartEvent)) {
            cmux->CloseChannels();
            cmux->closeChannels();
            ///> change state - simulate hot start
            handle_power_up_request();
        }


@@ 475,7 473,7 @@ void ServiceCellular::registerMessageHandlers()
            bus.sendUnicast(std::move(message), service::name::service_desktop);
        }
        if (typeid(*msg->event.get()) == typeid(sdesktop::developerMode::ATResponseEvent)) {
            auto channel = cmux->get(TS0710::Channel::Commands);
            auto channel = cmux->get(CellularMux::Channel::Commands);
            assert(channel);
            auto handler = cellular::RawATHandler(*channel);
            return handler.handle(msg);


@@ 658,7 656,7 @@ bool ServiceCellular::resetCellularModule(ResetType type)
{
    LOG_DEBUG("Cellular modem reset. Type %d", static_cast<int>(type));

    auto channel = cmux->get(TS0710::Channel::Commands);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    if (!channel) {
        LOG_ERROR("Bad channel");
        return false;


@@ 672,12 670,12 @@ bool ServiceCellular::resetCellularModule(ResetType type)
        LOG_ERROR("Cellular modem reset failed.");
        return false;
    case ResetType::PowerCycle:
        cmux->TurnOffModem();
        cmux->TurnOnModem();
        cmux->turnOffModem();
        cmux->turnOnModem();
        isAfterForceReboot = true;
        return true;
    case ResetType::HardReset:
        cmux->ResetModem();
        cmux->resetModem();
        isAfterForceReboot = true;
        return true;
    }


@@ 778,7 776,7 @@ bool ServiceCellular::handle_wait_for_start_permission()

bool ServiceCellular::handle_power_up_request()
{
    cmux->SelectAntenna(bsp::cellular::antenna::lowBand);
    cmux->selectAntenna(bsp::cellular::antenna::lowBand);
    switch (board) {
    case bsp::Board::T4:
        state.set(this, State::ST::StatusCheck);


@@ 801,14 799,14 @@ bool ServiceCellular::handle_power_up_procedure()
    switch (board) {
    case bsp::Board::T4: {
        LOG_DEBUG("T4 - cold start");
        cmux->TurnOnModem();
        cmux->turnOnModem();
        // wait for status pin change to change state
        break;
    }
    case bsp::Board::T3: {
        // check baud once to determine if it's already turned on
        auto ret = cmux->BaudDetectOnce();
        if (ret == TS0710::ConfState::Success) {
        auto ret = cmux->baudDetectOnce();
        if (ret == CellularMux::ConfState::Success) {
            // it's on aka hot start.
            LOG_DEBUG("T3 - hot start");
            state.set(this, State::ST::CellularConfProcedure);


@@ 817,7 815,7 @@ bool ServiceCellular::handle_power_up_procedure()
        else {
            // it's off aka cold start
            LOG_DEBUG("T3 - cold start");
            cmux->TurnOnModem();
            cmux->turnOnModem();
            // if it's T3, then wait for status pin to become active, to align its starting position with T4
            vTaskDelay(pdMS_TO_TICKS(8000));
            state.set(this, State::ST::PowerUpInProgress);


@@ 827,8 825,8 @@ bool ServiceCellular::handle_power_up_procedure()
    case bsp::Board::Linux: {
        // it is basically the same as T3
        // check baud once to determine if it's already turned on
        auto ret = cmux->BaudDetectOnce();
        if (ret == TS0710::ConfState::Success) {
        auto ret = cmux->baudDetectOnce();
        if (ret == CellularMux::ConfState::Success) {
            // it's on aka hot start.
            LOG_DEBUG("Linux - hot start");
            state.set(this, State::ST::CellularConfProcedure);


@@ 868,8 866,8 @@ bool ServiceCellular::handle_power_up_in_progress_procedure(void)

bool ServiceCellular::handle_baud_detect()
{
    auto ret = cmux->BaudDetectProcedure();
    if (ret == TS0710::ConfState::Success) {
    auto ret = cmux->baudDetectProcedure();
    if (ret == CellularMux::ConfState::Success) {
        state.set(this, cellular::State::ST::CellularConfProcedure);
        return true;
    }


@@ 908,8 906,9 @@ bool ServiceCellular::handle_power_down()
{
    LOG_DEBUG("Powered Down");
    isAfterForceReboot = true;

    cmux.reset();
    cmux = std::make_unique<TS0710>(PortSpeed_e::PS460800, this);
    cmux = std::make_unique<CellularMux>(PortSpeed_e::PS460800, this);

    return true;
}


@@ 917,8 916,8 @@ bool ServiceCellular::handle_power_down()
bool ServiceCellular::handle_start_conf_procedure()
{
    // Start configuration procedure, if it's first run modem will be restarted
    auto confRet = cmux->ConfProcedure();
    if (confRet == TS0710::ConfState::Success) {
    auto confRet = cmux->confProcedure();
    if (confRet == CellularMux::ConfState::Success) {
        state.set(this, State::ST::AudioConfigurationProcedure);
        return true;
    }


@@ 928,8 927,8 @@ bool ServiceCellular::handle_start_conf_procedure()

bool ServiceCellular::handle_audio_conf_procedure()
{
    auto audioRet = cmux->AudioConfProcedure();
    if (audioRet == TS0710::ConfState::Success) {
    auto audioRet = cmux->audioConfProcedure();
    if (audioRet == CellularMux::ConfState::Success) {
        auto cmd = at::factory(at::AT::IPR) + std::to_string(ATPortSpeeds_text[cmux->getStartParams().PortSpeed]);
        LOG_DEBUG("Setting baudrate %i baud", ATPortSpeeds_text[cmux->getStartParams().PortSpeed]);
        if (!cmux->getParser()->cmd(cmd)) {


@@ 940,12 939,12 @@ bool ServiceCellular::handle_audio_conf_procedure()
        cmux->getCellular()->setSpeed(ATPortSpeeds_text[cmux->getStartParams().PortSpeed]);
        vTaskDelay(1000);

        if (cmux->StartMultiplexer() == TS0710::ConfState::Success) {
        if (cmux->startMultiplexer() == CellularMux::ConfState::Success) {

            LOG_DEBUG("[ServiceCellular] Modem is fully operational");

            // open channel - notifications
            DLC_channel *notificationsChannel = cmux->get(TS0710::Channel::Notifications);
            DLCChannel *notificationsChannel = cmux->get(CellularMux::Channel::Notifications);
            if (notificationsChannel != nullptr) {
                LOG_DEBUG("Setting up notifications callback");
                notificationsChannel->setCallback(notificationCallback);


@@ 974,7 973,7 @@ bool ServiceCellular::handle_audio_conf_procedure()
            return false;
        }
    }
    else if (audioRet == TS0710::ConfState::Failure) {
    else if (audioRet == CellularMux::ConfState::Failure) {
        /// restart
        state.set(this, State::ST::AudioConfigurationProcedure);
        return true;


@@ 1299,7 1298,7 @@ auto ServiceCellular::sendSMS(SMSRecord record) -> bool
    auto commandTimeout                 = at::factory(at::AT::CMGS).getTimeout();
    constexpr uint32_t singleMessageLen = msgConstants::singleMessageMaxLen;
    bool result                         = false;
    auto channel                        = cmux->get(TS0710::Channel::Commands);
    auto channel                        = cmux->get(CellularMux::Channel::Commands);
    auto receiver                       = record.number.getEntered();
    if (channel) {
        if (!channel->cmd(at::AT::SET_SMS_TEXT_MODE_UCS2)) {


@@ 1316,7 1315,7 @@ auto ServiceCellular::sendSMS(SMSRecord record) -> bool
            std::string body         = UCS2(UTF8(receiver)).str();
            std::string suffix       = "\"";
            std::string command_data = command + body + suffix;
            if (cmux->CheckATCommandPrompt(channel->SendCommandPrompt(command_data.c_str(), 1, commandTimeout))) {
            if (cmux->checkATCommandPrompt(channel->sendCommandPrompt(command_data.c_str(), 1, commandTimeout))) {

                if (channel->cmd((UCS2(record.body).str() + "\032").c_str(), commandTimeout)) {
                    result = true;


@@ 1341,7 1340,7 @@ auto ServiceCellular::sendSMS(SMSRecord record) -> bool
                result = false;
            }
            else {
                auto channel = cmux->get(TS0710::Channel::Commands);
                auto channel = cmux->get(CellularMux::Channel::Commands);

                for (uint32_t i = 0; i < messagePartsCount; i++) {



@@ 1354,7 1353,7 @@ auto ServiceCellular::sendSMS(SMSRecord record) -> bool
                    std::string command(at::factory(at::AT::QCMGS) + UCS2(UTF8(receiver)).str() + "\",120," +
                                        std::to_string(i + 1) + "," + std::to_string(messagePartsCount));

                    if (cmux->CheckATCommandPrompt(channel->SendCommandPrompt(command.c_str(), 1, commandTimeout))) {
                    if (cmux->checkATCommandPrompt(channel->sendCommandPrompt(command.c_str(), 1, commandTimeout))) {
                        // prompt sign received, send data ended by "Ctrl+Z"
                        if (channel->cmd(UCS2(messagePart).str() + "\032", commandTimeout, 2)) {
                            result = true;


@@ 1400,7 1399,7 @@ auto ServiceCellular::receiveSMS(std::string messageNumber) -> bool

    auto retVal = true;

    auto channel = cmux->get(TS0710::Channel::Commands);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    if (channel == nullptr) {
        retVal = false;
        return retVal;


@@ 1524,7 1523,7 @@ auto ServiceCellular::receiveSMS(std::string messageNumber) -> bool

bool ServiceCellular::getOwnNumber(std::string &destination)
{
    auto ret = cmux->get(TS0710::Channel::Commands)->cmd(at::AT::CNUM);
    auto ret = cmux->get(CellularMux::Channel::Commands)->cmd(at::AT::CNUM);

    if (ret) {
        auto begin = ret.response[0].find(',');


@@ 1551,7 1550,7 @@ bool ServiceCellular::getOwnNumber(std::string &destination)

bool ServiceCellular::getIMSI(std::string &destination, bool fullNumber)
{
    auto ret = cmux->get(TS0710::Channel::Commands)->cmd(at::AT::CIMI);
    auto ret = cmux->get(CellularMux::Channel::Commands)->cmd(at::AT::CIMI);

    if (ret) {
        if (fullNumber) {


@@ 1574,7 1573,7 @@ bool ServiceCellular::getIMSI(std::string &destination, bool fullNumber)
std::vector<std::string> ServiceCellular::getNetworkInfo(void)
{
    std::vector<std::string> data;
    auto channel = cmux->get(TS0710::Channel::Commands);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    if (channel) {
        auto resp = channel->cmd(at::AT::CSQ);
        if (resp.code == at::Result::Code::OK) {


@@ 1612,13 1611,13 @@ std::vector<std::string> ServiceCellular::getNetworkInfo(void)
    return data;
}

std::vector<std::string> get_last_AT_error(DLC_channel *channel)
std::vector<std::string> get_last_AT_error(DLCChannel *channel)
{
    auto ret = channel->cmd(at::AT::CEER);
    return std::move(ret.response);
}

void log_last_AT_error(DLC_channel *channel)
void log_last_AT_error(DLCChannel *channel)
{
    std::vector<std::string> atErrors(get_last_AT_error(channel));
    int i = 1;


@@ 1628,7 1627,7 @@ void log_last_AT_error(DLC_channel *channel)
    }
}

bool is_SIM_detection_enabled(DLC_channel *channel)
bool is_SIM_detection_enabled(DLCChannel *channel)
{
    auto ret = channel->cmd(at::AT::SIM_DET);
    if (ret) {


@@ 1644,7 1643,7 @@ bool is_SIM_detection_enabled(DLC_channel *channel)
    return false;
}

bool enable_SIM_detection(DLC_channel *channel)
bool enable_SIM_detection(DLCChannel *channel)
{
    auto ret = channel->cmd(at::AT::SIM_DET_ON);
    if (!ret) {


@@ 1654,7 1653,7 @@ bool enable_SIM_detection(DLC_channel *channel)
    return true;
}

bool is_SIM_status_enabled(DLC_channel *channel)
bool is_SIM_status_enabled(DLCChannel *channel)
{
    auto ret = channel->cmd(at::AT::QSIMSTAT);
    if (ret) {


@@ 1670,7 1669,7 @@ bool is_SIM_status_enabled(DLC_channel *channel)
    return false;
}

bool enable_SIM_status(DLC_channel *channel)
bool enable_SIM_status(DLCChannel *channel)
{
    auto ret = channel->cmd(at::AT::SIMSTAT_ON);
    if (!ret) {


@@ 1680,7 1679,7 @@ bool enable_SIM_status(DLC_channel *channel)
    return true;
}

void save_SIM_detection_status(DLC_channel *channel)
void save_SIM_detection_status(DLCChannel *channel)
{
    auto ret = channel->cmd(at::AT::STORE_SETTINGS_ATW);
    if (!ret) {


@@ 1688,7 1687,7 @@ void save_SIM_detection_status(DLC_channel *channel)
    }
}

bool sim_check_hot_swap(DLC_channel *channel)
bool sim_check_hot_swap(DLCChannel *channel)
{
    assert(channel);
    bool reboot_needed = false;


@@ 1710,7 1709,7 @@ bool sim_check_hot_swap(DLC_channel *channel)

bool ServiceCellular::handle_sim_sanity_check()
{
    auto ret = sim_check_hot_swap(cmux->get(TS0710::Channel::Commands));
    auto ret = sim_check_hot_swap(cmux->get(CellularMux::Channel::Commands));
    if (ret) {
        state.set(this, State::ST::ModemOn);
        bsp::cellular::sim::simSelect();


@@ 1728,8 1727,8 @@ bool ServiceCellular::handle_select_sim()
    bsp::cellular::sim::simSelect();
    bsp::cellular::sim::hotSwapTrigger();
#if defined(TARGET_Linux)
    DLC_channel *channel = cmux->get(TS0710::Channel::Commands);
    auto ret             = channel->cmd(at::AT::QSIMSTAT);
    DLCChannel *channel = cmux->get(CellularMux::Channel::Commands);
    auto ret            = channel->cmd(at::AT::QSIMSTAT);
    if (!ret) {
        LOG_FATAL("Cant check sim stat status");
    }


@@ 1760,10 1759,10 @@ bool ServiceCellular::handle_select_sim()

bool ServiceCellular::handle_modem_on()
{
    auto channel = cmux->get(TS0710::Channel::Commands);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    channel->cmd("AT+CCLK?");
    // inform host ap ready
    cmux->InformModemHostWakeup();
    cmux->informModemHostWakeup();
    state.set(this, State::ST::URCReady);
    LOG_DEBUG("AP ready");
    return true;


@@ 1771,7 1770,7 @@ bool ServiceCellular::handle_modem_on()

bool ServiceCellular::handle_URCReady()
{
    auto channel = cmux->get(TS0710::Channel::Commands);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    bool ret     = true;
    if (isSettingsAutomaticTimeSyncEnabled()) {
        ret = ret && channel->cmd(at::AT::ENABLE_TIME_ZONE_UPDATE);


@@ 1785,7 1784,7 @@ bool ServiceCellular::handle_URCReady()

bool ServiceCellular::handle_sim_init()
{
    auto channel = cmux->get(TS0710::Channel::Commands);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    if (channel == nullptr) {
        LOG_ERROR("Cant configure sim! no Commands channel!");
        state.set(this, State::ST::Failed);


@@ 1807,7 1806,7 @@ bool ServiceCellular::handle_sim_init()

bool ServiceCellular::handleTextMessagesInit()
{
    auto channel = cmux->get(TS0710::Channel::Commands);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    if (channel == nullptr) {
        LOG_ERROR("Cant configure sim! no Commands channel!");
        return false;


@@ 1866,7 1865,7 @@ void ServiceCellular::onSMSReceived()

bool ServiceCellular::receiveAllMessages()
{
    auto channel = cmux->get(TS0710::Channel::Commands);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    if (channel == nullptr) {
        return false;
    }


@@ 1915,7 1914,7 @@ bool ServiceCellular::handle_ready()

bool ServiceCellular::SetScanMode(std::string mode)
{
    auto channel = cmux->get(TS0710::Channel::Commands);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    if (channel) {
        auto command = at::factory(at::AT::SET_SCANMODE);



@@ 1929,7 1928,7 @@ bool ServiceCellular::SetScanMode(std::string mode)

std::string ServiceCellular::GetScanMode(void)
{
    auto channel = cmux->get(TS0710::Channel::Commands);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    if (channel) {

        auto resp = channel->cmd(at::AT::GET_SCANMODE);


@@ 1949,7 1948,7 @@ std::string ServiceCellular::GetScanMode(void)

bool ServiceCellular::transmitDtmfTone(uint32_t digit)
{
    auto channel = cmux->get(TS0710::Channel::Commands);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    at::Result resp;
    if (channel) {
        auto command           = at::factory(at::AT::QLDTMF);


@@ 1967,7 1966,7 @@ void ServiceCellular::handle_CellularGetChannelMessage()
{
    connect(CellularGetChannelMessage(), [&](sys::Message *req) {
        auto getChannelMsg = static_cast<CellularGetChannelMessage *>(req);
        LOG_DEBUG("Handle request for channel: %s", TS0710::name(getChannelMsg->dataChannel).c_str());
        LOG_DEBUG("Handle request for channel: %s", CellularMux::name(getChannelMsg->dataChannel).c_str());
        std::shared_ptr<CellularGetChannelResponseMessage> channelResponsMessage =
            std::make_shared<CellularGetChannelResponseMessage>(cmux->get(getChannelMsg->dataChannel));
        LOG_DEBUG("channel ptr: %p", channelResponsMessage->dataChannelPtr);


@@ 1978,7 1977,7 @@ void ServiceCellular::handle_CellularGetChannelMessage()
bool ServiceCellular::handle_status_check(void)
{
    LOG_INFO("Checking modem status.");
    auto modemActive = cmux->IsModemActive();
    auto modemActive = cmux->isModemActive();
    if (modemActive) {
        // modem is already turned on, call configutarion procedure
        LOG_INFO("Modem is already turned on.");


@@ 2016,7 2015,7 @@ void ServiceCellular::handleStateTimer(void)
void ServiceCellular::handle_power_state_change()
{
    nextPowerStateChangeAwaiting = false;
    auto modemActive             = cmux->IsModemActive();
    auto modemActive             = cmux->isModemActive();

    if (nextPowerState == State::PowerState::On) {
        if (state.get() == State::ST::PowerDownWaiting) {


@@ 2051,7 2050,7 @@ void ServiceCellular::handle_power_state_change()
        }
        else {
            LOG_INFO("Modem Power DOWN.");
            cmux->TurnOffModem();
            cmux->turnOffModem();
            state.set(this, State::ST::PowerDownWaiting);
        }
    }


@@ 2061,7 2060,7 @@ bool ServiceCellular::handleUSSDRequest(CellularUSSDMessage::RequestType request
{
    constexpr uint32_t commandTimeout = 120000;

    auto channel = cmux->get(TS0710::Channel::Commands);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    if (channel != nullptr) {
        if (requestType == CellularUSSDMessage::RequestType::pullSesionRequest) {
            channel->cmd(at::AT::SMS_GSM);


@@ 2260,7 2259,7 @@ void ServiceCellular::apnListChanged(const std::string &value)
auto ServiceCellular::handleCellularAnswerIncomingCallMessage(CellularMessage *msg)
    -> std::shared_ptr<CellularResponseMessage>
{
    auto channel = cmux->get(TS0710::Channel::Commands);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    auto ret     = false;
    if (channel) {
        // TODO alek: check if your request isn't for 5 sec when you wait in command for 90000, it's exclusivelly


@@ 2279,7 2278,7 @@ auto ServiceCellular::handleCellularAnswerIncomingCallMessage(CellularMessage *m
auto ServiceCellular::handleCellularCallRequestMessage(CellularCallRequestMessage *msg)
    -> std::shared_ptr<CellularResponseMessage>
{
    auto channel = cmux->get(TS0710::Channel::Commands);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    if (channel == nullptr) {
        return std::make_shared<CellularResponseMessage>(false);
    }


@@ 2300,7 2299,7 @@ auto ServiceCellular::handleCellularCallRequestMessage(CellularCallRequestMessag

void ServiceCellular::handleCellularHangupCallMessage(CellularHangupCallMessage *msg)
{
    auto channel = cmux->get(TS0710::Channel::Commands);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    LOG_INFO("CellularHangupCall");
    if (channel) {
        if (channel->cmd(at::AT::ATH)) {


@@ 2345,7 2344,7 @@ auto ServiceCellular::handleDBQueryResponseMessage(db::QueryResponse *msg) -> st
auto ServiceCellular::handleCellularListCallsMessage(CellularMessage *msg) -> std::shared_ptr<sys::ResponseMessage>
{
    at::cmd::CLCC cmd;
    auto base = cmux->get(TS0710::Channel::Commands)->cmd(cmd);
    auto base = cmux->get(CellularMux::Channel::Commands)->cmd(cmd);
    if (auto response = cmd.parse(base); response) {
        const auto &data = response.getData();
        auto it          = std::find_if(std::begin(data), std::end(data), [&](const auto &entry) {


@@ 2436,9 2435,9 @@ auto ServiceCellular::handleCellularSelectAntennaMessage(sys::Message *msg) -> s
{
    auto message = static_cast<CellularAntennaRequestMessage *>(msg);

    cmux->SelectAntenna(message->antenna);
    cmux->selectAntenna(message->antenna);
    vTaskDelay(50); // sleep for 50 ms...
    auto actualAntenna  = cmux->GetAntenna();
    auto actualAntenna  = cmux->getAntenna();
    bool changedAntenna = (actualAntenna == message->antenna);

    auto notification = std::make_shared<AntennaChangedMessage>();


@@ 2469,7 2468,7 @@ auto ServiceCellular::handleCellularGetFirmwareVersionMessage(sys::Message *msg)
    -> std::shared_ptr<sys::ResponseMessage>
{
    std::string response;
    auto channel = cmux->get(TS0710::Channel::Commands);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    if (channel) {
        auto resp = channel->cmd(at::AT::QGMR);
        if (resp.code == at::Result::Code::OK) {


@@ 2505,7 2504,7 @@ auto ServiceCellular::handleEVMStatusMessage(sys::Message *msg) -> std::shared_p

auto ServiceCellular::handleCellularGetCsqMessage(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>
{
    auto channel = cmux->get(TS0710::Channel::Commands);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    if (channel) {
        auto modemResponse = channel->cmd(at::AT::CSQ);
        if (modemResponse.code == at::Result::Code::OK) {


@@ 2517,7 2516,7 @@ auto ServiceCellular::handleCellularGetCsqMessage(sys::Message *msg) -> std::sha

auto ServiceCellular::handleCellularGetCregMessage(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>
{
    auto channel = cmux->get(TS0710::Channel::Commands);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    if (channel) {
        auto resp = channel->cmd(at::AT::CREG);
        if (resp.code == at::Result::Code::OK) {


@@ 2529,7 2528,7 @@ auto ServiceCellular::handleCellularGetCregMessage(sys::Message *msg) -> std::sh

auto ServiceCellular::handleCellularGetNwinfoMessage(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>
{
    auto channel = cmux->get(TS0710::Channel::Commands);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    if (channel) {
        auto resp = channel->cmd(at::AT::QNWINFO);
        if (resp.code == at::Result::Code::OK) {


@@ 2541,7 2540,7 @@ auto ServiceCellular::handleCellularGetNwinfoMessage(sys::Message *msg) -> std::

auto ServiceCellular::handleCellularGetAntennaMessage(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>
{
    auto antenna = cmux->GetAntenna();
    auto antenna = cmux->getAntenna();
    return std::make_shared<CellularAntennaResponseMessage>(true, antenna, CellularMessage::Type::GetAntenna);
}
auto ServiceCellular::handleCellularDtmfRequestMessage(sys::Message *msg) -> std::shared_ptr<sys::ResponseMessage>


@@ 2640,7 2639,7 @@ auto ServiceCellular::handleUrcIncomingNotification(sys::Message *msg) -> std::s
{
    // when handling URC, the CPU frequency does not go below a certain level
    cpuSentinel->HoldMinimumFrequency(bsp::CpuFrequencyHz::Level_4);
    cmux->ExitSleepMode();
    cmux->exitSleepMode();
    return std::make_shared<CellularResponseMessage>(true);
}



@@ 2713,7 2712,7 @@ auto ServiceCellular::isIncommingCallAllowed() -> bool

auto ServiceCellular::hangUpCall() -> bool
{
    auto channel = cmux->get(TS0710::Channel::Commands);
    auto channel = cmux->get(CellularMux::Channel::Commands);
    if (channel) {
        if (channel->cmd(at::factory(at::AT::ATH))) {
            return true;

M module-services/service-cellular/SimCard.cpp => module-services/service-cellular/SimCard.cpp +7 -7
@@ 25,7 25,7 @@ SimCardResult SimCard::convertErrorFromATResult(const at::Result atres) const

std::optional<at::response::qpinc::AttemptsCounters> SimCard::getAttemptsCounters(const std::string &type) const
{
    auto channel = cellularService.cmux->get(TS0710::Channel::Commands);
    auto channel = cellularService.cmux->get(CellularMux::Channel::Commands);
    if (channel) {
        auto resp = channel->cmd(at::factory(at::AT::QPINC) + "\"" + type + "\"");
        at::response::qpinc::AttemptsCounters ret;


@@ 41,7 41,7 @@ SimCardResult SimCard::supplyPin(const std::string pin) const
{
    if (auto pc = getAttemptsCounters(); pc) {
        if (pc.value().PinCounter > 0) {
            if (auto channel = cellularService.cmux->get(TS0710::Channel::Commands); channel) {
            if (auto channel = cellularService.cmux->get(CellularMux::Channel::Commands); channel) {
                auto resp = channel->cmd(at::factory(at::AT::CPIN) + "\"" + pin + "\"");

                if (resp.code == at::Result::Code::OK) {


@@ 68,7 68,7 @@ SimCardResult SimCard::supplyPuk(const std::string puk, const std::string pin) c
{
    if (auto pc = getAttemptsCounters(); pc) {
        if (pc.value().PukCounter != 0) {
            if (auto channel = cellularService.cmux->get(TS0710::Channel::Commands); channel) {
            if (auto channel = cellularService.cmux->get(CellularMux::Channel::Commands); channel) {
                auto resp = channel->cmd(at::factory(at::AT::CPIN) + "\"" + puk + "\"" + ",\"" + pin + "\"");
                if (resp.code == at::Result::Code::OK) {
                    return SimCardResult::OK;


@@ 88,7 88,7 @@ SimCardResult SimCard::supplyPuk(const std::string puk, const std::string pin) c

bool SimCard::isPinLocked() const
{
    if (auto channel = cellularService.cmux->get(TS0710::Channel::Commands); channel) {
    if (auto channel = cellularService.cmux->get(CellularMux::Channel::Commands); channel) {
        auto resp = channel->cmd(at::factory(at::AT::CLCK) + "\"SC\",2\r");
        int val   = 0;
        if (at::response::parseCLCK(resp, val)) {


@@ 102,7 102,7 @@ SimCardResult SimCard::setPinLock(bool lock, const std::string &pin) const
{
    if (auto pc = getAttemptsCounters(); pc) {
        if (pc.value().PukCounter != 0) {
            auto channel = cellularService.cmux->get(TS0710::Channel::Commands);
            auto channel = cellularService.cmux->get(CellularMux::Channel::Commands);
            if (channel) {
                auto resp =
                    channel->cmd(at::factory(at::AT::CLCK) + "\"SC\"," + (lock ? "1" : "0") + ",\"" + pin + "\"");


@@ 126,7 126,7 @@ SimCardResult SimCard::changePin(const std::string oldPin, const std::string new
{
    if (auto pc = getAttemptsCounters(); pc) {
        if (pc.value().PukCounter != 0) {
            auto channel = cellularService.cmux->get(TS0710::Channel::Commands);
            auto channel = cellularService.cmux->get(CellularMux::Channel::Commands);
            if (channel) {
                auto resp = channel->cmd(at::factory(at::AT::CPWD) + "\"SC\", \"" + oldPin + "\",\"" + newPin + "\"");
                if (resp.code == at::Result::Code::OK) {


@@ 153,7 153,7 @@ std::optional<at::SimState> SimCard::simState() const

std::optional<at::SimState> SimCard::simStateWithMessage(std::string &message) const
{
    if (auto channel = cellularService.cmux->get(TS0710::Channel::Commands); channel) {
    if (auto channel = cellularService.cmux->get(CellularMux::Channel::Commands); channel) {
        auto resp = channel->cmd(at::factory(at::AT::GET_CPIN));
        if (resp.code == at::Result::Code::OK) {
            if (resp.response.size()) {

M module-services/service-cellular/checkSmsCenter.cpp => module-services/service-cellular/checkSmsCenter.cpp +1 -1
@@ 2,7 2,7 @@
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "checkSmsCenter.hpp"
#include "Modem/BaseChannel.hpp"
#include "modem/BaseChannel.hpp"
#include <at/cmd/CSCA.hpp>

[[nodiscard]] bool checkSmsCenter(at::BaseChannel &channel)

M module-services/service-cellular/connection-manager/ConnectionManagerCellularCommands.cpp => module-services/service-cellular/connection-manager/ConnectionManagerCellularCommands.cpp +4 -4
@@ 10,7 10,7 @@
auto ConnectionManagerCellularCommands::disconnectFromNetwork() -> bool
{
    using at::cfun::Functionality;
    auto channel = cellular.cmux->get(TS0710::Channel::Commands);
    auto channel = cellular.cmux->get(CellularMux::Channel::Commands);
    if (channel) {
        auto cmd = at::cmd::CFUN(at::cmd::Modifier::Set);
        cmd.set(Functionality::DisableRF);


@@ 23,7 23,7 @@ auto ConnectionManagerCellularCommands::disconnectFromNetwork() -> bool
auto ConnectionManagerCellularCommands::connectToNetwork() -> bool
{
    using at::cfun::Functionality;
    auto channel = cellular.cmux->get(TS0710::Channel::Commands);
    auto channel = cellular.cmux->get(CellularMux::Channel::Commands);
    if (channel) {
        auto cmd = at::cmd::CFUN(at::cmd::Modifier::Set);
        cmd.set(Functionality::Full);


@@ 37,7 37,7 @@ auto ConnectionManagerCellularCommands::isConnectedToNetwork() -> bool
{

    using at::cfun::Functionality;
    auto channel = cellular.cmux->get(TS0710::Channel::Commands);
    auto channel = cellular.cmux->get(CellularMux::Channel::Commands);
    if (channel) {
        auto cmd      = at::cmd::CFUN(at::cmd::Modifier::Get);
        auto response = channel->cmd(cmd);


@@ 67,7 67,7 @@ auto ConnectionManagerCellularCommands::clearNetworkIndicator() -> bool
auto ConnectionManagerCellularCommands::hangUpOngoingCall() -> bool
{
    if (cellular.ongoingCall.isActive()) {
        auto channel = cellular.cmux->get(TS0710::Channel::Commands);
        auto channel = cellular.cmux->get(CellularMux::Channel::Commands);
        if (channel) {
            if (channel->cmd(at::factory(at::AT::ATH))) {
                cellular.callStateTimer.stop();

M module-services/service-cellular/doc/call_request_handling.puml => module-services/service-cellular/doc/call_request_handling.puml +2 -2
@@ 3,7 3,7 @@ participant ServiceCellular as cellular
participant RequestFactory as factory
participant IRequest as request
participant CellularRequestHandler as handler
participant DLC_channel as channel
participant DLCChannel as channel


?->     cellular + : ""call request""


@@ 40,4 40,4 @@ request -> handler + : Handle(IRequest)
handler->? - : <<specific system actions>>
?<--    cellular -- : ""multicast response""
cellular -> request !! : delete
@enduml
\ No newline at end of file
@enduml

M module-services/service-cellular/doc/call_request_handling.svg => module-services/service-cellular/doc/call_request_handling.svg +10 -10
@@ 1,4 1,4 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="969px" preserveAspectRatio="none" style="width:995px;height:969px;" version="1.1" viewBox="0 0 995 969" width="995px" zoomAndPan="magnify"><defs><filter height="300%" id="f1ke4x5lxerpcl" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="808.0938" style="stroke:#A80036;stroke-width:1.0;" width="10" x="163" y="71.4297"/><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="538.8984" style="stroke:#A80036;stroke-width:1.0;" width="10" x="399" y="100.5625"/><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="116.5313" style="stroke:#A80036;stroke-width:1.0;" width="10" x="632" y="792.125"/><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="29.1328" style="stroke:#A80036;stroke-width:1.0;" width="10" x="772" y="821.2578"/><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="164.6328" style="stroke:#000000;stroke-width:2.0;" width="588" x="99" y="157.6953"/><rect fill="#FFFFFF" height="73.0703" style="stroke:none;stroke-width:1.0;" width="588" x="99" y="249.2578"/><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="148.6641" style="stroke:#000000;stroke-width:2.0;" width="608" x="89" y="336.3281"/><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="75.3984" style="stroke:#000000;stroke-width:2.0;" width="588" x="99" y="402.5938"/><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="148.4688" style="stroke:#000000;stroke-width:2.0;" width="588" x="99" y="498.9922"/><rect fill="#FFFFFF" height="73.0703" style="stroke:none;stroke-width:1.0;" width="588" x="99" y="574.3906"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:5.0,5.0;" x1="168" x2="168" y1="40.2969" y2="926.6563"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:5.0,5.0;" x1="403.5" x2="403.5" y1="40.2969" y2="926.6563"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:5.0,5.0;" x1="637" x2="637" y1="207.4766" y2="926.6563"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:5.0,5.0;" x1="777" x2="777" y1="40.2969" y2="926.6563"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:5.0,5.0;" x1="931" x2="931" y1="40.2969" y2="926.6563"/><rect fill="#FEFECE" filter="url(#f1ke4x5lxerpcl)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="114" x="109" y="5"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="100" x="116" y="24.9951">ServiceCellular</text><rect fill="#FEFECE" filter="url(#f1ke4x5lxerpcl)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="114" x="109" y="925.6563"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="100" x="116" y="945.6514">ServiceCellular</text><rect fill="#FEFECE" filter="url(#f1ke4x5lxerpcl)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="123" x="340.5" y="5"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="109" x="347.5" y="24.9951">RequestFactory</text><rect fill="#FEFECE" filter="url(#f1ke4x5lxerpcl)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="123" x="340.5" y="925.6563"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="109" x="347.5" y="945.6514">RequestFactory</text><rect fill="#FEFECE" filter="url(#f1ke4x5lxerpcl)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="76" x="597" y="925.6563"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="62" x="604" y="945.6514">IRequest</text><rect fill="#FEFECE" filter="url(#f1ke4x5lxerpcl)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="176" x="687" y="5"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="162" x="694" y="24.9951">CellularRequestHandler</text><rect fill="#FEFECE" filter="url(#f1ke4x5lxerpcl)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="176" x="687" y="925.6563"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="162" x="694" y="945.6514">CellularRequestHandler</text><rect fill="#FEFECE" filter="url(#f1ke4x5lxerpcl)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="104" x="877" y="5"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="90" x="884" y="24.9951">DLC_channel</text><rect fill="#FEFECE" filter="url(#f1ke4x5lxerpcl)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="104" x="877" y="925.6563"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="90" x="884" y="945.6514">DLC_channel</text><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="808.0938" style="stroke:#A80036;stroke-width:1.0;" width="10" x="163" y="71.4297"/><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="538.8984" style="stroke:#A80036;stroke-width:1.0;" width="10" x="399" y="100.5625"/><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="116.5313" style="stroke:#A80036;stroke-width:1.0;" width="10" x="632" y="792.125"/><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="29.1328" style="stroke:#A80036;stroke-width:1.0;" width="10" x="772" y="821.2578"/><polygon fill="#A80036" points="151,67.4297,161,71.4297,151,75.4297,155,71.4297" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="53" x2="157" y1="71.4297" y2="71.4297"/><text fill="#000000" font-family="monospace" font-size="13" lengthAdjust="spacing" textLength="96" x="60" y="66.3638">call request</text><polygon fill="#A80036" points="387,96.5625,397,100.5625,387,104.5625,391,100.5625" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="173" x2="393" y1="100.5625" y2="100.5625"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="43" x="180" y="95.4966">Create</text><line style="stroke:#A80036;stroke-width:1.0;" x1="409" x2="451" y1="129.6953" y2="129.6953"/><line style="stroke:#A80036;stroke-width:1.0;" x1="451" x2="451" y1="129.6953" y2="142.6953"/><line style="stroke:#A80036;stroke-width:1.0;" x1="410" x2="451" y1="142.6953" y2="142.6953"/><polygon fill="#A80036" points="420,138.6953,410,142.6953,420,146.6953,416,142.6953" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="121" x="416" y="124.6294">emergencyCheck()</text><path d="M99,157.6953 L163,157.6953 L163,164.6953 L153,174.6953 L99,174.6953 L99,157.6953 " fill="#EEEEEE" style="stroke:#000000;stroke-width:1.0;"/><rect fill="none" height="164.6328" style="stroke:#000000;stroke-width:2.0;" width="588" x="99" y="157.6953"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="19" x="114" y="170.7622">alt</text><text fill="#000000" font-family="sans-serif" font-size="11" font-weight="bold" lengthAdjust="spacing" textLength="178" x="178" y="169.9058">[is emergency and allowed]</text><path d="M692,162.6953 L692,202.6953 L945,202.6953 L945,172.6953 L935,162.6953 L692,162.6953 " fill="#FBFB77" filter="url(#f1ke4x5lxerpcl)" style="stroke:#A80036;stroke-width:1.0;"/><path d="M935,162.6953 L935,172.6953 L945,172.6953 L935,162.6953 " fill="#FBFB77" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="232" x="698" y="179.7622">decision depends on the emergency</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="224" x="698" y="194.895">number itself and state of SIM card</text><polygon fill="#A80036" points="585,191.9609,595,195.9609,585,199.9609,589,195.9609" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="409" x2="591" y1="195.9609" y2="195.9609"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="164" x="416" y="190.895">&lt;&lt;create CallRequest&gt;&gt;</text><rect fill="#FEFECE" filter="url(#f1ke4x5lxerpcl)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="76" x="597" y="174.8281"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="62" x="604" y="194.8232">IRequest</text><polygon fill="#A80036" points="184,237.2578,174,241.2578,184,245.2578,180,241.2578" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="178" x2="398" y1="241.2578" y2="241.2578"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="186" x="190" y="236.1919">&lt;&lt;CallRequest : IRequest&gt;&gt;</text><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="99" x2="687" y1="250.2578" y2="250.2578"/><text fill="#000000" font-family="sans-serif" font-size="11" font-weight="bold" lengthAdjust="spacing" textLength="203" x="104" y="260.4683">[is emergency and not allowed]</text><polygon fill="#A80036" points="625,281.1953,635,285.1953,625,289.1953,629,285.1953" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="409" x2="631" y1="285.1953" y2="285.1953"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="180" x="416" y="280.1294">&lt;&lt;create RejectRequest&gt;&gt;</text><polygon fill="#A80036" points="184,310.3281,174,314.3281,184,318.3281,180,314.3281" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="178" x2="398" y1="314.3281" y2="314.3281"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="202" x="190" y="309.2622">&lt;&lt;RejectRequest : IRequest&gt;&gt;</text><path d="M89,336.3281 L166,336.3281 L166,343.3281 L156,353.3281 L89,353.3281 L89,336.3281 " fill="#EEEEEE" style="stroke:#000000;stroke-width:1.0;"/><rect fill="none" height="148.6641" style="stroke:#000000;stroke-width:2.0;" width="608" x="89" y="336.3281"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="32" x="104" y="349.395">loop</text><text fill="#000000" font-family="sans-serif" font-size="11" font-weight="bold" lengthAdjust="spacing" textLength="98" x="181" y="348.5386">[request types]</text><line style="stroke:#A80036;stroke-width:1.0;" x1="409" x2="451" y1="374.5938" y2="374.5938"/><line style="stroke:#A80036;stroke-width:1.0;" x1="451" x2="451" y1="374.5938" y2="387.5938"/><line style="stroke:#A80036;stroke-width:1.0;" x1="410" x2="451" y1="387.5938" y2="387.5938"/><polygon fill="#A80036" points="420,383.5938,410,387.5938,420,391.5938,416,387.5938" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="121" x="416" y="369.5278">&lt;&lt;regexmatch&gt;&gt;</text><path d="M99,402.5938 L163,402.5938 L163,409.5938 L153,419.5938 L99,419.5938 L99,402.5938 " fill="#EEEEEE" style="stroke:#000000;stroke-width:1.0;"/><rect fill="none" height="75.3984" style="stroke:#000000;stroke-width:2.0;" width="588" x="99" y="402.5938"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="19" x="114" y="415.6606">alt</text><text fill="#000000" font-family="sans-serif" font-size="11" font-weight="bold" lengthAdjust="spacing" textLength="65" x="178" y="414.8042">[matched]</text><polygon fill="#A80036" points="625,436.8594,635,440.8594,625,444.8594,629,440.8594" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="409" x2="631" y1="440.8594" y2="440.8594"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="199" x="416" y="435.7935">&lt;&lt;create matched request&gt;&gt;</text><polygon fill="#A80036" points="184,465.9922,174,469.9922,184,473.9922,180,469.9922" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="178" x2="398" y1="469.9922" y2="469.9922"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="172" x="190" y="464.9263">&lt;&lt; matched : IRequest&gt;&gt;</text><path d="M99,498.9922 L163,498.9922 L163,505.9922 L153,515.9922 L99,515.9922 L99,498.9922 " fill="#EEEEEE" style="stroke:#000000;stroke-width:1.0;"/><rect fill="none" height="148.4688" style="stroke:#000000;stroke-width:2.0;" width="588" x="99" y="498.9922"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="19" x="114" y="512.0591">alt</text><text fill="#000000" font-family="sans-serif" font-size="11" font-weight="bold" lengthAdjust="spacing" textLength="111" x="178" y="511.2026">[SIM not present]</text><polygon fill="#A80036" points="625,533.2578,635,537.2578,625,541.2578,629,537.2578" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="409" x2="631" y1="537.2578" y2="537.2578"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="180" x="416" y="532.1919">&lt;&lt;create RejectRequest&gt;&gt;</text><polygon fill="#A80036" points="184,562.3906,174,566.3906,184,570.3906,180,566.3906" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="178" x2="398" y1="566.3906" y2="566.3906"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="135" x="190" y="561.3247">&lt;&lt;RejectRequest&gt;&gt;</text><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="99" x2="687" y1="575.3906" y2="575.3906"/><text fill="#000000" font-family="sans-serif" font-size="11" font-weight="bold" lengthAdjust="spacing" textLength="37" x="104" y="585.6011">[else]</text><polygon fill="#A80036" points="625,606.3281,635,610.3281,625,614.3281,629,610.3281" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="409" x2="631" y1="610.3281" y2="610.3281"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="164" x="416" y="605.2622">&lt;&lt;create CallRequest&gt;&gt;</text><polygon fill="#A80036" points="184,635.4609,174,639.4609,184,643.4609,180,639.4609" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="178" x2="403" y1="639.4609" y2="639.4609"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="119" x="190" y="634.395">&lt;&lt;CallRequest&gt;&gt;</text><polygon fill="#A80036" points="625,671.5938,635,675.5938,625,679.5938,629,675.5938" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="173" x2="631" y1="675.5938" y2="675.5938"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="75" x="180" y="670.5278">command()</text><polygon fill="#A80036" points="184,700.7266,174,704.7266,184,708.7266,180,704.7266" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="178" x2="636" y1="704.7266" y2="704.7266"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="109" x="190" y="699.6606">&lt;&lt;command&gt;&gt;</text><polygon fill="#A80036" points="919,729.8594,929,733.8594,919,737.8594,923,733.8594" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="173" x2="925" y1="733.8594" y2="733.8594"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="103" x="180" y="728.7935">cmd(command)</text><polygon fill="#A80036" points="184,758.9922,174,762.9922,184,766.9922,180,762.9922" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="178" x2="930" y1="762.9922" y2="762.9922"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="60" x="190" y="757.9263">at::Result</text><polygon fill="#A80036" points="620,788.125,630,792.125,620,796.125,624,792.125" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="173" x2="626" y1="792.125" y2="792.125"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="272" x="180" y="787.0591">Handle(CellularRequestHandler, at::Result)</text><polygon fill="#A80036" points="760,817.2578,770,821.2578,760,825.2578,764,821.2578" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="642" x2="766" y1="821.2578" y2="821.2578"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="110" x="649" y="816.1919">Handle(IRequest)</text><polygon fill="#A80036" points="981,846.3906,991,850.3906,981,854.3906,985,850.3906" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="777" x2="987" y1="850.3906" y2="850.3906"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="192" x="784" y="845.3247">&lt;&lt;specific system actions&gt;&gt;</text><polygon fill="#A80036" points="11,875.5234,1,879.5234,11,883.5234,7,879.5234" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="5" x2="167" y1="879.5234" y2="879.5234"/><text fill="#000000" font-family="monospace" font-size="13" lengthAdjust="spacing" textLength="144" x="17" y="874.4575">multicast response</text><polygon fill="#A80036" points="625,904.6563,635,908.6563,625,912.6563,629,908.6563" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="168" x2="631" y1="908.6563" y2="908.6563"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="40" x="175" y="903.5903">delete</text><line style="stroke:#A80036;stroke-width:2.0;" x1="628" x2="646" y1="899.6563" y2="917.6563"/><line style="stroke:#A80036;stroke-width:2.0;" x1="628" x2="646" y1="917.6563" y2="899.6563"/><!--MD5=[edee2e5540815f12480a1f2d3e978caa]
<?xml version="1.0" encoding="UTF-8" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" contentScriptType="application/ecmascript" contentStyleType="text/css" height="969px" preserveAspectRatio="none" style="width:995px;height:969px;" version="1.1" viewBox="0 0 995 969" width="995px" zoomAndPan="magnify"><defs><filter height="300%" id="f1ke4x5lxerpcl" width="300%" x="-1" y="-1"><feGaussianBlur result="blurOut" stdDeviation="2.0"/><feColorMatrix in="blurOut" result="blurOut2" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 .4 0"/><feOffset dx="4.0" dy="4.0" in="blurOut2" result="blurOut3"/><feBlend in="SourceGraphic" in2="blurOut3" mode="normal"/></filter></defs><g><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="808.0938" style="stroke:#A80036;stroke-width:1.0;" width="10" x="163" y="71.4297"/><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="538.8984" style="stroke:#A80036;stroke-width:1.0;" width="10" x="399" y="100.5625"/><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="116.5313" style="stroke:#A80036;stroke-width:1.0;" width="10" x="632" y="792.125"/><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="29.1328" style="stroke:#A80036;stroke-width:1.0;" width="10" x="772" y="821.2578"/><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="164.6328" style="stroke:#000000;stroke-width:2.0;" width="588" x="99" y="157.6953"/><rect fill="#FFFFFF" height="73.0703" style="stroke:none;stroke-width:1.0;" width="588" x="99" y="249.2578"/><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="148.6641" style="stroke:#000000;stroke-width:2.0;" width="608" x="89" y="336.3281"/><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="75.3984" style="stroke:#000000;stroke-width:2.0;" width="588" x="99" y="402.5938"/><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="148.4688" style="stroke:#000000;stroke-width:2.0;" width="588" x="99" y="498.9922"/><rect fill="#FFFFFF" height="73.0703" style="stroke:none;stroke-width:1.0;" width="588" x="99" y="574.3906"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:5.0,5.0;" x1="168" x2="168" y1="40.2969" y2="926.6563"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:5.0,5.0;" x1="403.5" x2="403.5" y1="40.2969" y2="926.6563"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:5.0,5.0;" x1="637" x2="637" y1="207.4766" y2="926.6563"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:5.0,5.0;" x1="777" x2="777" y1="40.2969" y2="926.6563"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:5.0,5.0;" x1="931" x2="931" y1="40.2969" y2="926.6563"/><rect fill="#FEFECE" filter="url(#f1ke4x5lxerpcl)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="114" x="109" y="5"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="100" x="116" y="24.9951">ServiceCellular</text><rect fill="#FEFECE" filter="url(#f1ke4x5lxerpcl)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="114" x="109" y="925.6563"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="100" x="116" y="945.6514">ServiceCellular</text><rect fill="#FEFECE" filter="url(#f1ke4x5lxerpcl)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="123" x="340.5" y="5"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="109" x="347.5" y="24.9951">RequestFactory</text><rect fill="#FEFECE" filter="url(#f1ke4x5lxerpcl)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="123" x="340.5" y="925.6563"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="109" x="347.5" y="945.6514">RequestFactory</text><rect fill="#FEFECE" filter="url(#f1ke4x5lxerpcl)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="76" x="597" y="925.6563"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="62" x="604" y="945.6514">IRequest</text><rect fill="#FEFECE" filter="url(#f1ke4x5lxerpcl)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="176" x="687" y="5"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="162" x="694" y="24.9951">CellularRequestHandler</text><rect fill="#FEFECE" filter="url(#f1ke4x5lxerpcl)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="176" x="687" y="925.6563"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="162" x="694" y="945.6514">CellularRequestHandler</text><rect fill="#FEFECE" filter="url(#f1ke4x5lxerpcl)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="104" x="877" y="5"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="90" x="884" y="24.9951">DLCChannel</text><rect fill="#FEFECE" filter="url(#f1ke4x5lxerpcl)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="104" x="877" y="925.6563"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="90" x="884" y="945.6514">DLCChannel</text><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="808.0938" style="stroke:#A80036;stroke-width:1.0;" width="10" x="163" y="71.4297"/><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="538.8984" style="stroke:#A80036;stroke-width:1.0;" width="10" x="399" y="100.5625"/><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="116.5313" style="stroke:#A80036;stroke-width:1.0;" width="10" x="632" y="792.125"/><rect fill="#FFFFFF" filter="url(#f1ke4x5lxerpcl)" height="29.1328" style="stroke:#A80036;stroke-width:1.0;" width="10" x="772" y="821.2578"/><polygon fill="#A80036" points="151,67.4297,161,71.4297,151,75.4297,155,71.4297" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="53" x2="157" y1="71.4297" y2="71.4297"/><text fill="#000000" font-family="monospace" font-size="13" lengthAdjust="spacing" textLength="96" x="60" y="66.3638">call request</text><polygon fill="#A80036" points="387,96.5625,397,100.5625,387,104.5625,391,100.5625" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="173" x2="393" y1="100.5625" y2="100.5625"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="43" x="180" y="95.4966">Create</text><line style="stroke:#A80036;stroke-width:1.0;" x1="409" x2="451" y1="129.6953" y2="129.6953"/><line style="stroke:#A80036;stroke-width:1.0;" x1="451" x2="451" y1="129.6953" y2="142.6953"/><line style="stroke:#A80036;stroke-width:1.0;" x1="410" x2="451" y1="142.6953" y2="142.6953"/><polygon fill="#A80036" points="420,138.6953,410,142.6953,420,146.6953,416,142.6953" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="121" x="416" y="124.6294">emergencyCheck()</text><path d="M99,157.6953 L163,157.6953 L163,164.6953 L153,174.6953 L99,174.6953 L99,157.6953 " fill="#EEEEEE" style="stroke:#000000;stroke-width:1.0;"/><rect fill="none" height="164.6328" style="stroke:#000000;stroke-width:2.0;" width="588" x="99" y="157.6953"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="19" x="114" y="170.7622">alt</text><text fill="#000000" font-family="sans-serif" font-size="11" font-weight="bold" lengthAdjust="spacing" textLength="178" x="178" y="169.9058">[is emergency and allowed]</text><path d="M692,162.6953 L692,202.6953 L945,202.6953 L945,172.6953 L935,162.6953 L692,162.6953 " fill="#FBFB77" filter="url(#f1ke4x5lxerpcl)" style="stroke:#A80036;stroke-width:1.0;"/><path d="M935,162.6953 L935,172.6953 L945,172.6953 L935,162.6953 " fill="#FBFB77" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="232" x="698" y="179.7622">decision depends on the emergency</text><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="224" x="698" y="194.895">number itself and state of SIM card</text><polygon fill="#A80036" points="585,191.9609,595,195.9609,585,199.9609,589,195.9609" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="409" x2="591" y1="195.9609" y2="195.9609"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="164" x="416" y="190.895">&lt;&lt;create CallRequest&gt;&gt;</text><rect fill="#FEFECE" filter="url(#f1ke4x5lxerpcl)" height="30.2969" style="stroke:#A80036;stroke-width:1.5;" width="76" x="597" y="174.8281"/><text fill="#000000" font-family="sans-serif" font-size="14" lengthAdjust="spacing" textLength="62" x="604" y="194.8232">IRequest</text><polygon fill="#A80036" points="184,237.2578,174,241.2578,184,245.2578,180,241.2578" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="178" x2="398" y1="241.2578" y2="241.2578"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="186" x="190" y="236.1919">&lt;&lt;CallRequest : IRequest&gt;&gt;</text><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="99" x2="687" y1="250.2578" y2="250.2578"/><text fill="#000000" font-family="sans-serif" font-size="11" font-weight="bold" lengthAdjust="spacing" textLength="203" x="104" y="260.4683">[is emergency and not allowed]</text><polygon fill="#A80036" points="625,281.1953,635,285.1953,625,289.1953,629,285.1953" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="409" x2="631" y1="285.1953" y2="285.1953"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="180" x="416" y="280.1294">&lt;&lt;create RejectRequest&gt;&gt;</text><polygon fill="#A80036" points="184,310.3281,174,314.3281,184,318.3281,180,314.3281" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="178" x2="398" y1="314.3281" y2="314.3281"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="202" x="190" y="309.2622">&lt;&lt;RejectRequest : IRequest&gt;&gt;</text><path d="M89,336.3281 L166,336.3281 L166,343.3281 L156,353.3281 L89,353.3281 L89,336.3281 " fill="#EEEEEE" style="stroke:#000000;stroke-width:1.0;"/><rect fill="none" height="148.6641" style="stroke:#000000;stroke-width:2.0;" width="608" x="89" y="336.3281"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="32" x="104" y="349.395">loop</text><text fill="#000000" font-family="sans-serif" font-size="11" font-weight="bold" lengthAdjust="spacing" textLength="98" x="181" y="348.5386">[request types]</text><line style="stroke:#A80036;stroke-width:1.0;" x1="409" x2="451" y1="374.5938" y2="374.5938"/><line style="stroke:#A80036;stroke-width:1.0;" x1="451" x2="451" y1="374.5938" y2="387.5938"/><line style="stroke:#A80036;stroke-width:1.0;" x1="410" x2="451" y1="387.5938" y2="387.5938"/><polygon fill="#A80036" points="420,383.5938,410,387.5938,420,391.5938,416,387.5938" style="stroke:#A80036;stroke-width:1.0;"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="121" x="416" y="369.5278">&lt;&lt;regexmatch&gt;&gt;</text><path d="M99,402.5938 L163,402.5938 L163,409.5938 L153,419.5938 L99,419.5938 L99,402.5938 " fill="#EEEEEE" style="stroke:#000000;stroke-width:1.0;"/><rect fill="none" height="75.3984" style="stroke:#000000;stroke-width:2.0;" width="588" x="99" y="402.5938"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="19" x="114" y="415.6606">alt</text><text fill="#000000" font-family="sans-serif" font-size="11" font-weight="bold" lengthAdjust="spacing" textLength="65" x="178" y="414.8042">[matched]</text><polygon fill="#A80036" points="625,436.8594,635,440.8594,625,444.8594,629,440.8594" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="409" x2="631" y1="440.8594" y2="440.8594"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="199" x="416" y="435.7935">&lt;&lt;create matched request&gt;&gt;</text><polygon fill="#A80036" points="184,465.9922,174,469.9922,184,473.9922,180,469.9922" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="178" x2="398" y1="469.9922" y2="469.9922"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="172" x="190" y="464.9263">&lt;&lt; matched : IRequest&gt;&gt;</text><path d="M99,498.9922 L163,498.9922 L163,505.9922 L153,515.9922 L99,515.9922 L99,498.9922 " fill="#EEEEEE" style="stroke:#000000;stroke-width:1.0;"/><rect fill="none" height="148.4688" style="stroke:#000000;stroke-width:2.0;" width="588" x="99" y="498.9922"/><text fill="#000000" font-family="sans-serif" font-size="13" font-weight="bold" lengthAdjust="spacing" textLength="19" x="114" y="512.0591">alt</text><text fill="#000000" font-family="sans-serif" font-size="11" font-weight="bold" lengthAdjust="spacing" textLength="111" x="178" y="511.2026">[SIM not present]</text><polygon fill="#A80036" points="625,533.2578,635,537.2578,625,541.2578,629,537.2578" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="409" x2="631" y1="537.2578" y2="537.2578"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="180" x="416" y="532.1919">&lt;&lt;create RejectRequest&gt;&gt;</text><polygon fill="#A80036" points="184,562.3906,174,566.3906,184,570.3906,180,566.3906" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="178" x2="398" y1="566.3906" y2="566.3906"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="135" x="190" y="561.3247">&lt;&lt;RejectRequest&gt;&gt;</text><line style="stroke:#000000;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="99" x2="687" y1="575.3906" y2="575.3906"/><text fill="#000000" font-family="sans-serif" font-size="11" font-weight="bold" lengthAdjust="spacing" textLength="37" x="104" y="585.6011">[else]</text><polygon fill="#A80036" points="625,606.3281,635,610.3281,625,614.3281,629,610.3281" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="409" x2="631" y1="610.3281" y2="610.3281"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="164" x="416" y="605.2622">&lt;&lt;create CallRequest&gt;&gt;</text><polygon fill="#A80036" points="184,635.4609,174,639.4609,184,643.4609,180,639.4609" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="178" x2="403" y1="639.4609" y2="639.4609"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="119" x="190" y="634.395">&lt;&lt;CallRequest&gt;&gt;</text><polygon fill="#A80036" points="625,671.5938,635,675.5938,625,679.5938,629,675.5938" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="173" x2="631" y1="675.5938" y2="675.5938"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="75" x="180" y="670.5278">command()</text><polygon fill="#A80036" points="184,700.7266,174,704.7266,184,708.7266,180,704.7266" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="178" x2="636" y1="704.7266" y2="704.7266"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="109" x="190" y="699.6606">&lt;&lt;command&gt;&gt;</text><polygon fill="#A80036" points="919,729.8594,929,733.8594,919,737.8594,923,733.8594" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="173" x2="925" y1="733.8594" y2="733.8594"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="103" x="180" y="728.7935">cmd(command)</text><polygon fill="#A80036" points="184,758.9922,174,762.9922,184,766.9922,180,762.9922" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="178" x2="930" y1="762.9922" y2="762.9922"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="60" x="190" y="757.9263">at::Result</text><polygon fill="#A80036" points="620,788.125,630,792.125,620,796.125,624,792.125" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="173" x2="626" y1="792.125" y2="792.125"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="272" x="180" y="787.0591">Handle(CellularRequestHandler, at::Result)</text><polygon fill="#A80036" points="760,817.2578,770,821.2578,760,825.2578,764,821.2578" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="642" x2="766" y1="821.2578" y2="821.2578"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="110" x="649" y="816.1919">Handle(IRequest)</text><polygon fill="#A80036" points="981,846.3906,991,850.3906,981,854.3906,985,850.3906" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="777" x2="987" y1="850.3906" y2="850.3906"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="192" x="784" y="845.3247">&lt;&lt;specific system actions&gt;&gt;</text><polygon fill="#A80036" points="11,875.5234,1,879.5234,11,883.5234,7,879.5234" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;stroke-dasharray:2.0,2.0;" x1="5" x2="167" y1="879.5234" y2="879.5234"/><text fill="#000000" font-family="monospace" font-size="13" lengthAdjust="spacing" textLength="144" x="17" y="874.4575">multicast response</text><polygon fill="#A80036" points="625,904.6563,635,908.6563,625,912.6563,629,908.6563" style="stroke:#A80036;stroke-width:1.0;"/><line style="stroke:#A80036;stroke-width:1.0;" x1="168" x2="631" y1="908.6563" y2="908.6563"/><text fill="#000000" font-family="sans-serif" font-size="13" lengthAdjust="spacing" textLength="40" x="175" y="903.5903">delete</text><line style="stroke:#A80036;stroke-width:2.0;" x1="628" x2="646" y1="899.6563" y2="917.6563"/><line style="stroke:#A80036;stroke-width:2.0;" x1="628" x2="646" y1="917.6563" y2="899.6563"/><!--MD5=[edee2e5540815f12480a1f2d3e978caa]
@startuml
participant ServiceCellular as cellular
participant RequestFactory as factory


@@ 42,12 42,12 @@ handler->? - : <<specific system actions>>
?<- -    cellular - - : ""multicast response""
cellular -> request !! : delete
@enduml

PlantUML version 1.2021.00(Sun Jan 10 11:25:05 CET 2021)
(GPL source distribution)
Java Runtime: OpenJDK Runtime Environment
JVM: OpenJDK 64-Bit Server VM
Default Encoding: UTF-8
Language: en
Country: US
--></g></svg>
\ No newline at end of file

PlantUML version 1.2021.00(Sun Jan 10 11:25:05 CET 2021)
(GPL source distribution)
Java Runtime: OpenJDK Runtime Environment
JVM: OpenJDK 64-Bit Server VM
Default Encoding: UTF-8
Language: en
Country: US
--></g></svg>

M module-services/service-cellular/handler/RawATHandler.cpp => module-services/service-cellular/handler/RawATHandler.cpp +4 -1
@@ 1,5 1,8 @@
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#include "RawATHandler.hpp"
#include <Modem/ATCommon.hpp>
#include <modem/ATCommon.hpp>
#include <module-sys/Service/Message.hpp>
#include <service-desktop/endpoints/developerMode/DeveloperModeEndpoint.hpp>
#include <service-desktop/endpoints/developerMode/event/ATRequest.hpp>

M module-services/service-cellular/service-cellular/CellularMessage.hpp => module-services/service-cellular/service-cellular/CellularMessage.hpp +14 -14
@@ 7,7 7,7 @@
#include "State.hpp"

#include <MessageType.hpp>
#include <Modem/TS0710/TS0710.h>
#include <modem/mux/CellularMux.h>
#include <PhoneNumber.hpp>
#include <Service/Message.hpp>
#include <module-bsp/bsp/cellular/bsp_cellular.hpp>


@@ 138,15 138,15 @@ class CellularNotificationMessage : public CellularMessage
        SignalStrengthUpdate,     // update of the strength of the network's signal.
        NetworkStatusUpdate,      // update of the status of the network
        PowerUpProcedureComplete, // modem without cmux on initialization complete (cold start || reset modem -> and
                                  // cold start)
        SIM_READY,                // change on SIM from URC
        SIM_NOT_READY,            // change to not existing/not valid SIM
        PowerDownDeregistering,   // modem informed it has started to disconnect from network
        PowerDownDeregistered,    // modem informed it has disconnected from network
        SMSDone,                  // SMS initialization finished
        NewIncomingUrc,           // phone received new URC from network and we need to wake up modem and host
        Ring,                     // phone received Ring notification
        CallerID                  // phone received Caller Id notification
        // cold start)
        SIM_READY,              // change on SIM from URC
        SIM_NOT_READY,          // change to not existing/not valid SIM
        PowerDownDeregistering, // modem informed it has started to disconnect from network
        PowerDownDeregistered,  // modem informed it has disconnected from network
        SMSDone,                // SMS initialization finished
        NewIncomingUrc,         // phone received new URC from network and we need to wake up modem and host
        Ring,                   // phone received Ring notification
        CallerID                // phone received Caller Id notification
    };

    // TODO check and fix all CellularNotificationMessage constructors


@@ 644,19 644,19 @@ class CellularSimAbortMessage : public CellularSimDataMessage
class CellularGetChannelMessage : public CellularMessage
{
  public:
    CellularGetChannelMessage(TS0710::Channel dataChannel = TS0710::Channel::None)
    explicit CellularGetChannelMessage(CellularMux::Channel dataChannel = CellularMux::Channel::None)
        : CellularMessage{Type::GetChannel}, dataChannel(dataChannel)
    {}
    TS0710::Channel dataChannel;
    CellularMux::Channel dataChannel;
};

class CellularGetChannelResponseMessage : public CellularMessage
{
  public:
    CellularGetChannelResponseMessage(DLC_channel *dataChannelPtr = nullptr)
    explicit CellularGetChannelResponseMessage(DLCChannel *dataChannelPtr = nullptr)
        : CellularMessage{Type::GetChannelResponse}, dataChannelPtr(dataChannelPtr)
    {}
    DLC_channel *dataChannelPtr;
    DLCChannel *dataChannelPtr;
};

class CellularResponseMessage : public sys::ResponseMessage

M module-services/service-cellular/service-cellular/CellularServiceAPI.hpp => module-services/service-cellular/service-cellular/CellularServiceAPI.hpp +2 -2
@@ 6,7 6,7 @@
#include "CellularMessage.hpp"
#include "PacketDataCellularMessage.hpp"

#include <Modem/TS0710/TS0710.h>
#include <modem/mux/CellularMux.h>
#include <PhoneNumber.hpp>
#include <module-bsp/bsp/cellular/bsp_cellular.hpp>
#include <utf8/UTF8.hpp>


@@ 81,7 81,7 @@ namespace CellularServiceAPI
    bool GetScanMode(sys::Service *serv);
    bool GetFirmwareVersion(sys::Service *serv, std::string &response);
    bool GetChannel(sys::Service *serv,
                    TS0710::Channel channel); /// asynchronous, returns message CellureMessageChannelReady;
                    CellularMux::Channel channel); /// asynchronous, returns message CellureMessageChannelReady;
    bool GetDataChannel(sys::Service *serv);
    bool GetCSQ(sys::Service *serv, std::string &response);
    bool GetCREG(sys::Service *serv, std::string &response);

M module-services/service-cellular/service-cellular/RequestFactory.hpp => module-services/service-cellular/service-cellular/RequestFactory.hpp +1 -1
@@ 8,7 8,7 @@
#include <map>
#include <functional>

#include <Modem/TS0710/DLC_channel.h>
#include <modem/mux/DLCChannel.h>

#include "requests/CallRequest.hpp"
#include "service-appmgr/Actions.hpp"

M module-services/service-cellular/service-cellular/ServiceCellular.hpp => module-services/service-cellular/service-cellular/ServiceCellular.hpp +10 -15
@@ 13,10 13,10 @@
#include "PacketDataCellularMessage.hpp"
#include <service-cellular/connection-manager/ConnectionManager.hpp>

#include <module-cellular/Modem/ATURCStream.hpp>
#include <Modem/TS0710/DLC_channel.h>
#include <Modem/TS0710/TS0710.h>
#include <Modem/TS0710/TS0710_types.h>
#include <modem/ATURCStream.hpp>
#include <modem/mux/DLCChannel.h>
#include <modem/mux/CellularMux.h>
#include <modem/mux/CellularMuxTypes.h>
#include <SMSRecord.hpp>
#include <Service/Common.hpp>
#include <Service/Message.hpp>


@@ 25,23 25,18 @@
#include <Timers/TimerHandle.hpp>
#include <bsp/common.hpp>
#include <utf8/UTF8.hpp>
#include <optional> // for optional
#include <memory>   // for unique_ptr, allocator, make_unique, shared_ptr
#include <string>   // for string
#include <vector>   // for vector
#include <service-db/Settings.hpp>
#include <module-services/service-db/agents/settings/SystemSettings.hpp>
#include <module-sys/PhoneModes/Observer.hpp>
#include <service-db/DBServiceName.hpp>
#include <service-db/DBNotificationMessage.hpp>

#include <optional> // for optional
#include <memory>   // for unique_ptr, allocator, make_unique, shared_ptr
#include <string>   // for string
#include <vector>   // for vector
#include <cstdint>
#include <memory>
#include <optional>
#include <string>
#include <vector>

class MuxDaemon;

namespace db
{


@@ 180,7 175,7 @@ class ServiceCellular : public sys::Service

  private:
    at::ATURCStream atURCStream;
    std::unique_ptr<TS0710> cmux = std::make_unique<TS0710>(PortSpeed_e::PS460800, this);
    std::unique_ptr<CellularMux> cmux = std::make_unique<CellularMux>(PortSpeed_e::PS460800, this);
    std::shared_ptr<sys::CpuSentinel> cpuSentinel;

    // used for polling for call state


@@ 198,7 193,7 @@ class ServiceCellular : public sys::Service

    void SleepTimerHandler();
    void CallStateTimerHandler();
    DLC_channel::Callback_t notificationCallback = nullptr;
    DLCChannel::Callback_t notificationCallback = nullptr;

    std::unique_ptr<packet_data::PacketData> packetData;
    std::unique_ptr<sys::phone_modes::Observer> phoneModeObserver;

M module-services/service-cellular/tests/CMakeLists.txt => module-services/service-cellular/tests/CMakeLists.txt +2 -0
@@ 16,6 16,7 @@ add_catch2_executable(
        unittest_simcard.cpp
        LIBS
        module-cellular
        module-sys
)




@@ 26,6 27,7 @@ add_catch2_executable(
        unittest_datatransfer.cpp
        LIBS
        module-cellular
        module-sys
)

add_catch2_executable(

M module-services/service-cellular/tests/unittest_datatransfer.cpp => module-services/service-cellular/tests/unittest_datatransfer.cpp +0 -1
@@ 7,7 7,6 @@

#include "Result.hpp"
#include <service-cellular/PacketData.hpp>
#include <service-cellular/PacketDataTypes.hpp>

using namespace cellular;


M module-services/service-cellular/tests/unittest_simcard.cpp => module-services/service-cellular/tests/unittest_simcard.cpp +2 -4
@@ 1,4 1,4 @@
// Copyright (c) 2017-2020, Mudita Sp. z.o.o. All rights reserved.
// Copyright (c) 2017-2021, Mudita Sp. z.o.o. All rights reserved.
// For licensing, see https://github.com/mudita/MuditaOS/LICENSE.md

#define CATCH_CONFIG_MAIN


@@ 6,8 6,6 @@
#include <catch2/catch.hpp>
#include <service-cellular/SimCard.hpp>

using namespace cellular;

TEST_CASE("SimCard functionality test")
{
    SECTION("pinToString from vector")


@@ 15,6 13,6 @@ TEST_CASE("SimCard functionality test")
        std::vector<unsigned int> v{1, 2, 3, 4};
        std::vector<unsigned int> empty;
        REQUIRE(SimCard::pinToString(v) == "1234");
        REQUIRE(SimCard::pinToString(empty) == "");
        REQUIRE(SimCard::pinToString(empty).empty());
    }
}

M module-services/service-fota/ServiceFota.cpp => module-services/service-fota/ServiceFota.cpp +11 -12
@@ 8,30 8,29 @@

#include <Commands.hpp>
#include <MessageType.hpp>
#include <Modem/TS0710/DLC_channel.h>
#include <modem/mux/DLCChannel.h>
#include <Service/Message.hpp>
#include <Service/Service.hpp>
#include <module-sys/Timers/TimerFactory.hpp>
#include <Timers/TimerFactory.hpp>
#include <log/log.hpp>
#include <module-cellular/at/Result.hpp>
#include <module-cellular/at/UrcFactory.hpp>
#include <at/Result.hpp>
#include <at/UrcFactory.hpp>
#include <portmacro.h>
#include <service-cellular/CellularMessage.hpp>
#include <service-cellular/CellularServiceAPI.hpp>
#include <service-cellular/State.hpp>

#include <bits/exception.h>                            // for exception
#include <algorithm>                                   // for find_if, remove, transform
#include <cctype>                                      // for tolower
#include <functional>                                  // for _Bind_helper<>::type, _Placeholder, bind, _1, _2
#include <numeric>                                     // for accumulate
#include <bits/exception.h> // for exception
#include <algorithm>        // for find_if, remove, transform
#include <cctype>           // for tolower
#include <functional>       // for _Bind_helper<>::type, _Placeholder, bind, _1, _2
#include <numeric>          // for accumulate
#include <sstream> // for operator<<, basic_ostream, ostringstream, basic_ostream::operator<<, char_traits, basic_istream, istringstream, basic_ostream<>::__ostream_type
#include <string>  // for string, basic_string, stoi, getline, operator<<, operator==, operator+, operator!=
#include <unordered_map> // for unordered_map<>::iterator, _Node_iterator, operator==, _Map_base<>::mapped_type, _Node_iterator_base, unordered_map<>::mapped_type
#include <utility>       // for move, pair
#include <vector>        // for vector


namespace FotaService
{
    const TickType_t defaultTimer        = 1000;


@@ 401,8 400,8 @@ namespace FotaService
                    LOG_ERROR("Conversion error of %s, taking default value %d", data[2].c_str(), contextTypeRaw);
                }

                apnConfig.type      = static_cast<APN::ContextType>(contextTypeRaw);
                apnConfig.ip        = data[3].substr(1, data[3].size() - 1);
                apnConfig.type = static_cast<APN::ContextType>(contextTypeRaw);
                apnConfig.ip   = data[3].substr(1, data[3].size() - 1);
                LOG_DEBUG("Warking APN: %s", apnConfig.toString().c_str());
                contextMap[apnConfig.contextId] = apnConfig;
            }

M module-services/service-fota/service-fota/ServiceFota.hpp => module-services/service-fota/service-fota/ServiceFota.hpp +5 -5
@@ 5,8 5,8 @@

#include "FotaServiceAPI.hpp"

#include <Modem/TS0710/DLC_channel.h>
#include <Modem/TS0710/TS0710.h>
#include <modem/mux/DLCChannel.h>
#include <modem/mux/CellularMux.h>
#include <Result.hpp>
#include <Service/Common.hpp>
#include <Service/Message.hpp>


@@ 21,7 21,7 @@
#include <sstream>
#include <string>

class DLC_channel;
class DLCChannel;
class FotaUrcHandler;

namespace service::name


@@ 112,8 112,8 @@ namespace FotaService
        void sendProgress(unsigned int progress, const std::string &receiver);
        void sendFotaFinshed(const std::string &receiver);

        State state              = State ::Idle;
        DLC_channel *dataChannel = nullptr;
        State state             = State ::Idle;
        DLCChannel *dataChannel = nullptr;
        APN::ContextMap contextMap;
        std::string url;
        std::string file;

M module-utils/log/Logger.cpp => module-utils/log/Logger.cpp +2 -2
@@ 11,8 11,8 @@
namespace Log
{
    std::map<std::string, logger_level> Logger::filtered = {{"ApplicationManager", logger_level::LOGINFO},
                                                            {"TS0710Worker", logger_level::LOGTRACE},
                                                            {"ServiceCellular", logger_level::LOGTRACE},
                                                            {"CellularMux", logger_level::LOGINFO},
                                                            {"ServiceCellular", logger_level::LOGINFO},
                                                            {"ServiceAntenna", logger_level::LOGINFO},
                                                            {"ServiceAudio", logger_level::LOGINFO},
                                                            {"ServiceBluetooth", logger_level::LOGINFO},