~aleteoryx/muditaos

6d22e00544d7918bb71aa12519bdc1cbbf887c5f — Bartek Cichocki 5 years ago 49a6776
[EGD-3637] restoration of Bluetooth stack

[EGD-3637] Bluetooth hangup fix
57 files changed, 7547 insertions(+), 1 deletions(-)

M .gitmodules
M CMakeLists.txt
M module-apps/application-settings/ApplicationSettings.cpp
M module-apps/application-settings/CMakeLists.txt
A module-bluetooth/Bluetooth/BluetoothWorker.cpp
A module-bluetooth/Bluetooth/BluetoothWorker.hpp
A module-bluetooth/Bluetooth/BtCommand.hpp
A module-bluetooth/Bluetooth/Device.hpp
A module-bluetooth/Bluetooth/Error.hpp
A module-bluetooth/Bluetooth/Stack.hpp
A module-bluetooth/Bluetooth/glucode/HCITRANS.cpp
A module-bluetooth/Bluetooth/glucode/bluetooth_init_cc2564C_1.0.c
A module-bluetooth/Bluetooth/glucode/btstack_uart_block_rt1051.cpp
A module-bluetooth/Bluetooth/glucode/btstack_uart_block_rt1051.h
A module-bluetooth/Bluetooth/glucode/hal_time_ms.c
A module-bluetooth/Bluetooth/interface/bluekitchen/GAP.cpp
A module-bluetooth/Bluetooth/interface/bluekitchen/PAN.cpp
A module-bluetooth/Bluetooth/interface/bluekitchen/Worker.cpp
A module-bluetooth/Bluetooth/interface/bluekitchen/btstack_config.h
A module-bluetooth/CMakeLists.txt
A module-bluetooth/README.md
A module-bluetooth/lib/btstack
A module-bluetooth/lib/btstack.cmake
A module-bluetooth/targets/Target_Linux.cmake
A module-bluetooth/tests/CMakeLists.txt
M module-bsp/CMakeLists.txt
A module-bsp/board/linux/bluetooth/Bluetooth.cpp
A module-bsp/board/linux/bluetooth/test/bsp_bt.cpp
A module-bsp/board/linux/bluetooth/test/bsp_bt.hpp
A module-bsp/board/rt1051/bluetooth/BlueKitchen.cpp
A module-bsp/board/rt1051/bluetooth/BluetoothCommon.cpp
A module-bsp/board/rt1051/bluetooth/Bluetopia.cpp
M module-bsp/board/rt1051/common/board.h
A module-bsp/bsp/bluetooth/Bluetooth.cpp
A module-bsp/bsp/bluetooth/Bluetooth.hpp
M module-bsp/targets/Target_Linux.cmake
M module-bsp/targets/Target_RT1051.cmake
A module-lwip/CMakeLists.txt
A module-lwip/README.md
A module-lwip/includes/arch/cc.h
A module-lwip/includes/lwipopts.h
A module-lwip/lib/dhcp-server/LICENSE
A module-lwip/lib/dhcp-server/README
A module-lwip/lib/dhcp-server/dhserver.c
A module-lwip/lib/dhcp-server/dhserver.h
A module-lwip/lib/lwip
A module-lwip/lwip-includes.cmake
A module-lwip/tests/CMakeLists.txt
M module-services/CMakeLists.txt
A module-services/service-bluetooth/CMakeLists.txt
A module-services/service-bluetooth/ServiceBluetooth.cpp
A module-services/service-bluetooth/ServiceBluetooth.hpp
A module-services/service-bluetooth/messages/BluetoothMessage.hpp
A module-services/service-lwip/CMakeLists.txt
A module-services/service-lwip/ServiceLwIP.cpp
A module-services/service-lwip/ServiceLwIP.hpp
M source/main.cpp
M .gitmodules => .gitmodules +7 -0
@@ 1,3 1,7 @@
[submodule "module-lwip/lib/lwip"]
	path = module-lwip/lib/lwip
	url = ../lwip.git
	shallow = true
[submodule "module-utils/microtar"]
	path = module-utils/microtar
	url = ../microtar.git


@@ 40,3 44,6 @@
	path = module-audio/Audio/decoder/taglib
	url = ../taglib.git
	branch = rt1051
[submodule "module-bluetooth/lib/btstack"]
	path = module-bluetooth/lib/btstack
	url = git@github.com:mudita/btstack.git

M CMakeLists.txt => CMakeLists.txt +10 -0
@@ 11,6 11,7 @@ include(Colours)
include(CCacheConfig)
include(ProjectConfig)
include(ModuleConfig)
include(module-lwip/lwip-includes.cmake)
include(SerialPort)
include(CopyGdbInit)



@@ 161,6 162,12 @@ add_subdirectory(module-services)
message("${PROJECT_NAME}: add_subdirectory module-apps")
add_subdirectory(module-apps)

message("${PROJECT_NAME}: add_subdirectory module-bluetooth")
add_subdirectory(module-bluetooth)

message("${PROJECT_NAME}: add_subdirectory module-lwip")
add_subdirectory(module-lwip)

add_subdirectory(image)

set_target_properties(${CMAKE_PROJECT_NAME} PROPERTIES SUFFIX ".elf")


@@ 184,6 191,9 @@ target_link_libraries(${PROJECT_NAME}
        module-gui
        module-services
        module-apps
        module-bluetooth
        ${LWIP_LIBRARIES}
        module-lwip
        ${TARGET_LIBRARIES}
        )


M module-apps/application-settings/ApplicationSettings.cpp => module-apps/application-settings/ApplicationSettings.cpp +4 -0
@@ 11,6 11,7 @@
#include "MessageType.hpp"
#include "windows/SettingsMainWindow.hpp"
#include "windows/LanguageWindow.hpp"
#include "windows/BtWindow.hpp"
#include "windows/DateTimeWindow.hpp"
#include "windows/FotaWindow.hpp"
#include "windows/Info.hpp"


@@ 95,6 96,9 @@ namespace app
        window = new gui::LanguageWindow(this);
        windows.insert(std::pair<std::string, gui::AppWindow *>(window->getName(), window));

        window = new gui::BtWindow(this);
        windows.insert(std::pair<std::string, gui::AppWindow *>(window->getName(), window));

        window = new gui::UiTestWindow(this);
        windows.insert(std::pair<std::string, gui::AppWindow *>(window->getName(), window));


M module-apps/application-settings/CMakeLists.txt => module-apps/application-settings/CMakeLists.txt +1 -0
@@ 17,6 17,7 @@ target_sources( ${PROJECT_NAME}
        ApplicationSettings.cpp
        windows/SettingsMainWindow.cpp
        windows/LanguageWindow.cpp
        windows/BtWindow.cpp

        windows/UITestWindow.cpp
        windows/Info.cpp

A module-bluetooth/Bluetooth/BluetoothWorker.cpp => module-bluetooth/Bluetooth/BluetoothWorker.cpp +171 -0
@@ 0,0 1,171 @@
#include "BluetoothWorker.hpp"
#include "log/log.hpp"
#include "BtCommand.hpp"

using namespace bsp;

const char *c_str(Bt::Error::Code code)
{
    switch (code) {
    case Bt::Error::Code::Succes:
        return "Succes";
    case Bt::Error::Code::NotReady:
        return "NotReady";
    case Bt::Error::Code::SystemError:
        return "SystemError";
    case Bt::Error::Code::LibraryError:
        return "LibraryError";
    }
    return "";
}

BluetoothWorker::BluetoothWorker(sys::Service *service) : Worker(service)
{
    init({
        {"qBtIO", sizeof(Bt::Message), 10},
        {"qBtWork", sizeof(Bt::EvtWorker), 10},
    });
};

BluetoothWorker::~BluetoothWorker()
{
    if (this->bt_worker_task != nullptr) {}
    LOG_INFO("Worker removed");
}

bool BluetoothWorker::run()
{
    LOG_INFO("-> BluetoothWorker run request");
    if (is_running) {
        return true;
    }
    if (Worker::run()) {
        is_running                          = true;
        auto el                             = queues[queueIO_handle];
        BlueKitchen::getInstance()->qHandle = el;
        Bt::initialize_stack();
        Bt::register_hw_error_callback();
        Bt::GAP::register_scan();
        std::string name = "PurePhone";
        Bt::set_name(name);
        // set local namne
        // set discoverable (on)
        // Bt::GAP::
        Bt::run_stack(&this->bt_worker_task);
        return true;
    }
    else {
        return false;
    }
}

bool BluetoothWorker::scan()
{
    std::vector<Device> empty;

    auto ret = Bt::GAP::scan();
    if (ret.err != Bt::Error::Succes) {
        LOG_ERROR("Cant start scan!: %s %" PRIu32 "", c_str(ret.err), ret.lib_code);
        return false;
    }
    else {
        LOG_INFO("Scan started!");
        return true;
    }
}

bool BluetoothWorker::set_visible()
{
    LOG_ERROR("TODO");

    return false;
}

bool BluetoothWorker::start_pan()
{
    Bt::PAN::bnep_setup();
    auto err = Bt::PAN::bnep_start();
    if (err.err != Bt::Error::Succes) {
        LOG_ERROR("PAN setup error: %s %" PRIu32, c_str(err.err), err.lib_code);
    }
    return false;
}

BluetoothWorker::Error BluetoothWorker::aud_init()
{
    LOG_INFO("%s", __PRETTY_FUNCTION__);
    Error err = SuccessBt;
    LOG_INFO("AUDIO - TODO");
    // start GAVD
    // &&  ASSIGN_CLASS_OF_DEVICE(ClassOfDevice, 0x28, 0x04, 0x10);
    return err;
}

#include <sstream>

bool BluetoothWorker::handleMessage(uint32_t queueID)
{

    QueueHandle_t queue = queues[queueID];
    if (queueID == queueService) {
        LOG_DEBUG("not interested");
        return true;
    }
    if (queueID != queueIO_handle) {
        LOG_ERROR("Wrong queue! %" PRIu32, queueID);
        return false;
    }

    Bt::Message notification = Bt::Message::EvtErrorRec;
    if (xQueueReceive(queue, &notification, 0) != pdTRUE) {
        LOG_ERROR("Receive failure!");
        return false;
    }
    auto bt = BlueKitchen::getInstance();
    switch (notification) {
    case Bt::Message::EvtSent:
#ifdef DO_DEBUG_HCI_COMS
        LOG_INFO("[evt] sent");
#endif
        if (bt->write_done_cb) {
            bt->write_done_cb();
        }
        break;
    case Bt::Message::EvtReceived: {
        if (bt->to_read_req > bt->in.len) {
            // LOG_ERROR("%d vs %d", bt->to_read_req, bt->in.len);
            break;
        }
        for (int i = 0; i < bt->to_read_req; ++i) {
            // error in pop should never happen
            if (int ret = bt->in.pop((char *)bt->read_buff + i)) {
                LOG_ERROR("This shall never happen: %d", ret);
            }
        }
        // LOG_DEBUG(">> %d",bt->in.len);
#ifdef DO_DEBUG_HCI_COMS
        std::stringstream ss;
        for (int i = 0; i < bt->to_read_req; ++i) {
            ss << " 0x" << std::hex << (int)*(bt->read_buff + i);
        }
        LOG_DEBUG("[evt] recieved <-- [%d]>%s<", bt->to_read_req, ss.str().c_str());
#endif
        bt->to_read_req = 0;

        if (bt->read_ready_cb) {
            bt->read_ready_cb();
        }
    } break;
    case Bt::Message::EvtSentError:
    case Bt::Message::EvtRecError:
    case Bt::Message::EvtUartError:
    case Bt::Message::EvtRecUnwanted: {
        LOG_ERROR("Uart error [%d]: %s", notification, Bt::MessageCstr(notification));
        break;
    } break;
    default:
        LOG_ERROR("ERROR");
    }

    return true;
}

A module-bluetooth/Bluetooth/BluetoothWorker.hpp => module-bluetooth/Bluetooth/BluetoothWorker.hpp +98 -0
@@ 0,0 1,98 @@
#pragma once

#include <FreeRTOS.h>
#include <task.h>
#include <bsp/bluetooth/Bluetooth.hpp>
#include <memory>
#include <vector>

#include "Device.hpp"
#include "Service/Worker.hpp"

struct HCI;

/// debug option for HCI (uart) commands debugging
// #define DO_DEBUG_HCI_COMS

namespace Bt
{
    enum Message : uint8_t
    {
        /// asynchronous messages to use on event from irq
        EvtSent,        /// trigger Bt stack wrote, enable writting in HCI in BluetoothWorker task
        EvtRecUnwanted, /// not requested recieve - probably receive came to fast from sent...
        EvtRecError,    /// bsp error on receive
        EvtSentError,   /// bsp error on send
        EvtUartError,   /// generic uart error
        EvtReceived,    /// trigger Bt stack received, start processing HCI in BluetoothWorker task
        EvtErrorRec,    /// there was error o queue receive
    };

    inline const char *MessageCstr(Message what)
    {
        switch (what) {
        case EvtReceived:
            return "EvtReceived";
        case EvtSent:
            return "EvtSent";
        case EvtRecUnwanted:
            return "EvtRecUnwanted";
        case EvtRecError:
            return "EvtRecError";
        case EvtSentError:
            return "EvtSentError";
        case EvtUartError:
            return "EvtUartError";
        case EvtErrorRec:
            return "EvtErrorRec";
        default:
            return "";
        }
    }

    struct EvtWorker
    {
        enum Evt : uint8_t
        {
        };
    };
}; // namespace Bt

class BluetoothWorker : private sys::Worker
{
    enum WorkerEventQueues
    {
        queueService = 0,
        queueIO_handle, /// bsp support queue
        queue_profiles, /// queue for communication between profile workers,
                        /// main bt_worker_task should dispatch these in events
    };

    TaskHandle_t bt_worker_task = nullptr;
    int is_running              = false;

  public:
    enum Error
    {
        SuccessBt,
        ErrorBtGeneric,
        ErrorBtAPI,
    };

    BluetoothWorker(sys::Service *service);
    virtual ~BluetoothWorker();

    virtual bool handleMessage(uint32_t queueID);

    bool run();

    bool scan();

    bool set_visible();

    bool start_pan();

    Error aud_init();
    /// bluetooth stack id in use
    unsigned long active_features;
};

A module-bluetooth/Bluetooth/BtCommand.hpp => module-bluetooth/Bluetooth/BtCommand.hpp +26 -0
@@ 0,0 1,26 @@
#pragma once
#include <FreeRTOS.h>
#include <task.h>

#include "BluetoothWorker.hpp"
#include "Error.hpp"
#include <functional>

namespace Bt
{
    Error initialize_stack();
    Error register_hw_error_callback(std::function<void(uint8_t)> new_callback = nullptr);
    Error set_name(std::string &name);
    Error run_stack(TaskHandle_t *handle);
    namespace GAP
    {
        /// THIS have to be called prior to Bt system start!
        Error register_scan();
        Error scan();
    }; // namespace GAP
    namespace PAN
    {
        Error bnep_start();
        Error bnep_setup();
    } // namespace PAN
};    // namespace Bt

A module-bluetooth/Bluetooth/Device.hpp => module-bluetooth/Bluetooth/Device.hpp +11 -0
@@ 0,0 1,11 @@
#pragma once
#include <string>

struct Device
{
  public:
    Device(std::string name = "") : name(name)
    {}
    virtual ~Device(){};
    std::string name;
};

A module-bluetooth/Bluetooth/Error.hpp => module-bluetooth/Bluetooth/Error.hpp +25 -0
@@ 0,0 1,25 @@
#pragma once

#include <cstdint>
#include <variant>
#include <optional>

namespace Bt
{

    struct Error
    {
        enum Code
        {
            Succes,
            NotReady,
            SystemError,
            LibraryError,
        } err             = Succes;
        uint32_t lib_code = 0;
        Error(enum Code err = Succes, int lib_code = Succes) : err(err), lib_code(0)
        {}
    };

} // namespace Bt
const char *c_str(Bt::Error::Code code);

A module-bluetooth/Bluetooth/Stack.hpp => module-bluetooth/Bluetooth/Stack.hpp +8 -0
@@ 0,0 1,8 @@
#pragma once

struct Stack
{
    int id;
    Stack() : id(0)
    {}
};

A module-bluetooth/Bluetooth/glucode/HCITRANS.cpp => module-bluetooth/Bluetooth/glucode/HCITRANS.cpp +123 -0
@@ 0,0 1,123 @@
#include <bsp/bluetooth/Bluetooth.hpp>
#include "log/log.hpp"

using namespace bsp;

extern "C"
{

#include "HCITRANS.h"
#define TRANSPORT_ID 1

    typedef void(BTPSAPI *HCITR_COMDataCallback_t)(unsigned int HCITransportID,
                                                   unsigned int DataLength,
                                                   unsigned char *DataBuffer,
                                                   unsigned long CallbackParameter);
    void RxThread(void *Param);

    int BTPSAPI HCITR_COMOpen(HCI_COMMDriverInformation_t *COMMDriverInformation,
                              HCITR_COMDataCallback_t COMDataCallback,
                              unsigned long CallbackParameter)
    {

        int ret = TRANSPORT_ID;
        LOG_INFO("COM OPEN!");
        Bluetopia *bt = Bluetopia::getInstance();
        bt->set_reset(true);
        bt->open();
        bt->com_cb       = COMDataCallback;
        bt->com_cb_param = CallbackParameter;
        bt->rx_thread    = xTaskCreate(RxThread, "RxThread", 4096, NULL, 3, &bt->thandle);
        if (bt->rx_thread != pdPASS) {
            ret = ErrorBtGeneric;
            LOG_ERROR("COM OPEN failure: %d", bt->rx_thread);
        }
        LOG_INFO("COM OPEN! done");
        return ret;
    }

    void BTPSAPI HCITR_COMClose(unsigned int HCITransportID)
    {
        LOG_ERROR("COM CLOSE");
        Bluetopia *dev = Bluetopia::getInstance();
        if (dev->thandle != NULL) {
            // vTaskDelete(bt->thandle);
        }
        dev->close();
        dev->set_reset(false);
        if (dev->com_cb) {
            dev->com_cb(TRANSPORT_ID, 0, NULL, dev->com_cb_param);
        }
        LOG_ERROR("COM CLOSED");
    }

    void BTPSAPI HCITR_COMReconfigure(unsigned int HCITransportID, HCI_Driver_Reconfigure_Data_t *DriverReconfigureData)
    {
        HCI_COMMReconfigureInformation_t *ReconfigureInformation;
        Bluetopia *dev = Bluetopia::getInstance();
        if ((HCITransportID == TRANSPORT_ID) && dev->is_open && (DriverReconfigureData)) {
            if ((DriverReconfigureData->ReconfigureCommand ==
                 HCI_COMM_DRIVER_RECONFIGURE_DATA_COMMAND_CHANGE_COMM_PARAMETERS) &&
                (DriverReconfigureData->ReconfigureData)) {
                ReconfigureInformation = (HCI_COMMReconfigureInformation_t *)(DriverReconfigureData->ReconfigureData);
                if (ReconfigureInformation->ReconfigureFlags &
                    HCI_COMM_RECONFIGURE_INFORMATION_RECONFIGURE_FLAGS_CHANGE_BAUDRATE) {
                    LOG_INFO("Set baudrate to: %d", ReconfigureInformation->BaudRate);
                    dev->set_irq(false);
                    dev->set_baudrate(ReconfigureInformation->BaudRate);
                    dev->set_irq(true);
                }
            }
        }
    }

    int BTPSAPI HCITR_COMWrite(unsigned int HCITransportID, unsigned int Length, unsigned char *Buffer)
    {
        int ret = 0;
        // LOG_INFO("DATA -> [%d]", Length);
        if (HCITransportID) {
            ret = Bluetopia::getInstance()->write_blocking(reinterpret_cast<char *>(Buffer), Length);
        }
        else {
            ret = -1;
        }
        return ret;
    }

    int BTPSAPI HCITR_COMSuspend(unsigned int HCITransportID)
    {
        LOG_ERROR("Not implemented!");
        int ret = -1;
        if (HCITransportID) {}
        else {
            ret = -1;
        }
        return ret;
    }

    int BTPSAPI HCITR_EnableDebugLogging(Boolean_t Enable)
    {
        return 0;
    }

    void RxThread(void *Param)
    {
        LOG_INFO("BT RxThread created");
        Bluetopia *dev = Bluetopia::getInstance();
        while (dev->is_open) {
            dev->wait_data();
            dev->set_irq(false);
            // LOG_INFO("DATA [%d]<--", dev->in.len);
            // for(int i=0; i<dev->in.len; ++i) {
            //     LOG_PRINTF("0x%X ", dev->in.buff[i]);
            // }
            // LOG_PRINTF("\n");
            if (dev->com_cb) {
                dev->com_cb(TRANSPORT_ID, dev->in.len, (unsigned char *)dev->in.buff, dev->com_cb_param);
            }
            dev->in.flush();
            dev->set_irq(true);
            dev->set_rts(true);
        }
    }
};

A module-bluetooth/Bluetooth/glucode/bluetooth_init_cc2564C_1.0.c => module-bluetooth/Bluetooth/glucode/bluetooth_init_cc2564C_1.0.c +3939 -0
@@ 0,0 1,3939 @@
// init script created from
// - initscripts-TIInit_6.12.26_v1.0.bts
// - AKA TIInit_6.12.26.bts
// - initscripts-TIInit_6.12.26_ble_add-on_v1.0.bts
#include <stdint.h>
#include "btstack_chipset_cc256x.h"

const uint16_t cc256x_init_script_lmp_subversion = 0x9a1a;

uint16_t btstack_chipset_cc256x_lmp_subversion(void)
{
    return cc256x_init_script_lmp_subversion;
}

#if defined(__GNUC__) && defined(__MSP430X__) && (__MSP430X__ > 0)
__attribute__((section(".fartext")))
#endif
#ifdef __AVR__
__attribute__((__progmem__))
#endif
const uint8_t cc256x_init_script[] = {

    // #--------------------------------------------------------------------------------
    // # Description : Orca C ROM Initialization Script
    // #
    // # Compatibility: Orca, 12.0.26 ROM
    // #
    // # Last Updated: 29-Sep-2016  14:08:47.69
    // #
    // # Version     : 12_26.12
    // #
    // #
    // #
    // #
    // # Notes       : Use this script on Orca C, 12.0.26 ROM device only (FW v12.0.26)
    // #--------------------------------------------------------------------------------
    //
    // #################################################################
    // ## START of CC256x Add-On
    // #################################################################
    //
    // ## Change UART baudrate
    //
    // #################################################################
    // ## END of CC256x Add-On
    // #################################################################
    //
    0x01,
    0x37,
    0xfe,
    0x02,
    0x0c,
    0x1a,

    //
    //
    0x01,
    0x05,
    0xff,
    0xff,
    0xd0,
    0x65,
    0x08,
    0x00,
    0xfa,
    0x0c,
    0x1a,
    0x09,
    0x0c,
    0x01,
    0x6a,
    0xc8,
    0x7b,
    0x00,
    0x02,
    0x89,
    0x7b,
    0x01,
    0x43,
    0x09,
    0x48,
    0x51,
    0x30,
    0x02,
    0x88,
    0x06,
    0x48,
    0x91,
    0x42,
    0x03,
    0xd1,
    0x04,
    0x49,
    0x09,
    0x78,
    0x01,
    0x29,
    0x01,
    0xd0,
    0x5d,
    0x30,
    0xf7,
    0x46,
    0xff,
    0x30,
    0xd8,
    0x30,
    0xf7,
    0x46,
    0x76,
    0x24,
    0x08,
    0x00,
    0xbd,
    0x28,
    0x02,
    0x00,
    0x69,
    0x53,
    0x08,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0xb5,
    0x00,
    0x69,
    0xff,
    0x21,
    0x02,
    0x31,
    0x09,
    0x5c,
    0x09,
    0x29,
    0x05,
    0xd1,
    0x01,
    0x21,
    0x00,
    0x22,
    0x8e,
    0x46,
    0xcb,
    0x4b,
    0xfe,
    0x44,
    0x18,
    0x47,
    0x00,
    0xbd,
    0xca,
    0x4a,
    0x11,
    0x88,
    0x01,
    0x20,
    0x40,
    0x03,
    0x08,
    0x43,
    0x10,
    0x80,
    0xf7,
    0x46,
    0x30,
    0xb5,
    0x00,
    0x69,
    0xf4,
    0x21,
    0x08,
    0x5c,
    0x01,
    0x28,
    0x16,
    0xd1,
    0xc5,
    0x48,
    0x00,
    0x78,
    0x03,
    0x28,
    0x12,
    0xd0,
    0x00,
    0x25,
    0x28,
    0x1c,
    0xc3,
    0x49,
    0x01,
    0x24,
    0xa6,
    0x46,
    0xc2,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x00,
    0x28,
    0x08,
    0xd0,
    0xc1,
    0x49,
    0xc1,
    0x4a,
    0xbb,
    0x32,
    0x20,
    0x20,
    0x2b,
    0x1c,
    0xa6,
    0x46,
    0xc0,
    0x4c,
    0xfe,
    0x44,
    0x20,
    0x47,
    0x30,
    0xbd,
    0x70,
    0xb5,
    0x85,
    0x69,
    0x00,
    0x7d,
    0x80,
    0x1f,
    0x11,
    0xd0,
    0x47,
    0x38,
    0x2e,
    0xd1,
    0xa9,
    0x79,
    0x28,
    0x20,
    0x48,
    0x43,
    0xba,
    0x4a,
    0x10,
    0x18,
    0x23,
    0x22,
    0x12,
    0x5c,
    0x01,
    0x2a,
    0x25,
    0xd1,
    0x80,
    0x7b,
    0x00,
    0x28,
    0x22,
    0xd0,
    0xb6,
    0x4a,
    0x00,
    0x20,
    0x50,
    0x54,
    0x70,
    0xbd,
    0x01,
    0x24,
    0xa6,
    0x46,
    0xef,
    0x48,
    0xfe,
    0x44,
    0x00,
    0x47,

    0x01,
    0x05,
    0xff,
    0xff,
    0xca,
    0x66,
    0x08,
    0x00,
    0xfa,
    0x01,
    0x28,
    0x05,
    0xd0,
    0xa6,
    0x46,
    0xec,
    0x48,
    0xfe,
    0x44,
    0x00,
    0x47,
    0x04,
    0x28,
    0x11,
    0xd1,
    0xe8,
    0x78,
    0x00,
    0x28,
    0x0e,
    0xd1,
    0x0e,
    0x26,
    0x31,
    0x1c,
    0xe9,
    0x4d,
    0x28,
    0x1c,
    0x14,
    0x38,
    0xa6,
    0x46,
    0xe6,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x28,
    0x1c,
    0x31,
    0x1c,
    0xa6,
    0x46,
    0xe3,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x70,
    0xbd,
    0x70,
    0xb5,
    0x01,
    0x1c,
    0x88,
    0x69,
    0x89,
    0x8a,
    0xe1,
    0x4a,
    0x89,
    0x1a,
    0x1c,
    0xd0,
    0x1c,
    0x39,
    0x20,
    0xd1,
    0xc5,
    0x7a,
    0x01,
    0x21,
    0x0c,
    0x1c,
    0x8e,
    0x46,
    0xde,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x06,
    0x1c,
    0x10,
    0x20,
    0xa6,
    0x46,
    0xdc,
    0x49,
    0xfe,
    0x44,
    0x08,
    0x47,
    0x00,
    0x2d,
    0x11,
    0xd0,
    0x02,
    0x2e,
    0x0f,
    0xd0,
    0xd9,
    0x49,
    0xda,
    0x4a,
    0xd9,
    0x32,
    0x20,
    0x20,
    0x00,
    0x23,
    0xa6,
    0x46,
    0x92,
    0x4c,
    0xfe,
    0x44,
    0x20,
    0x47,
    0x70,
    0xbd,
    0xc0,
    0x7a,
    0x00,
    0x28,
    0x02,
    0xd1,
    0x00,
    0x20,
    0xd4,
    0x49,
    0x08,
    0x70,
    0x70,
    0xbd,
    0x00,
    0xb5,
    0x00,
    0x69,
    0xff,
    0x21,
    0x04,
    0x31,
    0x09,
    0x5c,
    0x06,
    0x29,
    0x06,
    0xd1,
    0xff,
    0x21,
    0x05,
    0x31,
    0x0a,
    0x5c,
    0x2c,
    0x2a,
    0x01,
    0xd1,
    0x2d,
    0x22,
    0x0a,
    0x54,
    0xff,
    0x21,
    0x05,
    0x31,
    0x09,
    0x5c,
    0x34,
    0x29,
    0x11,
    0xd1,
    0xff,
    0x21,
    0x0b,
    0x31,
    0x09,
    0x5c,
    0x91,
    0x29,
    0x0c,
    0xd1,
    0xf1,
    0x21,
    0x09,
    0x5c,
    0x60,
    0x22,
    0x4a,
    0x43,
    0xc6,
    0x4b,
    0x00,
    0x21,
    0x99,
    0x54,
    0x06,
    0x21,
    0x01,
    0x22,
    0x96,
    0x46,
    0xc4,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x00,
    0xbd,
    0xf0,
    0xb5,
    0x06,
    0x1c,
    0xf7,
    0x69,
    0x08,
    0x20,
    0xc0,
    0x19,
    0x01,
    0x24,
    0xa6,
    0x46,
    0xbf,
    0x49,
    0xfe,
    0x44,
    0x08,
    0x47,
    0xc1,
    0x7b,
    0x09,
    0x02,
    0x80,
    0x7b,
    0x08,
    0x43,
    0x05,
    0x04,
    0x2d,
    0x0c,
    0x02,
    0x2d,

    0x01,
    0x05,
    0xff,
    0xff,
    0xc4,
    0x67,
    0x08,
    0x00,
    0xfa,
    0x12,
    0xd0,
    0xbb,
    0x48,
    0x00,
    0x88,
    0xa8,
    0x42,
    0x0e,
    0xd1,
    0xba,
    0x48,
    0x00,
    0x78,
    0x01,
    0x28,
    0x0a,
    0xd1,
    0xb9,
    0x48,
    0x82,
    0x8f,
    0x81,
    0x6b,
    0x08,
    0x1c,
    0x10,
    0x43,
    0x04,
    0xd0,
    0x38,
    0x1c,
    0xa6,
    0x46,
    0xb6,
    0x4b,
    0xfe,
    0x44,
    0x18,
    0x47,
    0x35,
    0x60,
    0xb5,
    0x48,
    0x24,
    0x30,
    0x30,
    0x62,
    0xf0,
    0xbd,
    0xf0,
    0xb5,
    0x85,
    0xb0,
    0x04,
    0x90,
    0x87,
    0x69,
    0x81,
    0x8a,
    0xb1,
    0x48,
    0x08,
    0x1a,
    0x74,
    0xd0,
    0xb1,
    0x49,
    0x40,
    0x1a,
    0x28,
    0xd0,
    0xb0,
    0x49,
    0x40,
    0x1a,
    0x1d,
    0xd1,
    0xb0,
    0x48,
    0x05,
    0x1c,
    0x84,
    0x3d,
    0x00,
    0x78,
    0x02,
    0x28,
    0x17,
    0xd1,
    0x01,
    0x24,
    0xa6,
    0x46,
    0xad,
    0x48,
    0xfe,
    0x44,
    0x00,
    0x47,
    0x00,
    0x28,
    0x10,
    0xd1,
    0xa6,
    0x46,
    0xab,
    0x48,
    0xfe,
    0x44,
    0x00,
    0x47,
    0x00,
    0x28,
    0x0a,
    0xd1,
    0xa6,
    0x46,
    0xa9,
    0x48,
    0xfe,
    0x44,
    0x00,
    0x47,
    0x00,
    0x28,
    0x04,
    0xd1,
    0x28,
    0x78,
    0x00,
    0x28,
    0x01,
    0xd1,
    0xa8,
    0x78,
    0x00,
    0x28,
    0x00,
    0xd0,
    0x8b,
    0xe0,
    0xa6,
    0x20,
    0xa6,
    0x46,
    0xa3,
    0x49,
    0xfe,
    0x44,
    0x08,
    0x47,
    0x85,
    0xe0,
    0x95,
    0x48,
    0x51,
    0x38,
    0x00,
    0x78,
    0x2a,
    0x28,
    0x7c,
    0xd1,
    0x0e,
    0x20,
    0xc6,
    0x19,
    0x44,
    0x20,
    0x0c,
    0x21,
    0x1a,
    0x22,
    0x01,
    0x24,
    0xa6,
    0x46,
    0x9c,
    0x4b,
    0xfe,
    0x44,
    0x18,
    0x47,
    0x9b,
    0x48,
    0x81,
    0x78,
    0xc2,
    0x78,
    0x9b,
    0x48,
    0xa6,
    0x46,
    0x9b,
    0x4b,
    0xfe,
    0x44,
    0x18,
    0x47,
    0x06,
    0x20,
    0xb8,
    0x80,
    0x08,
    0x25,
    0x35,
    0x70,
    0x01,
    0x36,
    0x30,
    0x1c,
    0x00,
    0x21,
    0xa6,
    0x46,
    0x96,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x06,
    0x1c,
    0x35,
    0x70,
    0x01,
    0x36,
    0x30,
    0x1c,
    0x0d,
    0x21,
    0xa6,
    0x46,
    0x92,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x06,
    0x1c,
    0xa6,
    0x46,
    0x91,
    0x48,
    0xfe,
    0x44,
    0x00,
    0x47,

    0x01,
    0x05,
    0xff,
    0xff,
    0xbe,
    0x68,
    0x08,
    0x00,
    0xfa,
    0x81,
    0x02,
    0x8a,
    0x48,
    0xc0,
    0x78,
    0x40,
    0x06,
    0x40,
    0x0e,
    0x08,
    0x43,
    0x8c,
    0x49,
    0x01,
    0x43,
    0x09,
    0x04,
    0x09,
    0x0c,
    0x30,
    0x1c,
    0xa6,
    0x46,
    0x88,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x7d,
    0x80,
    0x38,
    0x1c,
    0xff,
    0x21,
    0x02,
    0x31,
    0x00,
    0x22,
    0xa6,
    0x46,
    0x86,
    0x4b,
    0xfe,
    0x44,
    0x18,
    0x47,
    0x38,
    0xe0,
    0x38,
    0x1c,
    0x00,
    0x21,
    0x6a,
    0x46,
    0x01,
    0x24,
    0xa6,
    0x46,
    0x84,
    0x4b,
    0xfe,
    0x44,
    0x18,
    0x47,
    0x02,
    0xa8,
    0x00,
    0x21,
    0x06,
    0x22,
    0xa6,
    0x46,
    0x81,
    0x4b,
    0xfe,
    0x44,
    0x18,
    0x47,
    0x00,
    0x25,
    0x02,
    0xe0,
    0x68,
    0x1c,
    0x05,
    0x04,
    0x2d,
    0x0c,
    0x66,
    0x48,
    0x4f,
    0x38,
    0x00,
    0x78,
    0x85,
    0x42,
    0x23,
    0xda,
    0x11,
    0x20,
    0x40,
    0x01,
    0x68,
    0x43,
    0x7a,
    0x49,
    0x0e,
    0x18,
    0x10,
    0x20,
    0x80,
    0x19,
    0x69,
    0x46,
    0xa6,
    0x46,
    0x78,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x00,
    0x28,
    0xe9,
    0xd1,
    0x68,
    0x46,
    0x02,
    0xa9,
    0xa6,
    0x46,
    0x74,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x00,
    0x28,
    0xe1,
    0xd0,
    0xb0,
    0x78,
    0x01,
    0x28,
    0xde,
    0xd0,
    0x38,
    0x1c,
    0x5c,
    0x49,
    0x3a,
    0x22,
    0xa6,
    0x46,
    0x6f,
    0x4b,
    0xfe,
    0x44,
    0x18,
    0x47,
    0x69,
    0x49,
    0xe2,
    0x31,
    0x04,
    0x98,
    0x01,
    0x62,
    0x05,
    0xb0,
    0xf0,
    0xbd,
    0xc0,
    0x46,
    0xdd,
    0x9d,
    0x00,
    0x00,
    0x3e,
    0xa6,
    0x1b,
    0x00,
    0x18,
    0x32,
    0x08,
    0x00,
    0xce,
    0x04,
    0x00,
    0x00,
    0x23,
    0xb9,
    0x02,
    0x00,
    0xf1,
    0x6b,
    0x08,
    0x00,
    0xfd,
    0x79,
    0x00,
    0x00,
    0x35,
    0x6b,
    0x08,
    0x00,
    0xd4,
    0x1d,
    0x08,
    0x00,
    0x94,
    0x54,
    0x08,
    0x00,
    0xfe,
    0xb5,
    0x00,
    0x90,
    0x81,
    0x69,
    0x01,
    0x91,
    0x4c,
    0x78,
    0xc6,
    0x69,
    0x25,
    0x20,
    0x20,
    0x1a,
    0x5d,
    0x49,
    0x32,
    0xd0,
    0x01,
    0x38,
    0x68,
    0xd1,
    0x05,
    0x23,
    0x03,
    0x20,
    0x1a,
    0x1c,
    0x01,
    0x25,

    0x01,
    0x05,
    0xff,
    0xff,
    0xb8,
    0x69,
    0x08,
    0x00,
    0xfa,
    0xae,
    0x46,
    0x5a,
    0x4f,
    0xfe,
    0x44,
    0x38,
    0x47,
    0x04,
    0x20,
    0xb0,
    0x80,
    0x0c,
    0x20,
    0x87,
    0x19,
    0x61,
    0x00,
    0x01,
    0x98,
    0x00,
    0x78,
    0x08,
    0x43,
    0x38,
    0x70,
    0x08,
    0x20,
    0x78,
    0x70,
    0x02,
    0x37,
    0x38,
    0x1c,
    0x0d,
    0x21,
    0xae,
    0x46,
    0x46,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x07,
    0x1c,
    0xae,
    0x46,
    0x45,
    0x48,
    0xfe,
    0x44,
    0x00,
    0x47,
    0x82,
    0x02,
    0x4d,
    0x48,
    0x00,
    0x78,
    0x40,
    0x06,
    0x41,
    0x0e,
    0x11,
    0x43,
    0x40,
    0x48,
    0x08,
    0x43,
    0x01,
    0x04,
    0x09,
    0x0c,
    0x38,
    0x1c,
    0xae,
    0x46,
    0x3c,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x03,
    0x20,
    0x02,
    0x90,
    0x2e,
    0xe0,
    0x03,
    0x20,
    0x02,
    0x90,
    0x04,
    0x22,
    0x13,
    0x1c,
    0x01,
    0x25,
    0xae,
    0x46,
    0x41,
    0x4f,
    0xfe,
    0x44,
    0x38,
    0x47,
    0x04,
    0x20,
    0xb0,
    0x80,
    0x0c,
    0x20,
    0x87,
    0x19,
    0x61,
    0x00,
    0x01,
    0x98,
    0x00,
    0x78,
    0x08,
    0x43,
    0x38,
    0x70,
    0x08,
    0x20,
    0x78,
    0x70,
    0x02,
    0x37,
    0x38,
    0x1c,
    0x0d,
    0x21,
    0xae,
    0x46,
    0x2d,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x07,
    0x1c,
    0xae,
    0x46,
    0x2c,
    0x48,
    0xfe,
    0x44,
    0x00,
    0x47,
    0x82,
    0x02,
    0x34,
    0x48,
    0x00,
    0x78,
    0x40,
    0x06,
    0x41,
    0x0e,
    0x11,
    0x43,
    0x27,
    0x48,
    0x08,
    0x43,
    0x01,
    0x04,
    0x09,
    0x0c,
    0x38,
    0x1c,
    0xae,
    0x46,
    0x23,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x06,
    0x20,
    0x70,
    0x80,
    0x02,
    0x98,
    0x30,
    0x80,
    0x2d,
    0x48,
    0x2c,
    0x49,
    0x09,
    0x18,
    0x00,
    0x98,
    0x01,
    0x62,
    0xfe,
    0xbd,
    0x8f,
    0x8d,
    0x01,
    0x00,
    0xfd,
    0x06,
    0x05,
    0x00,
    0x14,
    0x05,
    0x1a,
    0x00,
    0xa2,
    0xfd,
    0x00,
    0x00,
    0x65,
    0x2d,
    0x00,
    0x00,
    0x7d,
    0xca,
    0x03,
    0x00,
    0x31,
    0x6c,
    0x08,
    0x00,
    0x79,
    0x47,
    0x00,
    0x00,
    0x78,
    0x24,
    0x08,
    0x00,
    0x76,
    0xa0,
    0x1b,
    0x00,
    0xc5,
    0x8e,
    0x00,
    0x00,
    0x5b,
    0x19,

    0x01,
    0x05,
    0xff,
    0xff,
    0xb2,
    0x6a,
    0x08,
    0x00,
    0xfa,
    0x04,
    0x00,
    0xba,
    0x53,
    0x08,
    0x00,
    0x90,
    0xa1,
    0x1b,
    0x00,
    0xa8,
    0x59,
    0x08,
    0x00,
    0x25,
    0x6f,
    0x04,
    0x00,
    0x79,
    0x6c,
    0x04,
    0x00,
    0x05,
    0x04,
    0x00,
    0x00,
    0xfc,
    0x0b,
    0x00,
    0x00,
    0x1d,
    0x10,
    0x00,
    0x00,
    0x45,
    0x10,
    0x08,
    0x00,
    0xc1,
    0x72,
    0x03,
    0x00,
    0x1b,
    0x5f,
    0x03,
    0x00,
    0x53,
    0x38,
    0x02,
    0x00,
    0x21,
    0xf0,
    0x04,
    0x00,
    0xdb,
    0x8e,
    0x04,
    0x00,
    0xfc,
    0x53,
    0x08,
    0x00,
    0xc6,
    0x02,
    0x00,
    0x00,
    0x8d,
    0x8f,
    0x04,
    0x00,
    0xf9,
    0x2d,
    0x00,
    0x00,
    0x00,
    0x82,
    0xff,
    0xff,
    0xa9,
    0x57,
    0x05,
    0x00,
    0xed,
    0x49,
    0x02,
    0x00,
    0x25,
    0x00,
    0x00,
    0x00,
    0x99,
    0x2d,
    0x00,
    0x00,
    0xe9,
    0x63,
    0x05,
    0x00,
    0x00,
    0x00,
    0x08,
    0x00,
    0x49,
    0x8f,
    0x03,
    0x00,
    0x85,
    0x48,
    0x02,
    0x00,
    0xc5,
    0x05,
    0x00,
    0x00,
    0x31,
    0x90,
    0x04,
    0x00,
    0xff,
    0x53,
    0x08,
    0x00,
    0x4e,
    0x05,
    0x00,
    0x00,
    0xb5,
    0xcc,
    0x00,
    0x00,
    0x40,
    0x1e,
    0x80,
    0x00,
    0x8c,
    0x4b,
    0x19,
    0x50,
    0x8a,
    0x49,
    0x0a,
    0x50,
    0xf7,
    0x46,
    0xf0,
    0xb5,
    0x01,
    0x1c,
    0x88,
    0x69,
    0x82,
    0x88,
    0x53,
    0x04,
    0x5b,
    0x0c,
    0x88,
    0x4e,
    0x88,
    0x4f,
    0x89,
    0x4d,
    0x03,
    0xd0,
    0x60,
    0x2b,
    0x01,
    0xdc,
    0xb2,
    0x42,
    0x14,
    0xd0,
    0x82,
    0x88,
    0x01,
    0x23,
    0x1b,
    0x03,
    0x54,
    0x04,
    0x64,
    0x0f,
    0x24,
    0x03,
    0x9c,
    0x42,
    0x08,
    0xdb,
    0x3b,
    0x1c,
    0x01,
    0x33,
    0x54,
    0x04,
    0x24,
    0x0d,
    0xe4,
    0x00,
    0x9c,
    0x42,
    0x01,
    0xda,
    0xba,
    0x42,
    0x03,
    0xd0,
    0xff,
    0x20,
    0x88,
    0x60,
    0xe8,
    0x1d,
    0xf0,
    0xbd,
    0x01,
    0x24,
    0xa6,
    0x46,
    0x7b,
    0x49,
    0xfe,
    0x44,
    0x08,
    0x47,
    0x38,
    0x1c,
    0xa6,
    0x46,
    0x7a,
    0x49,
    0xfe,
    0x44,
    0x08,
    0x47,
    0x30,
    0x1c,
    0xa6,
    0x46,
    0x77,
    0x49,
    0xfe,
    0x44,
    0x08,
    0x47,
    0xa6,
    0x46,
    0x76,
    0x48,
    0xfe,
    0x44,

    0x01,
    0x05,
    0xff,
    0xff,
    0xac,
    0x6b,
    0x08,
    0x00,
    0xfa,
    0x00,
    0x47,
    0x38,
    0x1c,
    0xa6,
    0x46,
    0x73,
    0x49,
    0xfe,
    0x44,
    0x08,
    0x47,
    0xe8,
    0x48,
    0x01,
    0x68,
    0x30,
    0x1c,
    0xa6,
    0x46,
    0x71,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x71,
    0x48,
    0x40,
    0x19,
    0xf0,
    0xbd,
    0x01,
    0x1c,
    0x0a,
    0x7d,
    0x6f,
    0x48,
    0x00,
    0x2a,
    0x02,
    0xd0,
    0xc9,
    0x68,
    0x01,
    0x29,
    0x01,
    0xd0,
    0x4f,
    0x30,
    0xf7,
    0x46,
    0x31,
    0x30,
    0xf7,
    0x46,
    0x41,
    0x68,
    0x02,
    0x39,
    0x41,
    0x60,
    0xe9,
    0x48,
    0x3f,
    0x30,
    0xf7,
    0x46,
    0x1c,
    0xb5,
    0x41,
    0x68,
    0xe7,
    0x4c,
    0x00,
    0x29,
    0x17,
    0xd0,
    0x41,
    0x69,
    0xb0,
    0x20,
    0x40,
    0x18,
    0xb8,
    0x31,
    0x6a,
    0x46,
    0x01,
    0x23,
    0x9e,
    0x46,
    0xe9,
    0x4b,
    0xfe,
    0x44,
    0x18,
    0x47,
    0x00,
    0x99,
    0xe8,
    0x48,
    0xe4,
    0x38,
    0x41,
    0x43,
    0x68,
    0x46,
    0x80,
    0x88,
    0x41,
    0x18,
    0xff,
    0x20,
    0xae,
    0x30,
    0x81,
    0x42,
    0x02,
    0xd9,
    0x20,
    0x1c,
    0xbf,
    0x30,
    0x1c,
    0xbd,
    0x20,
    0x1c,
    0xdf,
    0x30,
    0x1c,
    0xbd,
    0x10,
    0xb5,
    0x04,
    0x1c,
    0xc8,
    0x68,
    0x0a,
    0x21,
    0x01,
    0x22,
    0x96,
    0x46,
    0xde,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x00,
    0x28,
    0x00,
    0xd1,
    0x8c,
    0x20,
    0xa0,
    0x60,
    0xdc,
    0x48,
    0xdb,
    0x30,
    0x10,
    0xbd,
    0xdc,
    0x49,
    0x04,
    0x39,
    0x09,
    0x78,
    0x00,
    0x29,
    0x01,
    0xd1,
    0x00,
    0x21,
    0x41,
    0x60,
    0x41,
    0x68,
    0x42,
    0x69,
    0x51,
    0x1a,
    0x41,
    0x60,
    0xd6,
    0x48,
    0x55,
    0x30,
    0xf7,
    0x46,
    0xd6,
    0x49,
    0x09,
    0x78,
    0x00,
    0x29,
    0x04,
    0xd1,
    0x01,
    0x7d,
    0xd3,
    0x48,
    0x02,
    0x30,
    0xff,
    0x22,
    0x42,
    0x54,
    0xd3,
    0x48,
    0x4f,
    0x30,
    0xf7,
    0x46,
    0x01,
    0x1c,
    0x8a,
    0x69,
    0x4b,
    0x68,
    0xd1,
    0x48,
    0x9a,
    0x42,
    0x01,
    0xd9,
    0x3b,
    0x30,
    0xf7,
    0x46,
    0xca,
    0x60,
    0x79,
    0x30,
    0xf7,
    0x46,
    0xcf,
    0x48,
    0xcd,
    0x49,
    0x08,
    0x80,
    0xce,
    0x48,
    0xff,
    0x30,
    0xde,
    0x30,

    0x01,
    0x05,
    0xff,
    0xff,
    0xa6,
    0x6c,
    0x08,
    0x00,
    0xfa,
    0xf7,
    0x46,
    0xc2,
    0x69,
    0xff,
    0x21,
    0x11,
    0x31,
    0x8b,
    0x5c,
    0xcb,
    0x49,
    0x5b,
    0x08,
    0x08,
    0xd3,
    0xff,
    0x23,
    0x02,
    0x33,
    0x9a,
    0x5c,
    0x02,
    0x2a,
    0x03,
    0xd0,
    0x01,
    0x2a,
    0x01,
    0xd0,
    0x03,
    0x2a,
    0x02,
    0xd1,
    0x08,
    0x1c,
    0x5b,
    0x30,
    0xf7,
    0x46,
    0xff,
    0x22,
    0x42,
    0x60,
    0x08,
    0x1c,
    0x39,
    0x30,
    0xf7,
    0x46,
    0x00,
    0xb5,
    0x40,
    0x68,
    0x01,
    0x21,
    0x8e,
    0x46,
    0xc0,
    0x49,
    0xfe,
    0x44,
    0x08,
    0x47,
    0xc0,
    0x48,
    0x57,
    0x30,
    0x00,
    0xbd,
    0x02,
    0x8a,
    0x01,
    0x79,
    0x0a,
    0x29,
    0x00,
    0xdb,
    0x0a,
    0x21,
    0xbd,
    0x48,
    0x8a,
    0x42,
    0x01,
    0xdd,
    0x5f,
    0x30,
    0xf7,
    0x46,
    0x5b,
    0x30,
    0xf7,
    0x46,
    0xf0,
    0xb5,
    0x01,
    0x24,
    0xa6,
    0x46,
    0xb9,
    0x48,
    0xfe,
    0x44,
    0x00,
    0x47,
    0x01,
    0x28,
    0x05,
    0xd0,
    0xa6,
    0x46,
    0xb6,
    0x48,
    0xfe,
    0x44,
    0x00,
    0x47,
    0x04,
    0x28,
    0x19,
    0xd1,
    0x02,
    0x26,
    0xb4,
    0x4d,
    0x28,
    0x79,
    0x00,
    0x28,
    0x11,
    0xd0,
    0xe8,
    0x7a,
    0x06,
    0x28,
    0x0e,
    0xd1,
    0x0e,
    0x20,
    0x01,
    0x1c,
    0xb1,
    0x4f,
    0x38,
    0x1c,
    0x14,
    0x38,
    0xa6,
    0x46,
    0xae,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x38,
    0x1c,
    0x0e,
    0x21,
    0xa6,
    0x46,
    0xab,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x70,
    0x35,
    0x01,
    0x3e,
    0xe7,
    0xd1,
    0xa6,
    0x46,
    0xaa,
    0x48,
    0xfe,
    0x44,
    0x00,
    0x47,
    0xa9,
    0x49,
    0x0b,
    0x48,
    0x54,
    0x30,
    0x40,
    0x18,
    0xf0,
    0xbd,
    0xc0,
    0x46,
    0x04,
    0xf3,
    0x1a,
    0x00,
    0x80,
    0x7b,
    0x08,
    0x00,
    0x03,
    0x80,
    0x00,
    0x00,
    0x17,
    0x10,
    0x00,
    0x00,
    0xc9,
    0xfb,
    0x04,
    0x00,
    0xbb,
    0x15,
    0x04,
    0x00,
    0x7d,
    0xca,
    0x03,
    0x00,
    0x05,
    0x43,
    0x02,
    0x00,
    0x0b,
    0xc9,
    0x03,
    0x00,
    0xab,
    0x02,
    0x00,
    0x00,
    0xb1,
    0x33,
    0x02,
    0x00,
    0xf0,
    0xb5,
    0x8d,
    0xb0,
    0x01,
    0x90,
    0x81,
    0x69,
    0x02,
    0x91,
    0x01,
    0x7d,

    0x01,
    0x05,
    0xff,
    0xff,
    0xa0,
    0x6d,
    0x08,
    0x00,
    0xfa,
    0x03,
    0x91,
    0x42,
    0x68,
    0x00,
    0x92,
    0x80,
    0x8b,
    0x40,
    0x00,
    0x04,
    0x90,
    0x6b,
    0x48,
    0x83,
    0x30,
    0x00,
    0x78,
    0x40,
    0x00,
    0x05,
    0x90,
    0x00,
    0x29,
    0x01,
    0xd1,
    0x00,
    0x20,
    0xe1,
    0xe0,
    0x04,
    0x98,
    0x02,
    0x04,
    0x12,
    0x0c,
    0x06,
    0x92,
    0x02,
    0x98,
    0x03,
    0x99,
    0x6b,
    0x46,
    0x01,
    0x24,
    0xa6,
    0x46,
    0x8e,
    0x4d,
    0xfe,
    0x44,
    0x28,
    0x47,
    0x07,
    0x90,
    0x00,
    0x9e,
    0x00,
    0x20,
    0x08,
    0x90,
    0x7e,
    0x48,
    0x09,
    0x90,
    0x0a,
    0x90,
    0x7f,
    0xe0,
    0x09,
    0x98,
    0x00,
    0x28,
    0x2b,
    0xd0,
    0x0b,
    0x98,
    0x09,
    0x90,
    0x28,
    0xe0,
    0x05,
    0x98,
    0x87,
    0x42,
    0x25,
    0xdb,
    0x90,
    0x79,
    0x03,
    0x28,
    0x01,
    0xd0,
    0x01,
    0x28,
    0x20,
    0xd1,
    0x79,
    0x19,
    0x05,
    0x98,
    0x08,
    0x1a,
    0x07,
    0x99,
    0xa6,
    0x46,
    0x80,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x07,
    0x1c,
    0x28,
    0x1c,
    0x07,
    0x99,
    0xa6,
    0x46,
    0x7d,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x01,
    0x04,
    0x09,
    0x0c,
    0x3a,
    0x04,
    0x12,
    0x0c,
    0x00,
    0x20,
    0xa6,
    0x46,
    0x79,
    0x4b,
    0xfe,
    0x44,
    0x18,
    0x47,
    0x00,
    0x28,
    0x04,
    0xd1,
    0x0a,
    0x98,
    0x00,
    0x28,
    0x03,
    0xd0,
    0x0a,
    0x97,
    0x01,
    0xe0,
    0x00,
    0x20,
    0x0a,
    0x90,
    0xb6,
    0x68,
    0x00,
    0x2e,
    0x03,
    0xd0,
    0x30,
    0x88,
    0x07,
    0x99,
    0x88,
    0x42,
    0x49,
    0xdb,
    0x08,
    0x98,
    0x00,
    0x28,
    0x46,
    0xd1,
    0x5f,
    0x49,
    0x09,
    0x98,
    0x88,
    0x42,
    0x42,
    0xd1,
    0x0a,
    0x98,
    0x88,
    0x42,
    0x3f,
    0xd1,
    0x03,
    0x98,
    0x00,
    0x28,
    0x2c,
    0xd0,
    0x02,
    0x9d,
    0x03,
    0x98,
    0x0c,
    0x90,
    0x00,
    0x27,
    0x28,
    0x88,
    0x0b,
    0x90,
    0x04,
    0x99,
    0xa6,
    0x46,
    0x64,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x00,
    0x28,
    0x07,
    0xd0,
    0x0b,
    0x99,
    0x04,
    0x98,
    0xa6,
    0x46,
    0x60,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x00,
    0x28,
    0x11,
    0xd1,
    0x08,
    0x98,
    0xb8,
    0x42,

    0x01,
    0x05,
    0xff,
    0xff,
    0x9a,
    0x6e,
    0x08,
    0x00,
    0xfa,
    0x09,
    0xd0,
    0x08,
    0x98,
    0xc1,
    0x00,
    0x02,
    0x98,
    0x40,
    0x18,
    0x29,
    0x1c,
    0x08,
    0x22,
    0xa6,
    0x46,
    0x5b,
    0x4b,
    0xfe,
    0x44,
    0x18,
    0x47,
    0x08,
    0x98,
    0x40,
    0x1c,
    0x00,
    0x06,
    0x00,
    0x0e,
    0x08,
    0x90,
    0x08,
    0x35,
    0x01,
    0x37,
    0x0c,
    0x98,
    0x01,
    0x38,
    0x0c,
    0x90,
    0xd6,
    0xd1,
    0x08,
    0x98,
    0x00,
    0x28,
    0x0c,
    0xd0,
    0x02,
    0x98,
    0x08,
    0x99,
    0x06,
    0x9a,
    0x6b,
    0x46,
    0xa6,
    0x46,
    0x4d,
    0x4d,
    0xfe,
    0x44,
    0x28,
    0x47,
    0x07,
    0x90,
    0x00,
    0x9e,
    0x3d,
    0x48,
    0x09,
    0x90,
    0x0a,
    0x90,
    0x00,
    0x2e,
    0x3a,
    0xd0,
    0x35,
    0x88,
    0x07,
    0x98,
    0x85,
    0x42,
    0x36,
    0xda,
    0xb0,
    0x68,
    0x00,
    0x28,
    0x05,
    0xd0,
    0x00,
    0x88,
    0x07,
    0x99,
    0x88,
    0x42,
    0x01,
    0xdc,
    0x47,
    0x1b,
    0x04,
    0xe0,
    0x07,
    0x98,
    0x40,
    0x1b,
    0x00,
    0x99,
    0x09,
    0x88,
    0x0f,
    0x18,
    0x72,
    0x68,
    0x91,
    0x88,
    0x05,
    0x98,
    0x40,
    0x18,
    0x87,
    0x42,
    0x00,
    0xda,
    0x6a,
    0xe7,
    0x48,
    0x19,
    0x07,
    0x99,
    0xa6,
    0x46,
    0x3b,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x0b,
    0x90,
    0x79,
    0x19,
    0x05,
    0x98,
    0x08,
    0x1a,
    0x07,
    0x99,
    0xa6,
    0x46,
    0x36,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0x02,
    0x04,
    0x12,
    0x0c,
    0x0b,
    0x98,
    0x01,
    0x04,
    0x09,
    0x0c,
    0x00,
    0x20,
    0xa6,
    0x46,
    0x32,
    0x4b,
    0xfe,
    0x44,
    0x18,
    0x47,
    0x00,
    0x28,
    0x00,
    0xd1,
    0x48,
    0xe7,
    0x00,
    0x20,
    0x09,
    0x90,
    0x06,
    0xe0,
    0xc0,
    0x46,
    0xe0,
    0x31,
    0x08,
    0x00,
    0x1d,
    0x48,
    0x09,
    0x99,
    0x81,
    0x42,
    0x02,
    0xd0,
    0x09,
    0x98,
    0x0a,
    0x90,
    0x02,
    0xe0,
    0x0a,
    0x99,
    0x81,
    0x42,
    0x01,
    0xd0,
    0x0a,
    0x98,
    0x04,
    0xe0,
    0x06,
    0x98,
    0xa6,
    0x46,
    0x27,
    0x49,
    0xfe,
    0x44,
    0x08,
    0x47,
    0x01,
    0x99,
    0x48,
    0x60,
    0x20,
    0x48,
    0xff,
    0x30,
    0x10,
    0x30,
    0x0d,
    0xb0,
    0xf0,
    0xbd,
    0xb7,
    0x4b,
    0x04,
    0x00,

    0x01,
    0x05,
    0xff,
    0xf3,
    0x94,
    0x6f,
    0x08,
    0x00,
    0xee,
    0xfd,
    0x79,
    0x00,
    0x00,
    0x22,
    0x49,
    0x09,
    0x78,
    0x2a,
    0x29,
    0x01,
    0xd1,
    0x08,
    0x21,
    0x00,
    0xe0,
    0x06,
    0x21,
    0x41,
    0x60,
    0x1d,
    0x48,
    0x43,
    0x30,
    0xf7,
    0x46,
    0xc0,
    0x46,
    0x4f,
    0x81,
    0x03,
    0x00,
    0xc6,
    0x05,
    0x00,
    0x00,
    0x65,
    0x2d,
    0x00,
    0x00,
    0x79,
    0x47,
    0x00,
    0x00,
    0x0d,
    0x13,
    0x02,
    0x00,
    0x76,
    0x24,
    0x08,
    0x00,
    0xe0,
    0xa0,
    0x1b,
    0x00,
    0x89,
    0x28,
    0x05,
    0x00,
    0x3d,
    0x39,
    0x02,
    0x00,
    0x60,
    0x5b,
    0x08,
    0x00,
    0xff,
    0xff,
    0x00,
    0x00,
    0xd9,
    0xaa,
    0x00,
    0x00,
    0xd5,
    0x75,
    0x00,
    0x00,
    0x23,
    0x01,
    0x05,
    0x00,
    0xb3,
    0x09,
    0x02,
    0x00,
    0xf9,
    0x97,
    0x00,
    0x00,
    0x8f,
    0x8d,
    0x01,
    0x00,
    0xa4,
    0x13,
    0x08,
    0x00,
    0xe5,
    0x06,
    0x05,
    0x00,
    0x14,
    0x05,
    0x1a,
    0x00,
    0x77,
    0xc5,
    0x01,
    0x00,
    0xb9,
    0xc5,
    0x01,
    0x00,
    0x6d,
    0x95,
    0x00,
    0x00,
    0xa1,
    0x95,
    0x01,
    0x00,
    0x95,
    0x49,
    0x05,
    0x00,
    0x21,
    0x96,
    0x01,
    0x00,
    0x5d,
    0x5f,
    0x05,
    0x00,
    0x4d,
    0x96,
    0x01,
    0x00,
    0x7b,
    0x5e,
    0x02,
    0x00,
    0x69,
    0x53,
    0x08,
    0x00,
    0xff,
    0xb5,
    0x68,
    0x46,
    0xff,
    0xf7,
    0xb9,
    0xfb,
    0xff,
    0xbd,
    0xff,
    0xb5,
    0x68,
    0x46,
    0xff,
    0xf7,
    0xde,
    0xfb,
    0xff,
    0xbd,
    0xff,
    0xb5,
    0x68,
    0x46,
    0xff,
    0xf7,
    0xaa,
    0xfc,
    0xff,
    0xbd,
    0xff,
    0xb5,
    0x68,
    0x46,
    0xff,
    0xf7,
    0x84,
    0xfb,
    0xff,
    0xbd,
    0xff,
    0xb5,
    0x68,
    0x46,
    0xff,
    0xf7,
    0xf8,
    0xfa,
    0xff,
    0xbd,
    0xff,
    0xb5,
    0x68,
    0x46,
    0xff,
    0xf7,
    0xe5,
    0xfa,
    0xff,
    0xbd,
    0xff,
    0xb5,
    0x68,
    0x46,
    0xff,
    0xf7,
    0xf5,
    0xfa,
    0xff,
    0xbd,
    0xff,
    0xb5,
    0x68,
    0x46,
    0xff,
    0xf7,
    0x45,
    0xfb,
    0xff,
    0xbd,
    0xff,
    0xb5,
    0x68,
    0x46,
    0xff,
    0xf7,
    0x09,
    0xfb,
    0xff,
    0xbd,

    0x01,
    0x05,
    0xff,
    0x8d,
    0x78,
    0x7b,
    0x08,
    0x00,
    0x88,
    0x00,
    0xb5,
    0xf8,
    0xf0,
    0xa7,
    0xfa,
    0x00,
    0xbd,
    0x43,
    0x6b,
    0x08,
    0x00,
    0xcd,
    0x6b,
    0x08,
    0x00,
    0xd5,
    0x65,
    0x08,
    0x00,
    0xe5,
    0x6b,
    0x08,
    0x00,
    0x51,
    0x6c,
    0x08,
    0x00,
    0x6d,
    0x6c,
    0x08,
    0x00,
    0x85,
    0x6c,
    0x08,
    0x00,
    0x9b,
    0x6c,
    0x08,
    0x00,
    0xa9,
    0x6c,
    0x08,
    0x00,
    0xd9,
    0x6c,
    0x08,
    0x00,
    0xed,
    0x6c,
    0x08,
    0x00,
    0x05,
    0x6d,
    0x08,
    0x00,
    0x95,
    0x6d,
    0x08,
    0x00,
    0x99,
    0x6f,
    0x08,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x31,
    0x6c,
    0x08,
    0x00,

    0x01,
    0x05,
    0xff,
    0x85,
    0x04,
    0xf3,
    0x1a,
    0x00,
    0x80,
    0xce,
    0xfb,
    0x04,
    0x00,
    0xde,
    0x33,
    0x02,
    0x00,
    0x14,
    0x29,
    0x02,
    0x00,
    0xf4,
    0x4b,
    0x04,
    0x00,
    0x60,
    0x13,
    0x02,
    0x00,
    0xd6,
    0x28,
    0x05,
    0x00,
    0x74,
    0x39,
    0x02,
    0x00,
    0x88,
    0xac,
    0x00,
    0x00,
    0x0c,
    0x76,
    0x00,
    0x00,
    0x06,
    0x0a,
    0x02,
    0x00,
    0x50,
    0x98,
    0x00,
    0x00,
    0xb4,
    0xc6,
    0x01,
    0x00,
    0x7a,
    0x95,
    0x00,
    0x00,
    0xb8,
    0x5e,
    0x02,
    0x00,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0x52,
    0x48,
    0x00,
    0x00,

    0x01,
    0x05,
    0xff,
    0xff,
    0x00,
    0x00,
    0x18,
    0x00,
    0xfa,
    0x70,
    0xb5,
    0x25,
    0x4d,
    0xae,
    0x7f,
    0x01,
    0x24,
    0xa6,
    0x46,
    0x21,
    0x48,
    0xfe,
    0x44,
    0x00,
    0x47,
    0xb0,
    0x42,
    0xf8,
    0xd1,
    0x03,
    0x20,
    0x17,
    0x21,
    0x89,
    0x01,
    0xa6,
    0x46,
    0x1d,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0xad,
    0x7f,
    0xa6,
    0x46,
    0x1a,
    0x48,
    0xfe,
    0x44,
    0x00,
    0x47,
    0xa8,
    0x42,
    0xf9,
    0xd1,
    0xfe,
    0xe7,
    0x10,
    0xb5,
    0x19,
    0x49,
    0x08,
    0x1f,
    0x19,
    0x4a,
    0x10,
    0x60,
    0x1c,
    0x48,
    0x02,
    0x1c,
    0x71,
    0x3a,
    0x93,
    0x24,
    0x01,
    0x23,
    0xa3,
    0x54,
    0x16,
    0x4b,
    0x0b,
    0x60,
    0x02,
    0x23,
    0x13,
    0x71,
    0x15,
    0x4b,
    0x4b,
    0x60,
    0x03,
    0x23,
    0x53,
    0x71,
    0x14,
    0x4b,
    0x8b,
    0x60,
    0x04,
    0x23,
    0x03,
    0x70,
    0x14,
    0x4b,
    0xcb,
    0x60,
    0x05,
    0x23,
    0x83,
    0x73,
    0x13,
    0x4b,
    0x0b,
    0x61,
    0x06,
    0x23,
    0x03,
    0x73,
    0x12,
    0x4b,
    0x4b,
    0x61,
    0x07,
    0x23,
    0x43,
    0x71,
    0x11,
    0x4b,
    0x8b,
    0x61,
    0x08,
    0x23,
    0x33,
    0x38,
    0x03,
    0x70,
    0x10,
    0x48,
    0xc8,
    0x61,
    0x09,
    0x20,
    0xd0,
    0x74,
    0x0f,
    0x48,
    0x08,
    0x62,
    0x10,
    0xbd,
    0x25,
    0x86,
    0x04,
    0x00,
    0x1b,
    0x90,
    0x04,
    0x00,
    0x6c,
    0x52,
    0x08,
    0x00,
    0x08,
    0x66,
    0x08,
    0x00,
    0x20,
    0x55,
    0x08,
    0x00,
    0x5b,
    0x70,
    0x08,
    0x00,
    0x6f,
    0x70,
    0x08,
    0x00,
    0x79,
    0x70,
    0x08,
    0x00,
    0x95,
    0x55,
    0x08,
    0x00,
    0x47,
    0x70,
    0x08,
    0x00,
    0x51,
    0x70,
    0x08,
    0x00,
    0x65,
    0x70,
    0x08,
    0x00,
    0x29,
    0x70,
    0x08,
    0x00,
    0x33,
    0x70,
    0x08,
    0x00,
    0x3d,
    0x70,
    0x08,
    0x00,
    0xf0,
    0xb5,
    0x0c,
    0x22,
    0x22,
    0x4e,
    0x32,
    0x70,
    0x1a,
    0x23,
    0x73,
    0x70,
    0x09,
    0x20,
    0xb0,
    0x70,
    0xf2,
    0x70,
    0x03,
    0x20,
    0x20,
    0x4d,
    0x29,
    0x1c,
    0x01,
    0x39,
    0x01,
    0x24,
    0xa6,
    0x46,
    0x1d,
    0x4f,
    0xfe,
    0x44,
    0x38,
    0x47,
    0xb2,
    0x78,
    0xf3,
    0x78,
    0x03,
    0x20,
    0x29,
    0x1c,
    0xa6,
    0x46,

    0x01,
    0x05,
    0xff,
    0x8b,
    0xfa,
    0x00,
    0x18,
    0x00,
    0x86,
    0x19,
    0x4e,
    0xfe,
    0x44,
    0x30,
    0x47,
    0x03,
    0x20,
    0x29,
    0x1c,
    0x01,
    0x31,
    0xa6,
    0x46,
    0x17,
    0x4a,
    0xfe,
    0x44,
    0x10,
    0x47,
    0xa6,
    0x46,
    0x16,
    0x48,
    0xfe,
    0x44,
    0x00,
    0x47,
    0x16,
    0x4b,
    0x00,
    0x21,
    0x08,
    0x1c,
    0x1a,
    0x68,
    0x00,
    0x2a,
    0x04,
    0xd0,
    0x02,
    0x07,
    0x15,
    0x0f,
    0x22,
    0x1c,
    0xaa,
    0x40,
    0x11,
    0x43,
    0x02,
    0x07,
    0x12,
    0x0f,
    0x0f,
    0x2a,
    0x05,
    0xd1,
    0xc5,
    0x08,
    0x06,
    0x22,
    0x2a,
    0x40,
    0x0e,
    0x4d,
    0xa9,
    0x52,
    0x00,
    0x21,
    0x04,
    0x33,
    0x01,
    0x30,
    0x20,
    0x28,
    0xe9,
    0xd3,
    0x0c,
    0x48,
    0x01,
    0x1c,
    0x50,
    0x31,
    0x0c,
    0x70,
    0x0a,
    0x21,
    0x09,
    0x4a,
    0x11,
    0x70,
    0x2a,
    0x21,
    0x01,
    0x70,
    0xf0,
    0xbd,
    0xfc,
    0x53,
    0x08,
    0x00,
    0x31,
    0x90,
    0x04,
    0x00,
    0xc6,
    0x05,
    0x00,
    0x00,
    0x1b,
    0x90,
    0x04,
    0x00,
    0x33,
    0x00,
    0x18,
    0x00,
    0x80,
    0x7b,
    0x08,
    0x00,
    0x84,
    0xf3,
    0x1a,
    0x00,
    0x6d,
    0x22,
    0x08,
    0x00,
    0x69,
    0x53,
    0x08,
    0x00,

    0x01,
    0x83,
    0xff,
    0x14,
    0x79,
    0x7b,
    0x08,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,
    0x00,

    //
    //
    0x01,
    0x0c,
    0xfd,
    0x09,
    0x01,
    0x00,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0x64,
    0x00,

    0x01,
    0x09,
    0xfd,
    0x08,
    0x58,
    0x60,
    0x1a,
    0x00,
    0x00,
    0x10,
    0x00,
    0x10,

    0x01,
    0x09,
    0xfd,
    0x08,
    0x10,
    0x60,
    0x1a,
    0x00,
    0x10,
    0x00,
    0x10,
    0x00,

    0x01,
    0x1c,
    0xfd,
    0x14,
    0xff,
    0x88,
    0x13,
    0x00,
    0x00,
    0xff,
    0x00,
    0x00,
    0x00,
    0xff,
    0xff,
    0xff,
    0xff,
    0xff,
    0x00,
    0xfa,
    0x00,
    0xff,
    0xff,
    0x00,

    //
    //
    // ##--------------------------------------------------------------------------------
    // ## Description:   ORCA_C Commercial PHY FW Initialization Script
    // ##--------------------------------------------------------------------------------
    0x01,
    0x76,
    0xfd,
    0x31,
    0x01,
    0x21,
    0x54,
    0x00,
    0x00,
    0x61,
    0x57,
    0x00,
    0x00,
    0x14,
    0x05,
    0x0a,
    0x05,
    0x00,
    0x07,
    0x06,
    0x0a,
    0x04,
    0x05,
    0x08,
    0x09,
    0x0b,
    0x0c,
    0x0d,
    0x0e,
    0x10,
    0x10,
    0x10,
    0x10,
    0x10,
    0x10,
    0x10,
    0x10,
    0x10,
    0x10,
    0x10,
    0x10,
    0x10,
    0x10,
    0x10,
    0x10,
    0x10,
    0x10,
    0x10,
    0x10,
    0x00,
    0x00,
    0x00,
    0x00,

    // BTstack: added HCI_VS_SET_POWER_VECTOR(GFSK) 0xFD82 template
    0x01,
    0x82,
    0xfd,
    0x14,
    0x00,
    0x9c,
    0x18,
    0xd2,
    0xd2,
    0xd2,
    0xd2,
    0xd2,
    0xd2,
    0xd2,
    0xdc,
    0xe6,
    0xf0,
    0xfa,
    0x04,
    0x0e,
    0x18,
    0xff,
    0x00,
    0x00,

    // BTstack: added HCI_VS_SET_POWER_VECTOR(EDR2) 0xFD82 template
    0x01,
    0x82,
    0xfd,
    0x14,
    0x01,
    0x9c,
    0xce,
    0xce,
    0xce,
    0xce,
    0xce,
    0xce,
    0xce,
    0xce,
    0xd8,
    0xe2,
    0xec,
    0xf6,
    0x00,
    0x0a,
    0x14,
    0xff,
    0x00,
    0x00,

    // BTstack: added HCI_VS_SET_POWER_VECTOR(EDR3) 0xFD82 for EDR3 template
    0x01,
    0x82,
    0xfd,
    0x14,
    0x02,
    0x9c,
    0xce,
    0xce,
    0xce,
    0xce,
    0xce,
    0xce,
    0xce,
    0xce,
    0xd8,
    0xe2,
    0xec,
    0xf6,
    0x00,
    0x0a,
    0x14,
    0xff,
    0x00,
    0x00,

    // BTstack: added HCI_VS_SET_CLASS2_SINGLE_POWER 0xFD87 template
    0x01,
    0x87,
    0xfd,
    0x03,
    0x0d,
    0x0d,
    0x0d,

    0x01,
    0x80,
    0xfd,
    0x06,
    0x00,
    0x01,
    0x00,
    0x00,
    0x00,
    0x01,

    0x01,
    0x80,
    0xfd,
    0x06,
    0x3c,
    0xf0,
    0x5f,
    0x00,
    0x00,
    0x00,

    //
    //
    //
    0x01,
    0x38,
    0xfe,
    0x00,

    //
    // #################################################################
    // ## START of CC2564 Adds-On
    // #################################################################
    //
    // ## Enable fast clock XTAL support
    0x01,
    0x1c,
    0xfd,
    0x14,
    0x01,
    0x88,
    0x13,
    0x00,
    0x00,
    0xd0,
    0x07,
    0x00,
    0x00,
    0xff,
    0xff,
    0x04,
    0xff,
    0xff,
    0xff,
    0xfa,
    0x00,
    0x00,
    0x00,
    0x00,

    //
    // ## Enable eHCILL
    0x01,
    0x2b,
    0xfd,
    0x05,
    0x10,
    0x00,
    0x50,
    0x00,
    0x96,

    //
    0x01,
    0x0c,
    0xfd,
    0x09,
    0x01,
    0x01,
    0x00,
    0xff,
    0xff,
    0xff,
    0xff,
    0x64,
    0x00,

    //
    // #################################################################
    // ## END of CC2564 Adds-On
    // #################################################################
    0x01,
    0x5b,
    0xfd,
    0x02,
    0x01,
    0x01,

    //
    0x01,
    0xdd,
    0xfd,
    0x01,
    0x01,

};

const uint32_t cc256x_init_script_size = 3825;

A module-bluetooth/Bluetooth/glucode/btstack_uart_block_rt1051.cpp => module-bluetooth/Bluetooth/glucode/btstack_uart_block_rt1051.cpp +107 -0
@@ 0,0 1,107 @@
#include <bsp/bluetooth/Bluetooth.hpp>
#include <log/log.hpp>

using namespace bsp;

extern "C"
{

#include "btstack_uart_block_rt1051.h"
#include <hci_transport.h>
#include <btstack_run_loop.h>
#include <btstack_uart_block.h>
#include <stddef.h> // for null
#include <btstack_run_loop_freertos.h>

    // #define DEBUG_UART

    // and it's hci_transport_config_uart_t which is a bit different...
    static int uart_rt1051_init(const btstack_uart_config_t *config)
    {
        LOG_INFO("Create BlueKitchen interface");
        BlueKitchen::getInstance();
        return 0;
    }

    static int uart_rt1051_open()
    {
        LOG_INFO("BlueKitchen uart open");
        BlueKitchen::getInstance()->open();
        return 0;
    }

    static int uart_rt1051_close()
    {
        LOG_INFO("BlueKitchen uart close");
        BlueKitchen::getInstance()->close();
        return 0;
    }

    static void uart_rt1051_set_block_received(void (*handler)(void))
    {
        BlueKitchen::getInstance()->read_ready_cb = handler;
    }

    static void uart_rt1051_set_block_sent(void (*handler)(void))
    {
        BlueKitchen::getInstance()->write_done_cb = handler;
    }

    static int uart_rt1051_set_baudrate(uint32_t baudrate)
    {
        BlueKitchen::getInstance()->set_baudrate(baudrate);
        return 0;
    }

    static int uart_rt1051_set_parity(int pairity)
    {
        // Not implemented
        LOG_INFO("BlueKitchen set pairity: %d", pairity);
        return 0;
    }

    static int uart_rt1051_set_flowcontrol(int flowcontrol)
    {
        LOG_INFO("BlueKitchen set flowcontrol: %d", flowcontrol);
        // BlueKitchen::getInstance()->set_rts(); ??
        return 0;
    }

    static void uart_rt1051_receive_block(uint8_t *buffer, uint16_t len)
    {
#ifdef DEBUG_UART
        LOG_INFO("<-- read: %d", len);
#endif
        BlueKitchen::getInstance()->read(buffer, len);
    }

    static void uart_rt1051_send_block(const uint8_t *buffer, uint16_t length)
    {
#ifdef DEBUG_UART
        LOG_INFO("--> write: %d", length);
#endif
        BlueKitchen::getInstance()->write_blocking((char *)buffer, length);
    }

    static const btstack_uart_block_t btstack_uart_posix = {
        /* int  (*init)(hci_transport_config_uart_t * config); */ uart_rt1051_init,
        /* int  (*open)(void); */ uart_rt1051_open,
        /* int  (*close)(void); */ uart_rt1051_close,
        /* void (*set_block_received)(void (*handler)(void)); */ uart_rt1051_set_block_received,
        /* void (*set_block_sent)(void (*handler)(void)); */ uart_rt1051_set_block_sent,
        /* int  (*set_baudrate)(uint32_t baudrate); */ uart_rt1051_set_baudrate,
        /* int  (*set_parity)(int parity); */ uart_rt1051_set_parity,
        /* int  (*set_flowcontrol)(int flowcontrol); */ NULL, // uart_rt1051_set_flowcontrol,
        /* void (*receive_block)(uint8_t *buffer, uint16_t len); */ uart_rt1051_receive_block,
        /* void (*send_block)(const uint8_t *buffer, uint16_t length); */ uart_rt1051_send_block,
        /* int (*get_supported_sleep_modes); */ NULL,
        /* void (*set_sleep)(btstack_uart_sleep_mode_t sleep_mode); */ NULL,
        /* void (*set_wakeup_handler)(void (*handler)(void)); */ NULL,
    };

    const btstack_uart_block_t *btstack_uart_block_rt1051_instance()
    {
        LOG_INFO("btstack_uart_block_rt1051_instance");
        return &btstack_uart_posix;
    }
};

A module-bluetooth/Bluetooth/glucode/btstack_uart_block_rt1051.h => module-bluetooth/Bluetooth/glucode/btstack_uart_block_rt1051.h +13 -0
@@ 0,0 1,13 @@
#pragma once

#ifdef __cplusplus
extern "C"
{
#endif
#include <btstack_uart_block.h>

    const btstack_uart_block_t *btstack_uart_block_rt1051_instance();

#ifdef __cplusplus
}; // __cplusplus
#endif

A module-bluetooth/Bluetooth/glucode/hal_time_ms.c => module-bluetooth/Bluetooth/glucode/hal_time_ms.c +8 -0
@@ 0,0 1,8 @@
#include <FreeRTOS.h>
#include <task.h>
#include <stdint.h>

uint32_t hal_time_ms(void)
{
    return xTaskGetTickCount();
}

A module-bluetooth/Bluetooth/interface/bluekitchen/GAP.cpp => module-bluetooth/Bluetooth/interface/bluekitchen/GAP.cpp +244 -0
@@ 0,0 1,244 @@
#include <Bluetooth/Device.hpp>
#include <log/log.hpp>
#include <vector>
#include <Bluetooth/Error.hpp>

extern "C"
{
#include "btstack.h"
};

btstack_packet_callback_registration_t cb_handler;
enum DEVICE_STATE
{
    REMOTE_NAME_REQUEST,
    REMOTE_NAME_INQUIRED,
    REMOTE_NAME_FETCHED
};

struct Devicei : public Device
{
  public:
    bd_addr_t address;
    uint8_t pageScanRepetitionMode;
    uint16_t clockOffset;
    enum DEVICE_STATE state;

    Devicei(std::string name = "") : name(name)
    {}
    virtual ~Devicei()
    {}
    void address_set(bd_addr_t *addr)
    {
        memcpy(&address, addr, sizeof address);
    }
    std::string name;
};

std::vector<Devicei> devices;

static int getDeviceIndexForAddress(std::vector<Devicei> &devs, bd_addr_t addr)
{
    int j;
    for (j = 0; j < devs.size(); j++) {
        if (bd_addr_cmp(addr, devs[j].address) == 0) {
            return j;
        }
    }
    return -1;
}

enum STATE
{
    INIT,
    ACTIVE,
    DONE
};
enum STATE state = INIT;

#define INQUIRY_INTERVAL 5
static int start_scan(void)
{
    LOG_INFO("Starting inquiry scan..");
    return gap_inquiry_start(INQUIRY_INTERVAL);
}

static int has_more_remote_name_requests(void)
{
    int i;
    for (i = 0; i < devices.size(); i++) {
        if (devices[i].state == REMOTE_NAME_REQUEST)
            return 1;
    }
    return 0;
}

static void do_next_remote_name_request(void)
{
    int i;
    for (i = 0; i < devices.size(); i++) {
        // remote name request
        if (devices[i].state == REMOTE_NAME_REQUEST) {
            devices[i].state = REMOTE_NAME_INQUIRED;
            LOG_INFO("Get remote name of %s...", bd_addr_to_str(devices[i].address));
            gap_remote_name_request(
                devices[i].address, devices[i].pageScanRepetitionMode, devices[i].clockOffset | 0x8000);
            return;
        }
    }
}

static void continue_remote_names(void)
{
    if (has_more_remote_name_requests()) {
        do_next_remote_name_request();
        return;
    }
    start_scan();
}

static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
{
    UNUSED(channel);
    UNUSED(size);

    bd_addr_t addr;
    int i;
    int index;

    if (packet_type != HCI_EVENT_PACKET)
        return;

    uint8_t event = hci_event_packet_get_type(packet);

    switch (state) {
    /* @text In INIT, an inquiry  scan is started, and the application transits to
     * ACTIVE state.
     */
    case INIT:
        switch (event) {
        case BTSTACK_EVENT_STATE:
            if (btstack_event_state_get_state(packet) == HCI_STATE_WORKING) {
                state = ACTIVE;
            }
            break;
        default:
            break;
        }
        break;

    /* @text In ACTIVE, the following events are processed:
     *  - GAP Inquiry result event: BTstack provides a unified inquiry result that contain
     *    Class of Device (CoD), page scan mode, clock offset. RSSI and name (from EIR) are optional.
     *  - Inquiry complete event: the remote name is requested for devices without a fetched
     *    name. The state of a remote name can be one of the following:
     *    REMOTE_NAME_REQUEST, REMOTE_NAME_INQUIRED, or REMOTE_NAME_FETCHED.
     *  - Remote name request complete event: the remote name is stored in the table and the
     *    state is updated to REMOTE_NAME_FETCHED. The query of remote names is continued.
     */
    case ACTIVE:
        switch (event) {

        case GAP_EVENT_INQUIRY_RESULT: {
            gap_event_inquiry_result_get_bd_addr(packet, addr);
            index = getDeviceIndexForAddress(devices, addr);
            if (index >= 0)
                break; // already in our list

            Devicei dev;
            dev.address_set(&addr);
            dev.pageScanRepetitionMode = gap_event_inquiry_result_get_page_scan_repetition_mode(packet);
            dev.clockOffset            = gap_event_inquiry_result_get_clock_offset(packet);
            // print info
            LOG_INFO("Device found: %s ", bd_addr_to_str(addr));
            LOG_INFO("with COD: 0x%06x, ", (unsigned int)gap_event_inquiry_result_get_class_of_device(packet));
            LOG_INFO("pageScan %d, ", dev.pageScanRepetitionMode);
            LOG_INFO("clock offset 0x%04x", dev.clockOffset);
            if (gap_event_inquiry_result_get_rssi_available(packet)) {
                LOG_INFO(", rssi %d dBm", (int8_t)gap_event_inquiry_result_get_rssi(packet));
            }
            if (gap_event_inquiry_result_get_name_available(packet)) {
                char name_buffer[240];
                int name_len = gap_event_inquiry_result_get_name_len(packet);
                memcpy(name_buffer, gap_event_inquiry_result_get_name(packet), name_len);
                name_buffer[name_len] = 0;
                LOG_INFO(", name '%s'", name_buffer);
                dev.state = REMOTE_NAME_FETCHED;
                ;
            }
            else {
                dev.state = REMOTE_NAME_REQUEST;
            }
            devices.push_back(dev);
        } break;

        case GAP_EVENT_INQUIRY_COMPLETE:
            for (i = 0; i < devices.size(); i++) {
                // retry remote name request
                if (devices[i].state == REMOTE_NAME_INQUIRED)
                    devices[i].state = REMOTE_NAME_REQUEST;
            }
            continue_remote_names();
            break;

        case HCI_EVENT_REMOTE_NAME_REQUEST_COMPLETE: {
            reverse_bd_addr(&packet[3], addr);
            index = getDeviceIndexForAddress(devices, addr);
            if (index >= 0) {
                if (packet[2] == 0) {
                    LOG_INFO("Name: '%s'", &packet[9]);
                    devices[index].state = REMOTE_NAME_FETCHED;
                    devices[index].name  = reinterpret_cast<char *>(&packet[9]);
                }
                else {
                    LOG_INFO("Failed to get name: page timeout");
                }
            }
            if (index + 1 == devices.size()) {
                LOG_INFO("Scanned all");
                state = DONE;
            }
            continue_remote_names();
        } break;

        default:
            break;
        }
        break;

    default:
        break;
    }
}

namespace Bt
{
    namespace GAP
    {

        Error register_scan()
        {
            LOG_INFO("GAP register scan!");
            /// -> this have to be called prior to power on!
            hci_set_inquiry_mode(INQUIRY_MODE_RSSI_AND_EIR);
            cb_handler.callback = &packet_handler;
            hci_add_event_handler(&cb_handler);
            return Error();
        }

        Error scan()
        {
            LOG_INFO("Start scan if active: %d: %d", hci_get_state(), state);
            if (hci_get_state() == HCI_STATE_WORKING) {
                if (int ret = start_scan() != 0) {
                    LOG_ERROR("Start scan error!: 0x%X", ret);
                    return Error(Error::LibraryError, ret);
                }
            }
            else {
                return Error(Error::NotReady);
            }
            return Error();
        }
    } // namespace GAP
} // namespace Bt

A module-bluetooth/Bluetooth/interface/bluekitchen/PAN.cpp => module-bluetooth/Bluetooth/interface/bluekitchen/PAN.cpp +174 -0
@@ 0,0 1,174 @@
#include <log/log.hpp>

extern "C"
{
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <signal.h>

#include "btstack_config.h"

#include <btstack_event.h>
// #include <btstack_link_key_db_fs.h>
#include <btstack_memory.h>
#include <btstack_run_loop.h>
#include <btstack_run_loop_freertos.h>
#include <bluetooth_company_id.h>
#include <hci.h>
#include <hci_dump.h>
#include <btstack_stdin.h>
    // #include <btstack_tlv_posix.h>

#include <btstack_chipset_cc256x.h>
#include <pan.h>
#include <sdp_util.h>
#include <bnep_lwip.h>
#include <bluetooth_sdp.h>
};

#include <BtCommand.hpp>
#include <Error.hpp>
#ifdef TARGET_RT1051
#include <Bluetooth/glucode/btstack_uart_block_rt1051.h>
#endif

static btstack_packet_callback_registration_t hci_event_callback_registration;

#define NETWORK_TYPE_IPv4 0x0800
#define NETWORK_TYPE_ARP  0x0806
#define NETWORK_TYPE_IPv6 0x86DD

static uint8_t pan_sdp_record[220];

static void packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
{
    /* LISTING_PAUSE */
    UNUSED(channel);
    UNUSED(size);

    bd_addr_t event_addr;

    switch (packet_type) {
    case HCI_EVENT_PACKET:
        switch (hci_event_packet_get_type(packet)) {

        case HCI_EVENT_PIN_CODE_REQUEST:
            // inform about pin code request
            LOG_INFO("Pin code request - using '0000'");
            hci_event_pin_code_request_get_bd_addr(packet, event_addr);
            gap_pin_code_response(event_addr, "0000");
            break;

        case HCI_EVENT_USER_CONFIRMATION_REQUEST:
            // inform about user confirmation request
            LOG_INFO("SSP User Confirmation Auto accept");
            hci_event_user_confirmation_request_get_bd_addr(packet, event_addr);
            break;

        /* @text BNEP_EVENT_CHANNEL_OPENED is received after a BNEP connection was established or
         * or when the connection fails. The status field returns the error code.
         */
        case BNEP_EVENT_CHANNEL_OPENED:
            if (bnep_event_channel_opened_get_status(packet)) {
                LOG_INFO("BNEP channel open failed, status %02x", bnep_event_channel_opened_get_status(packet));
            }
            else {
                uint16_t uuid_source = bnep_event_channel_opened_get_source_uuid(packet);
                uint16_t uuid_dest   = bnep_event_channel_opened_get_destination_uuid(packet);
                uint16_t mtu         = bnep_event_channel_opened_get_mtu(packet);
                bnep_event_channel_opened_get_remote_address(packet, event_addr);
                LOG_INFO("BNEP connection open succeeded to %s source UUID 0x%04x dest UUID: 0x%04x, max frame size %u",
                         bd_addr_to_str(event_addr),
                         uuid_source,
                         uuid_dest,
                         mtu);
                LOG_INFO("Please open 'http://192.168.7.1' in your web browser: ");
            }
            break;

        /* @text BNEP_EVENT_CHANNEL_CLOSED is received when the connection gets closed.
         */
        case BNEP_EVENT_CHANNEL_CLOSED:
            LOG_INFO("BNEP channel closed");
            break;

        default:
            break;
        }
        break;
    default:
        break;
    }
}

namespace Bt
{

    // Set local name with a template Bluetooth address, that will be automatically
    // replaced with a actual address once it is available, i.e. when BTstack boots
    Error set_name(std::string &name)
    {
        // name has to have storage
        constexpr uint32_t size = 64;
        static char lname[size] = {0};
        snprintf(lname, size, "%s %s", name.c_str(), "00:00:00:00:00:00");
        LOG_INFO("Setting local name: %s", lname);
        gap_set_local_name(lname);
        return Error();
    }
    namespace PAN
    {

        Error bnep_setup()
        {
            // Discoverable
            // up and starts talking to a Bluetooth module.
            gap_discoverable_control(1);

            // register for HCI events
            hci_event_callback_registration.callback = &packet_handler;
            hci_add_event_handler(&hci_event_callback_registration);

            // Initialize L2CAP
            l2cap_init();

            // Initialize BNEP
            bnep_init();

            // Init SDP
            sdp_init();
            memset(pan_sdp_record, 0, sizeof(pan_sdp_record));
            uint16_t network_packet_types[] = {NETWORK_TYPE_IPv4, NETWORK_TYPE_ARP, 0}; // 0 as end of list

            // NAP Network Access Type: Other, 1 MB/s
            pan_create_nap_sdp_record(pan_sdp_record,
                                      sdp_create_service_record_handle(),
                                      network_packet_types,
                                      NULL,
                                      NULL,
                                      BNEP_SECURITY_NONE,
                                      PAN_NET_ACCESS_TYPE_OTHER,
                                      1000000,
                                      NULL,
                                      NULL);
            sdp_register_service(pan_sdp_record);
            LOG_INFO("SDP service record size: %u", de_get_len((uint8_t *)pan_sdp_record));
            return Error();
        }

        Error bnep_start()
        {
            bnep_lwip_init();

            // Setup NAP Service via BENP lwIP adapter
            bnep_lwip_register_service(BLUETOOTH_SERVICE_CLASS_NAP, 1691);

            // register callback - to print state
            bnep_lwip_register_packet_handler(packet_handler);
            return Error();
        }

    } // namespace PAN
} // namespace Bt

A module-bluetooth/Bluetooth/interface/bluekitchen/Worker.cpp => module-bluetooth/Bluetooth/interface/bluekitchen/Worker.cpp +231 -0
@@ 0,0 1,231 @@
#include <log/log.hpp>

// #define __BTSTACK_FILE__ ".c"

extern "C"
{
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <signal.h>

#include "btstack_config.h"

#include <btstack_event.h>
// #include <btstack_link_key_db_fs.h>
#include <btstack_memory.h>
#include <btstack_run_loop.h>
#include <bluetooth_company_id.h>
#include <hci.h>
#include <hci_dump.h>
#include <btstack_stdin.h>

#include <btstack_chipset_cc256x.h>
#include <btstack_link_key_db_memory.h>
};

#ifdef TARGET_RT1051
#include <Bluetooth/glucode/btstack_uart_block_rt1051.h>
#include <btstack_run_loop_freertos.h>
#else
extern "C"
{
#include <btstack_run_loop_posix.h>
#include <btstack_tlv_posix.h>
}
#endif

#include <Error.hpp>
#include <functional>

// #define TLV_DB_PATH_PREFIX "/tmp/btstack_"
// #define TLV_DB_PATH_POSTFIX ".tlv"
// static char tlv_db_path[100];
// static const btstack_tlv_t * tlv_impl;
// static btstack_tlv_posix_t   tlv_context;

static void local_version_information_handler(uint8_t *packet);

static hci_transport_config_uart_t config = {
    .type          = HCI_TRANSPORT_CONFIG_UART,
    .baudrate_init = 115200,
    .baudrate_main = 0, // main baudrate
    .flowcontrol   = 1, // flow control
    .device_name   = NULL,
};

static btstack_packet_callback_registration_t hci_event_callback_registration;

static void hci_packet_handler(uint8_t packet_type, uint16_t channel, uint8_t *packet, uint16_t size)
{
    bd_addr_t addr;
    if (packet_type != HCI_EVENT_PACKET)
        return;
    switch (hci_event_packet_get_type(packet)) {
    case BTSTACK_EVENT_STATE:
        if (btstack_event_state_get_state(packet) != HCI_STATE_WORKING)
            break;
        gap_local_bd_addr(addr);
        LOG_INFO("BTstack up and running at %s", bd_addr_to_str(addr));
        // setup TLV
        //            strcpy(tlv_db_path, TLV_DB_PATH_PREFIX);
        //            strcat(tlv_db_path, bd_addr_to_str(addr));
        //            strcat(tlv_db_path, TLV_DB_PATH_POSTFIX);
        //            tlv_impl = btstack_tlv_posix_init_instance(&tlv_context, tlv_db_path);
        //            btstack_tlv_set_instance(tlv_impl, &tlv_context);
        break;
    case HCI_EVENT_COMMAND_COMPLETE:
        if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_read_local_name)) {
            if (hci_event_command_complete_get_return_parameters(packet)[0])
                break;
            // terminate, name 248 chars
            packet[6 + 248] = 0;
            LOG_INFO("Local name: %s", &packet[6]);
        }
        if (HCI_EVENT_IS_COMMAND_COMPLETE(packet, hci_read_local_version_information)) {
            local_version_information_handler(packet);
        }
        break;
    default:
        break;
    }
}

static void sigint_handler(int param)
{
    UNUSED(param);

    LOG_INFO("CTRL-C - SIGINT received, shutting down..");

    // reset anyway
    btstack_stdin_reset();

    // power down
    hci_power_control(HCI_POWER_OFF);
    hci_close();
    exit(0);
}

static int led_state = 0;
void hal_led_toggle(void)
{
    led_state = 1 - led_state;
    LOG_INFO("LED State %u", led_state);
}
static void use_fast_uart(void)
{
#if defined(HAVE_POSIX_B240000_MAPPED_TO_3000000) || defined(HAVE_POSIX_B600_MAPPED_TO_3000000)
    LOG_INFO("Using 3000000 baud.");
    config.baudrate_main = 3000000;
#elif defined(HAVE_POSIX_B1200_MAPPED_TO_2000000) || defined(HAVE_POSIX_B300_MAPPED_TO_2000000)
    LOG_INFO("Using 2000000 baud.");
    config.baudrate_main = 2000000;
#else
    LOG_INFO("Using 921600 baud");
    config.baudrate_main = 921600;
#endif
}

static void local_version_information_handler(uint8_t *packet)
{
    LOG_INFO("Local version information:");
    uint16_t hci_version    = packet[6];
    uint16_t hci_revision   = little_endian_read_16(packet, 7);
    uint16_t lmp_version    = packet[9];
    uint16_t manufacturer   = little_endian_read_16(packet, 10);
    uint16_t lmp_subversion = little_endian_read_16(packet, 12);
    LOG_INFO("- HCI Version    0x%04x", hci_version);
    LOG_INFO("- HCI Revision   0x%04x", hci_revision);
    LOG_INFO("- LMP Version    0x%04x", lmp_version);
    LOG_INFO("- LMP Subversion 0x%04x", lmp_subversion);
    LOG_INFO("- Manufacturer 0x%04x", manufacturer);
    switch (manufacturer) {
    case BLUETOOTH_COMPANY_ID_TEXAS_INSTRUMENTS_INC:
        LOG_INFO("Texas Instruments - CC256x compatible chipset.");
        if (lmp_subversion != btstack_chipset_cc256x_lmp_subversion()) {
            LOG_INFO("Error: LMP Subversion does not match initscript! ");
            LOG_INFO("Your initscripts is for %s chipset",
                     btstack_chipset_cc256x_lmp_subversion() < lmp_subversion ? "an older" : "a newer");
            LOG_INFO("Please update Makefile to include the appropriate bluetooth_init_cc256???.c file");
            exit(10);
        }
        use_fast_uart();
        hci_set_chipset(btstack_chipset_cc256x_instance());
#ifdef ENABLE_EHCILL
        LOG_INFO("eHCILL enabled.");
#else
        LOG_INFO("eHCILL disable.");
#endif

        break;
    case BLUETOOTH_COMPANY_ID_NORDIC_SEMICONDUCTOR_ASA:
        LOG_INFO("Nordic Semiconductor nRF5 chipset.");
        break;
    default:
        LOG_INFO("Unknown manufacturer / manufacturer not supported yet.\n");
        break;
    }
}

extern "C"
{
#include <FreeRTOS.h>
#include <task.h>
};

namespace Bt
{
    void run_btstack(void *)
    {
        LOG_INFO("- run BtStack loop\n");
        btstack_run_loop_execute();
    }

    Error initialize_stack()
    {
        btstack_memory_init();
#ifdef TARGET_RT1051
        btstack_run_loop_init(btstack_run_loop_freertos_get_instance());
        const btstack_uart_block_t *uart_driver = btstack_uart_block_rt1051_instance();
#else
        btstack_run_loop_init(btstack_run_loop_posix_get_instance());
        config.device_name = "/dev/telit";
        LOG_INFO("H4 device: %s", config.device_name);
        const btstack_uart_block_t *uart_driver = btstack_uart_block_posix_instance();
#endif
        const hci_transport_t *transport         = hci_transport_h4_instance(uart_driver);
        const btstack_link_key_db_t *link_key_db = btstack_link_key_db_memory_instance();
        hci_init(transport, (void *)&config);
        hci_set_link_key_db(link_key_db);

        hci_event_callback_registration.callback = &hci_packet_handler;
        hci_add_event_handler(&hci_event_callback_registration);
        LOG_DEBUG("BT worker run success");
        return Error();
    }

    Error register_hw_error_callback(std::function<void(uint8_t)> new_callback)
    {
        static std::function<void(uint8_t)> callback = nullptr;
        callback                                     = new_callback;
        hci_set_hardware_error_callback([](uint8_t val) -> void {
            LOG_ERROR("Bluetooth HW ERROR! %d", val);
            if (callback) {
                callback(val);
            }
        });
        return Error();
    }

    Error run_stack(TaskHandle_t *handle)
    {
        BaseType_t taskerr = 0;
        LOG_INFO("Past last moment for Bt registration prior to RUN state");
        hci_power_control(HCI_POWER_ON);
        if ((taskerr = xTaskCreate(run_btstack, "BtStack", 1024, NULL, tskIDLE_PRIORITY, handle)) != pdPASS) {
            LOG_ERROR("BT Service failure! %lu", taskerr);
            return Error(Error::SystemError, taskerr);
        }
        return Error();
    }
} // namespace Bt

A module-bluetooth/Bluetooth/interface/bluekitchen/btstack_config.h => module-bluetooth/Bluetooth/interface/bluekitchen/btstack_config.h +51 -0
@@ 0,0 1,51 @@
//
// btstack_config.h for generic POSIX H4 port
//

#ifndef __BTSTACK_CONFIG
#define __BTSTACK_CONFIG

// Port related features
#define HAVE_MALLOC
#ifndef TARGET_RT1051
#define HAVE_POSIX_FILE_IO
#endif
#define HAVE_BTSTACK_STDIN
// #define HAVE_POSIX_TIME
#define HAVE_EM9304_PATCH_CONTAINER

// BTstack features that can be enabled
// #define ENABLE_BLE
#define ENABLE_CLASSIC
#define ENABLE_HFP_WIDE_BAND_SPEECH
#define ENABLE_L2CAP_ENHANCED_RETRANSMISSION_MODE
// #define ENABLE_LE_CENTRAL
// #define ENABLE_LE_PERIPHERAL
// #define ENABLE_LE_SECURE_CONNECTIONS
// #define ENABLE_MICRO_ECC_FOR_LE_SECURE_CONNECTIONS
// #define ENABLE_LE_DATA_CHANNELS
// #define ENABLE_LE_DATA_LENGTH_EXTENSION
#define ENABLE_ATT_DELAYED_RESPONSE
#define ENABLE_USER_LOG
#define ENABLE_LOG_ERROR
#define ENABLE_LOG_INFO
#define ENABLE_LOG_WARNING
// #define ENABLE_LOG_DEBUG
#define ENABLE_SCO_OVER_HCI
#define ENABLE_SDP_DES_DUMP
// #define ENABLE_EHCILL

// BTstack configuration. buffers, sizes, ...
#define HCI_INCOMING_PRE_BUFFER_SIZE 14 // sizeof benep heade, avoid memcpy
#define HCI_ACL_PAYLOAD_SIZE         (1691 + 4)

// As an option - much slower (according to docs)
// HCI Controller to Host Flow Control
// #define ENABLE_HCI_CONTROLLER_TO_HOST_FLOW_CONTROL
//
// // Interal ring buffer: 21 kB
// #define HCI_HOST_ACL_PACKET_NUM 20
// #define HCI_HOST_ACL_PACKET_LEN 1024
// #define HCI_HOST_SCO_PACKET_NUM 10
// #define HCI_HOST_SCO_PACKET_LEN 60
#endif

A module-bluetooth/CMakeLists.txt => module-bluetooth/CMakeLists.txt +56 -0
@@ 0,0 1,56 @@
project(module-bluetooth VERSION 1.0 DESCRIPTION "Bluetooth module library")

include(${CMAKE_SOURCE_DIR}/config/ModuleConfig.cmake)

set(CMAKE_CXX_STANDARD 17)

set(SOURCES
    ${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/BluetoothWorker.cpp
)

message("Build with BlueKitchen")
include(lib/btstack.cmake)


message("Sources: " ${SOURCES})
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${BOARD_DIR_SOURCES})


# # Board specific compilation definitions,options,include directories and features
target_compile_definitions(${PROJECT_NAME} PUBLIC   ${PROJECT_CONFIG_DEFINITIONS}
                                                    ${PROJECT_TARGET}
                                                    ${TARGET_COMPILE_DEFINITIONS}
                                                    ${BOARD_DIR_DEFINITIONS}
                                                    )
target_compile_features(${PROJECT_NAME} PUBLIC ${TARGET_COMPILE_FEATURES})
target_compile_options(${PROJECT_NAME}
    PUBLIC
    ${TARGET_COMPILE_OPTIONS}
    PRIVATE
    -Wno-sign-compare
    -Wno-missing-field-initializers
    -Wno-unused-function
    -Wno-implicit-fallthrough

    # C only flags
    "$<$<COMPILE_LANGUAGE:C>:-Wno-old-style-declaration>"
)
target_link_options(${PROJECT_NAME} PUBLIC ${TARGET_LINK_OPTIONS})


target_include_directories(
    ${PROJECT_NAME}
    PUBLIC
    ${BOARD_DIR_INCLUDES}
    ${CMAKE_CURRENT_SOURCE_DIR}
    ${TARGET_LIBRARIES_INCLUDES}
)

target_link_libraries(
    ${PROJECT_NAME}
    module-bsp
    module-utils
    module-vfs
    module-sys
    ${BOARD_DIR_LIBRARIES}
    )

A module-bluetooth/README.md => module-bluetooth/README.md +15 -0
@@ 0,0 1,15 @@
Bluetooth interface layer
=========================

Right now it properly uses API from bsp/bsp-bluetooth and BlueKitchen stack.  
It's meant to provide interface layer for service-bluetooth like that:
>>> os calls <=> service-bluetooth <=> module-bluetooth <=> bluetooth library
>>>                                                     <=> bsp/bluetooth

## Layout
* Bluetooth
    * `interface` code - for other modules to use
    * `glucode` code needed for libraries to work
    * `profiles` bluetooth library function wrappers
* lib
    Libraries used with as little modifications as possible

A module-bluetooth/lib/btstack => module-bluetooth/lib/btstack +1 -0
@@ 0,0 1,1 @@
Subproject commit a652416846deeab67f1d4c9295d746db0f19a911

A module-bluetooth/lib/btstack.cmake => module-bluetooth/lib/btstack.cmake +168 -0
@@ 0,0 1,168 @@
set(BT_GLU "${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/glucode/")
set(BT_INT "${CMAKE_CURRENT_SOURCE_DIR}/Bluetooth/interface/bluekitchen/")
set(BT_STACK_ROOT "${CMAKE_CURRENT_SOURCE_DIR}/lib/btstack")


set(BT_CORE
    ${BT_STACK_ROOT}/src/btstack_memory.c
    ${BT_STACK_ROOT}/src/btstack_linked_list.c
    ${BT_STACK_ROOT}/src/btstack_memory_pool.c
    ${BT_STACK_ROOT}/src/btstack_run_loop.c
    ${BT_STACK_ROOT}/src/btstack_util.c
    )

set(BT_COMMON
    ${BT_STACK_ROOT}/src/ad_parser.c
    ${BT_STACK_ROOT}/src/hci.c
    ${BT_STACK_ROOT}/src/hci_cmd.c
    ${BT_STACK_ROOT}/src/hci_dump.c
    ${BT_STACK_ROOT}/src/l2cap.c
    ${BT_STACK_ROOT}/src/l2cap_signaling.c
    ${BT_STACK_ROOT}/src/btstack_audio.c
    ${BT_STACK_ROOT}/src/btstack_tlv.c
    ${BT_STACK_ROOT}/src/btstack_crypto.c
    #${BT_STACK_ROOT}/src/3rd-party/micro-ecc/uECC.c
    #${BT_STACK_ROOT}/src/sm.c
    )

set(BT_CLASSIC
    ${BT_STACK_ROOT}/src/classic/btstack_link_key_db_memory.c
    ${BT_STACK_ROOT}/src/classic/sdp_util.c
    ${BT_STACK_ROOT}/src/classic/gatt_sdp.c
    ${BT_STACK_ROOT}/src/classic/spp_server.c
    ${BT_STACK_ROOT}/src/classic/rfcomm.c
    ${BT_STACK_ROOT}/src/classic/bnep.c
    ${BT_STACK_ROOT}/src/classic/btstack_link_key_db_memory.c
    ${BT_STACK_ROOT}/src/classic/pan.c
    ${BT_STACK_ROOT}/src/classic/sdp_server.c
    ${BT_STACK_ROOT}/src/classic/device_id_server.c
    )

set(BNEP_LWIP
    ${BT_STACK_ROOT}/platform/lwip/bnep_lwip.c
    )

# ATT
# 	${BT_STACK_ROOT}/att_dispatch.c
#
# GATT_SERVER
# 	${BT_STACK_ROOT}/att_db.c
# 	${BT_STACK_ROOT}/att_server.c
#
# GATT_CLIENT
# 	${BT_STACK_ROOT}/gatt_client.c

    # PAN
    # 	${BT_STACK_ROOT}/pan.c

    # MBEDTLS = 					\
    # 	${BT_STACK_ROOT}/bignum.c 				\
    # 	${BT_STACK_ROOT}/ecp.c 					\
    # 	${BT_STACK_ROOT}/ecp_curves.c 			\
    # 	${BT_STACK_ROOT}/sm_mbedtls_allocator.c  \
    # 	${BT_STACK_ROOT}/memory_buffer_alloc.c   \
    # 	${BT_STACK_ROOT}/platform.c 				\
    #
    # LWIP_CORE_SRC  = init.c mem.c memp.c netif.c udp.c ip.c pbuf.c inet_chksum.c def.c tcp.c tcp_in.c tcp_out.c timeouts.c sys_arch.c
    # LWIP_IPV4_SRC  = acd.c dhcp.c etharp.c icmp.c ip4.c ip4_frag.c ip4_addr.c
    # LWIP_NETIF_SRC = ethernet.c
    # LWIP_HTTPD = altcp_proxyconnect.c fs.c httpd.c
    # LWIP_SRC = ${LWIP_CORE_SRC} ${LWIP_IPV4_SRC} ${LWIP_NETIF_SRC} ${LWIP_HTTPD} dhserver.c
    # # List of files for Bluedroid SBC codec
    # include ${BTSTACK_ROOT}/3rd-party/bluedroid/decoder/Makefile.inc
    # include ${BTSTACK_ROOT}/3rd-party/bluedroid/encoder/Makefile.inc

    # SBC_DECODER += \
    # 	btstack_sbc_plc.c \
    # 	btstack_sbc_decoder_bluedroid.c \
    #
    # SBC_ENCODER += \
    # 	btstack_sbc_encoder_bluedroid.c \
    # 	hfp_msbc.c \
    #
    # CVSD_PLC = \
    # 	btstack_cvsd_plc.c \
    #
    # AVDTP += \
    # 	avdtp_util.c           \
    # 	avdtp.c                \
    # 	avdtp_initiator.c      \
    # 	avdtp_acceptor.c       \
    # 	avdtp_source.c 	       \
    # 	avdtp_sink.c           \
    # 	a2dp_source.c          \
    # 	a2dp_sink.c            \
    # 	btstack_ring_buffer.c \

set(TARGET_LIBRARIES_INCLUDES
    "${BT_INT}"
    ${BT_STACK_ROOT}/platform/freertos/
    ${BT_STACK_ROOT}/platform/embedded/
    ${BT_STACK_ROOT}/chipset/cc256x

    ${BT_STACK_ROOT}/src/ble
    ${BT_STACK_ROOT}/src/classic
    ${BT_STACK_ROOT}/src
    ${BT_STACK_ROOT}/3rd-party/bluedroid/decoder/include
    ${BT_STACK_ROOT}/3rd-party/bluedroid/encoder/include
    ${BT_STACK_ROOT}/3rd-party/hxcmod-player
    # ${BT_STACK_ROOT}/3rd-party/lwip/core/src/include/
    ${BT_STACK_ROOT}/3rd-party/lwip/dhcp-server
    ${BT_STACK_ROOT}/3rd-party/md5
    ${BT_STACK_ROOT}/3rd-party/micro-ecc
    ${BT_STACK_ROOT}/3rd-party/yxml
    # ${BT_STACK_ROOT}/platform/lwip
    )

# pseudocode
#if(PLATFORM LINUX) {
#btstack_stdin_posix.c
#&& include from posix too
#}

if(${PROJECT_TARGET} STREQUAL "TARGET_Linux")
message("Linux specyfic includes")
message("-----------------------")
    list(APPEND TARGET_LIBRARIES_INCLUDES
        ${BT_STACK_ROOT}/platform/posix/
        )
else ()
endif()

include(${CMAKE_SOURCE_DIR}/module-lwip/lwip-includes.cmake)
list(APPEND TARGET_LIBRARIES_INCLUDES ${LWIP_INCLUDE_DIRS})
list(APPEND TARGET_LIBRARIES_INCLUDES
    ${BT_STACK_ROOT}/platform/lwip
    )

set(BOARD_DIR_SOURCES
            ${BT_INT}/Worker.cpp
            ${BT_INT}/GAP.cpp
            ${BT_INT}/PAN.cpp

            ${BT_GLU}/bluetooth_init_cc2564C_1.0.c
            ${BT_GLU}/btstack_uart_block_rt1051.cpp
            ${BT_GLU}/btstack_uart_block_rt1051.h
            ${BT_GLU}/hal_time_ms.c
            ${BT_STACK_ROOT}/chipset/cc256x/btstack_chipset_cc256x.c
            ${BT_STACK_ROOT}/platform/freertos/btstack_run_loop_freertos.c
            ${BT_STACK_ROOT}/src/hci_transport_h4.c
            ${BT_CORE}
            ${BT_COMMON}
            ${BT_CLASSIC}
            ${BNEP_LWIP}
    )

if(${PROJECT_TARGET} STREQUAL "TARGET_Linux")
message("Linux specyfic sources")
message("----------------------")
# include(${CMAKE_CURRENT_SOURCE_DIR}/targets/Target_Linux.cmake)
list(APPEND BOARD_DIR_SOURCES
    # ${BOARD_SOURCES}
    ${BT_STACK_ROOT}/platform/posix/btstack_stdin_posix.c
    ${BT_STACK_ROOT}/platform/posix/btstack_uart_block_posix.c
    ${BT_STACK_ROOT}/platform/posix/btstack_run_loop_posix.c
    ${BT_STACK_ROOT}/platform/posix/btstack_tlv_posix.c
    )
else()
endif()

A module-bluetooth/targets/Target_Linux.cmake => module-bluetooth/targets/Target_Linux.cmake +2 -0
@@ 0,0 1,2 @@
set(BOARD_SOURCES  CACHE INTERNAL "")
set(BOARD_DIR_INCLUDES  ${CMAKE_CURRENT_SOURCE_DIR}/board/linux CACHE INTERNAL "")

A module-bluetooth/tests/CMakeLists.txt => module-bluetooth/tests/CMakeLists.txt +0 -0
M module-bsp/CMakeLists.txt => module-bsp/CMakeLists.txt +1 -0
@@ 15,6 15,7 @@ set(SOURCES
        #"${CMAKE_CURRENT_SOURCE_DIR}/drivers/sai/DriverSAI.cpp"
        "${CMAKE_CURRENT_SOURCE_DIR}/drivers/gpio/DriverGPIO.cpp"
        board/linux/lpm/LinuxLPM.cpp board/linux/lpm/LinuxLPM.h
        "${CMAKE_CURRENT_SOURCE_DIR}/bsp/bluetooth/Bluetooth.cpp"
        "${CMAKE_CURRENT_SOURCE_DIR}/bsp/common.cpp"
        )


A module-bsp/board/linux/bluetooth/Bluetooth.cpp => module-bsp/board/linux/bluetooth/Bluetooth.cpp +117 -0
@@ 0,0 1,117 @@
#include "bsp/bluetooth/Bluetooth.hpp"
#include "BluetoothWorker.hpp"
#include "log/log.hpp"

/// stubs

using namespace bsp;

void BTdev::_circ::sem_take()
{}
void BTdev::_circ::sem_give()
{}

BTdev::_circ::_circ(unsigned int size, int threshold) : head(0), tail(0), threshold(threshold), size(size), len(0)
{
    buff = new char[size];
}
BTdev::_circ::~_circ()
{
    delete[] buff;
}

BlueKitchen::BlueKitchen(unsigned int in_size, unsigned int out_size) : BluetoothCommon(in_size, out_size)
{}

BlueKitchen *BlueKitchen::getInstance()
{
    static BlueKitchen *k = NULL;
    if (k == NULL) {
        k = new BlueKitchen();
    }
    return k;
}

ssize_t BlueKitchen::write_blocking(char *buf, ssize_t len)
{
    return 0;
}

BluetoothCommon::BluetoothCommon(unsigned int in_size, unsigned int out_size, int threshold)
    : BTdev(in_size, out_size, threshold)
{}

BlueKitchen::~BlueKitchen()
{}

BluetoothCommon::~BluetoothCommon()
{}

void BluetoothCommon::open()
{}

void BluetoothCommon::close()
{}

void BluetoothCommon::sleep_ms(ssize_t ms)
{
    ulTaskNotifyTake(pdTRUE, ms);
}

BTdev::Error BluetoothCommon::flush()
{
    return Success;
}

ssize_t BluetoothCommon::write(char *buf, size_t nbytes)
{
    return 0;
}

ssize_t BluetoothCommon::write_blocking(char *buf, ssize_t len)
{
    return 0;
}

BTdev::Error BluetoothCommon::set_baudrate(uint32_t bd)
{
    return Success;
}

// set flow on -> true, set flow off -> false
BTdev::Error BluetoothCommon::set_rts(bool on)
{
    return Success;
}

BTdev::Error BluetoothCommon::set_reset(bool on)
{
    return Success;
}

int BluetoothCommon::read_cts()
{
    return 0;
}

void BluetoothCommon::configure_uart_io()
{}

void BluetoothCommon::configure_lpuart()
{}

void BluetoothCommon::configure_cts_irq()
{}

void BluetoothCommon::set_irq(bool enable)
{}

ssize_t BlueKitchen::read(void *buf, size_t nbytes)
{
    return 0;
}

ssize_t Bluetopia::read(void *buf, size_t nbytes)
{
    return 0;
}

A module-bsp/board/linux/bluetooth/test/bsp_bt.cpp => module-bsp/board/linux/bluetooth/test/bsp_bt.cpp +138 -0
@@ 0,0 1,138 @@
#include "bsp_bt.hpp"

namespace bsp
{

    BluetopiaHW::BluetopiaHW(LogLvl lvl) : Bluetopia(64, 64, 0)
    {
        log(LogDebug, "Init done!\n");
    }

    BluetopiaHW::~BluetopiaHW()
    {}

    Bluetopia *BluetopiaHW::getInstance()
    {
        static BluetopiaHW *inst = NULL;
        if (inst == NULL) {
            inst = new BluetopiaHW();
        }
        return inst;
    }

    void Bluetopia::wait_data()
    {}

    void Bluetopia::set_data()
    {}

    void BluetopiaHW::open()
    {
        log(LogDebug, "open!\n");
        set_irq(true);
    }

    void BluetopiaHW::close()
    {
        log(LogDebug, "close!\n");
        set_irq(false);
    }

    void BluetopiaHW::sleep_ms(ssize_t ms)
    {
        log(LogDebug, "sleep %d [ms]!\n", ms);
        ulTaskNotifyTake(pdTRUE, ms);
    }

    void mocup_write_blocking(unsigned char *buf, size_t len)
    {
        printf("WRITE: [%d][%.*s]\n", int(len), int(len), buf);
    }

    BTdev::Error BluetopiaHW::flush()
    {
        log(LogDebug, "flush [%d] %s\n", out.len, out.tail < out.head ? "reverse" : "normal");
        Error err      = Success;
        unsigned int i = 0;
        for (i = 0; i < default_timeout_ms; ++i) {
            if (read_cts() == 0) {
                break;
            }
            else {
                sleep_ms(1);
            }
        }
        if (i == default_timeout_ms) {
            printf("BT CTS error!\n");
            err = ErrorTimeout;
        }
        char *from = &out.buff[out.head];
        if (out.tail >= out.head) {
            mocup_write_blocking(reinterpret_cast<uint8_t *>(from), out.len);
        }
        else {
            mocup_write_blocking(reinterpret_cast<uint8_t *>(from), out.len - out.tail);
            from = out.buff;
            mocup_write_blocking(reinterpret_cast<uint8_t *>(from), out.tail);
        }
        out.flush();
        return err;
    }

    ssize_t BluetopiaHW::write(char *buf, size_t nbytes)
    {
        log(LogDebug, "write %d -> [%.*s]\n", nbytes, nbytes, buf);
        size_t i = 0;
        // if CTS set -> ignore return 0, can use threshold_guard here too
        for (i = 0; i < nbytes; ++i) {
            if (out.push(*(buf + i)) != 0) {
                break;
            }
        }
        return i;
    }

    ssize_t BluetopiaHW::write_blocking(char *buf, ssize_t len)
    {
        int llen = 0;
        while (llen != len) {
            llen += write(buf, len - llen);
            flush();
        }
        return llen;
    }

    BTdev::Error BluetopiaHW::set_baudrate(uint32_t bd)
    {
        log(LogDebug, "Set baudrate: %d", bd);
        Error ret = Success;
        return ret;
    }

    // set flow on -> true, set flow off -> false
    BTdev::Error BluetopiaHW::set_rts(bool on)
    {
        log(LogDebug, "RTS %s", on ? "on" : "off");
        return Success;
    }

    BTdev::Error BluetopiaHW::set_reset(bool on)
    {
        log(LogDebug, "reset %s", on ? "on" : "off");
        return Success;
    }

    void BluetopiaHW::set_irq(bool enable)
    {}

    ssize_t BluetopiaHW::read(void *, unsigned long)
    {
        return 0;
    }

    int BluetopiaHW::read_cts()
    {
        return 0;
    }

}; // namespace bsp

A module-bsp/board/linux/bluetooth/test/bsp_bt.hpp => module-bsp/board/linux/bluetooth/test/bsp_bt.hpp +38 -0
@@ 0,0 1,38 @@
#pragma once

#include "bsp/bluetooth/Bluetooth.hpp"
#include "FreeRTOS.h"
#include "stream_buffer.h"
#include "timers.h"

#include <memory>

namespace bsp
{
    class BluetopiaHW : public Bluetopia
    {
      public:
        BluetopiaHW(LogLvl lvl = LogError);
        virtual ~BluetopiaHW();
        static Bluetopia *getInstance();
        static const ssize_t baudrate      = 115200;
        static const ssize_t off_threshold = 16;
        static const ssize_t on_threshold  = 32;

        // without them it doesnt see inherited functs o_o
        virtual void open() override;
        virtual void close() override;
        virtual void sleep_ms(ssize_t ms);
        virtual ssize_t read(void *buf, size_t nbytes) override;
        virtual ssize_t write(char *buf, size_t nbytes);
        virtual Error flush();
        virtual Error set_baudrate(uint32_t bd);
        virtual Error set_rts(bool on);
        virtual Error set_reset(bool on);
        virtual int read_cts();
        ssize_t write_blocking(char *buf, ssize_t len);
        virtual void set_irq(bool enable);
        virtual void wait_data();
        virtual void set_data();
    };
}; // namespace bsp

A module-bsp/board/rt1051/bluetooth/BlueKitchen.cpp => module-bsp/board/rt1051/bluetooth/BlueKitchen.cpp +120 -0
@@ 0,0 1,120 @@
#include "bsp/bluetooth/Bluetooth.hpp"
#include "BluetoothWorker.hpp"
#include "log/log.hpp"
#include "FreeRTOS.h"
#include "fsl_lpuart.h"
#include "board.h"

using namespace bsp;

BlueKitchen::BlueKitchen(unsigned int in_size, unsigned int out_size) : BluetoothCommon(in_size, out_size)
{
    to_read       = 0;
    read_buff     = NULL;
    read_ready_cb = NULL;
    write_done_cb = NULL;
    in.threshold  = 128;
}

BlueKitchen::~BlueKitchen()
{}

BlueKitchen *BlueKitchen::getInstance()
{
    static BlueKitchen *k = NULL;
    if (k == NULL) {
        /// outcomming & incomming heap allocated buffers sizes
        /// packet on IP network cna have MTU 1500, so big enough buffers were added to not throttle comms
        k = new BlueKitchen(2048, 8000);
    }
    return k;
}

// request... from circ buffer
ssize_t BlueKitchen::read(void *buf, size_t nbytes)
{
    set_rts(false);
    to_read     = nbytes;
    to_read_req = nbytes;
    read_buff   = reinterpret_cast<char *>(buf);
    // set bt ptr to 0, len to 0, to read to nbytes
    // bt->to_read
    BaseType_t taskwoken = 0;
    uint8_t val          = Bt::Message::EvtReceived;
    if ((to_read != 0) && (in.len >= to_read)) {
        to_read = 0;
        if (qHandle) {
            xQueueSendFromISR(qHandle, &val, &taskwoken);
            portEND_SWITCHING_ISR(taskwoken);
        }
    }
    set_rts(true);
    return 0;
}

void BlueKitchen::set_flowcontrol(int on)
{
    // TODO
}

#include <sstream>

ssize_t BlueKitchen::write_blocking(char *buf, ssize_t size)
{
    ssize_t i            = 0;
    BaseType_t taskwoken = 0;
    uint8_t val          = Bt::Message::EvtSent;

#ifdef DO_DEBUG_HCI_COMS
    std::stringstream ss;
    for (int i = 0; i < size; ++i) {
        ss << " 0x" << std::hex << (int)buf[i];
    }
    LOG_DEBUG("--> [%d]>%s<", size, ss.str().c_str());
#endif
    if (BluetoothCommon::write_blocking(buf, size) == size) {
        xQueueSendFromISR(qHandle, &val, &taskwoken);
        portEND_SWITCHING_ISR(taskwoken);
    }
    else {
        val = Bt::Message::EvtSentError;
        xQueueSendFromISR(qHandle, &val, &taskwoken);
    }

    return i;
}

extern "C"
{
    void LPUART2_IRQHandler(void)
    {
        uint32_t isrReg               = LPUART_GetStatusFlags(BSP_BLUETOOTH_UART_BASE);
        static char characterReceived = 0;
        BaseType_t taskwoken          = 0;
        uint8_t val                   = Bt::Message::EvtReceived;
        bsp::BlueKitchen *bt          = bsp::BlueKitchen::getInstance();

        if (isrReg & kLPUART_RxDataRegFullFlag) {
            characterReceived = LPUART_ReadByte(BSP_BLUETOOTH_UART_BASE);
            if (bt->in.push(characterReceived)) {
                val = Bt::Message::EvtRecUnwanted;
                xQueueSendFromISR(bt->qHandle, &val, &taskwoken);
            }
            if (bt->to_read != 0 && (bt->in.len >= bt->to_read)) {
                bt->to_read = 0;
                assert(bt->qHandle);
                val = Bt::Message::EvtReceived;
                xQueueSendFromISR(bt->qHandle, &val, &taskwoken);
                portEND_SWITCHING_ISR(taskwoken);
            }
            if (bt->in.threshold_guard()) {
                bt->set_rts(false);
            }
        }
        if (isrReg & kLPUART_RxOverrunFlag) {
            val = Bt::Message::EvtUartError;
            xQueueSendFromISR(bt->qHandle, &val, &taskwoken);
        }
        LPUART_ClearStatusFlags(BSP_BLUETOOTH_UART_BASE, isrReg);
    }
};

A module-bsp/board/rt1051/bluetooth/BluetoothCommon.cpp => module-bsp/board/rt1051/bluetooth/BluetoothCommon.cpp +273 -0
@@ 0,0 1,273 @@
#include "bsp/bluetooth/Bluetooth.hpp"
#include "log/log.hpp"
#include "FreeRTOS.h"
#include "fsl_lpuart.h"
#include "board.h"

using namespace bsp;

// TODO it's plain copy same as in cellular - this is kind of wrong
uint32_t UartGetPeripheralClock();

void BTdev::_circ::sem_take()
{
    if (!(SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk)) {
        xSemaphoreTake(sem, 0);
    }
    else {
        BaseType_t px;
        xSemaphoreTakeFromISR(sem, &px);
    }
}

void BTdev::_circ::sem_give()
{
    if (!(SCB->ICSR & SCB_ICSR_VECTACTIVE_Msk)) {
        xSemaphoreGive(sem);
    }
    else {
        BaseType_t px;
        xSemaphoreGiveFromISR(sem, &px);
    }
}

BTdev::_circ::_circ(unsigned int size, int threshold) : head(0), tail(0), threshold(threshold), size(size), len(0)
{
    buff = new char[size];
    sem  = xSemaphoreCreateBinary();
}

BTdev::_circ::~_circ()
{
    vSemaphoreDelete(sem);
    delete[] buff;
}

BluetoothCommon::BluetoothCommon(unsigned int in_size, unsigned int out_size, int threshold)
    : BTdev(in_size, out_size, threshold)
{
    configure_uart_io();
    configure_lpuart();
    configure_cts_irq();
    LOG_INFO("Bluetooth HW init done!");
}

BluetoothCommon::~BluetoothCommon()
{}

void BluetoothCommon::open()
{
    LOG_INFO("Bluetooth HW open!");
    set_reset(true);
    set_irq(true);
    is_open = true;
    set_rts(true);
}

void BluetoothCommon::close()
{
    LOG_INFO("close!");
    // TODO destroy semaphore
    set_rts(false);
    set_irq(false);
    is_open = false;
    set_reset(false);
}

void BluetoothCommon::sleep_ms(ssize_t ms)
{
    ulTaskNotifyTake(pdTRUE, ms);
}

BTdev::Error BluetoothCommon::flush()
{
    // LOG_INFO("flush [%d] %s", out.len, out.tail<out.head?"reverse":"normal");
    Error err  = Success;
    int len    = out.len;
    char *from = new char[out.len];
    for (int i = 0; i < len; ++i) {
        out.pop(from + i);
    }
    int to_write = len;
    char *fromp  = from;
    while (to_write) {
        while (1) {
            if (read_cts() == 0) {
                break;
            }
            else {
                sleep_ms(1);
            }
        }
        LPUART_WriteBlocking(BSP_BLUETOOTH_UART_BASE, reinterpret_cast<uint8_t *>(fromp), 1);
        --to_write;
        ++fromp;
    }
    delete[] from;
    return err;
}

ssize_t BluetoothCommon::write(char *buf, size_t nbytes)
{
    // LOG_INFO( "write -> [%.*s]",nbytes, buf);
    ssize_t i = 0;
    // if CTS set -> ignore return 0, can use threshold_guard here too
    for (i = 0; i < nbytes; ++i) {
        if (out.push(*(buf + i)) != 0) {
            LOG_ERROR("Cant push!");
            break;
        }
    }
    return i;
}

ssize_t BluetoothCommon::write_blocking(char *buf, ssize_t len)
{
    int yet_to_write = len;
    if (len > out.size) {
        LOG_WARN("WRITE: %d vs %d", len, out.size);
    }
    while (yet_to_write != 0) {
        yet_to_write -= write(buf + len - yet_to_write, yet_to_write < out.size ? yet_to_write : (out.size - 1));
        flush();
    }
    return len;
}

BTdev::Error BluetoothCommon::set_baudrate(uint32_t bd)
{
    LOG_INFO("Set baudrate: %" PRIu32, bd);
    Error ret = Success;
    int err   = 0;
    if ((err = LPUART_SetBaudRate(BSP_BLUETOOTH_UART_BASE, bd, UartGetPeripheralClock())) != 0) {
        LOG_ERROR("BT error: baudrate [%lu] set err: %d", bd, err);
        ret = ErrorBSP;
    }
    return ret;
}

// set flow on -> true, set flow off -> false
BTdev::Error BluetoothCommon::set_rts(bool on)
{
    GPIO_PinWrite(BSP_BLUETOOTH_UART_RTS_PORT, BSP_BLUETOOTH_UART_RTS_PIN, on ? 0U : 1U);
    return Success;
}

BTdev::Error BluetoothCommon::set_reset(bool on)
{
    LOG_INFO("reset %s", on ? "on" : "off");
    GPIO_PinWrite(BSP_BLUETOOTH_SHUTDOWN_PORT, BSP_BLUETOOTH_SHUTDOWN_PIN, on ? 1U : 0U);
    return Success;
}

int BluetoothCommon::read_cts()
{
    return GPIO_PinRead(BSP_BLUETOOTH_UART_CTS_PORT, BSP_BLUETOOTH_UART_CTS_PIN);
}

uint32_t UartGetPeripheralClock()
{
    const int UART_PERIPHERAL_PLL_DIVIDER = 6;
    uint32_t freq                         = 0;
    /* To make it simple, we assume default PLL and divider settings, and the only variable
       from application is use PLL3 source or OSC source */
    if (CLOCK_GetMux(kCLOCK_UartMux) == 0) /* PLL3 div6 80M */
    {
        freq = (CLOCK_GetPllFreq(kCLOCK_PllUsb1) / UART_PERIPHERAL_PLL_DIVIDER) / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
    }
    else {
        freq = CLOCK_GetOscFreq() / (CLOCK_GetDiv(kCLOCK_UartDiv) + 1U);
    }

    return freq;
}

void BluetoothCommon::configure_uart_io()
{
    gpio_pin_config_t gpio_init_structure;
    gpio_init_structure.direction     = kGPIO_DigitalOutput;
    gpio_init_structure.interruptMode = kGPIO_IntRisingOrFallingEdge;
    gpio_init_structure.outputLogic   = 1;
    GPIO_PinInit(BSP_BLUETOOTH_UART_RTS_PORT, BSP_BLUETOOTH_UART_RTS_PIN, &gpio_init_structure);
    gpio_init_structure.direction     = kGPIO_DigitalInput;
    gpio_init_structure.interruptMode = kGPIO_IntRisingOrFallingEdge;
    gpio_init_structure.outputLogic   = 0;
    GPIO_PinInit(BSP_BLUETOOTH_UART_CTS_PORT, BSP_BLUETOOTH_UART_CTS_PIN, &gpio_init_structure);
    gpio_init_structure.direction     = kGPIO_DigitalOutput;
    gpio_init_structure.interruptMode = kGPIO_NoIntmode;
    GPIO_PinInit(BSP_BLUETOOTH_OSC_EN_PORT, BSP_BLUETOOTH_OSC_EN_PIN, &gpio_init_structure);
    GPIO_PinWrite(BSP_BLUETOOTH_OSC_EN_PORT, BSP_BLUETOOTH_OSC_EN_PIN, 1U);
    gpio_init_structure.direction = kGPIO_DigitalOutput;
    GPIO_PinInit(BSP_BLUETOOTH_SHUTDOWN_PORT, BSP_BLUETOOTH_SHUTDOWN_PIN, &gpio_init_structure);
}

void BluetoothCommon::configure_lpuart()
{
    lpuart_config_t bt_c;
    LPUART_GetDefaultConfig(&bt_c);
    bt_c.baudRate_Bps  = baudrate;
    bt_c.dataBitsCount = kLPUART_EightDataBits;
    bt_c.parityMode    = kLPUART_ParityDisabled;
    bt_c.isMsb         = false;
    bt_c.rxIdleType    = kLPUART_IdleTypeStartBit;
    bt_c.rxIdleConfig  = kLPUART_IdleCharacter1;
    bt_c.enableTx      = false;
    bt_c.enableRx      = false;

    if (LPUART_Init(BSP_BLUETOOTH_UART_BASE, &bt_c, UartGetPeripheralClock()) != kStatus_Success) {
        LOG_ERROR("BT: UART config error Could not initialize the uart!");
        return;
    }

    LPUART_ClearStatusFlags(BSP_BLUETOOTH_UART_BASE, 0xFFFFFFFF);
    NVIC_ClearPendingIRQ(LPUART2_IRQn);
    NVIC_SetPriority(LPUART2_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY);
    NVIC_EnableIRQ(LPUART2_IRQn);
}

void BluetoothCommon::configure_cts_irq()
{
    DisableIRQ(GPIO1_Combined_16_31_IRQn);
    GPIO_PortClearInterruptFlags(GPIO1, 0xFFFFFFFF);
    GPIO_PortEnableInterrupts(GPIO1, (1 << BSP_BLUETOOTH_UART_CTS_PIN));
    EnableIRQ(GPIO1_Combined_16_31_IRQn);
    NVIC_SetPriority(GPIO1_Combined_16_31_IRQn, configLIBRARY_LOWEST_INTERRUPT_PRIORITY);
}

void BluetoothCommon::set_irq(bool enable)
{
    // printf("%s\n", __FUNCTION__);
    LPUART_EnableRx(BSP_BLUETOOTH_UART_BASE, false);
    LPUART_EnableTx(BSP_BLUETOOTH_UART_BASE, false);
    LPUART_ClearStatusFlags(BSP_BLUETOOTH_UART_BASE, 0xFFFFFFFF);
    if (enable) {
        LPUART_EnableInterrupts(BSP_BLUETOOTH_UART_BASE, kLPUART_RxDataRegFullInterruptEnable);
    }
    else {
        LPUART_DisableInterrupts(BSP_BLUETOOTH_UART_BASE, kLPUART_RxDataRegFullInterruptEnable);
    }
    // LPUART_EnableInterrupts(BSP_BLUETOOTH_UART_BASE,
    // kLPUART_RxDataRegFullInterruptEnable|kLPUART_TxDataRegEmptyInterruptEnable|kLPUART_TransmissionCompleteInterruptEnable|kLPUART_RxOverrunInterruptEnable
    // );
    LPUART_EnableRx(BSP_BLUETOOTH_UART_BASE, true);
    LPUART_EnableTx(BSP_BLUETOOTH_UART_BASE, true);
}

extern "C"
{
    void GPIO1_Combined_16_31_IRQHandler(void)
    {
        BaseType_t xHigherPriorityTaskWoken = 0;
        uint32_t irq_mask                   = GPIO_GetPinsInterruptFlags(GPIO1);

        if (irq_mask & (1 << BSP_BLUETOOTH_UART_CTS_PIN)) {
            LOG_DEBUG("CTS IRQ!\n");
        }

        // Clear all IRQs
        GPIO_PortClearInterruptFlags(GPIO1, irq_mask);

        // Switch context if necessary
        portEND_SWITCHING_ISR(xHigherPriorityTaskWoken);
    }
};

A module-bsp/board/rt1051/bluetooth/Bluetopia.cpp => module-bsp/board/rt1051/bluetooth/Bluetopia.cpp +57 -0
@@ 0,0 1,57 @@
#include "bluetooth/Bluetooth.hpp"
#include "log/log.hpp"
#include "fsl_lpuart.h"
#include "board.h"

namespace bsp
{

    Bluetopia::Bluetopia(unsigned int in_size, unsigned int out_size, int threshold)
        : BluetoothCommon(default_buff_size, default_buff_size, 32)
    {}

    Bluetopia::~Bluetopia()
    {}

    Bluetopia *Bluetopia::getInstance()
    {
        static Bluetopia *inst = NULL;
        if (inst == NULL) {
            inst = new Bluetopia();
        }
        return inst;
    }

    ssize_t Bluetopia::read(void *, size_t nbytes)
    {
        LOG_INFO("not implemented");
        return 0;
    }

    extern "C"
    {
        void LPUART2_IRQHandler(void)
        {
            uint32_t isrReg               = LPUART_GetStatusFlags(BSP_BLUETOOTH_UART_BASE);
            static char characterReceived = 0;

            if (isrReg & kLPUART_RxDataRegFullFlag) {
                characterReceived  = LPUART_ReadByte(BSP_BLUETOOTH_UART_BASE);
                bsp::Bluetopia *bt = bsp::Bluetopia::getInstance();
                if (bt->in.push(characterReceived) != 0) {
                    // LOG_ERROR("BT: error no RX space!");
                }
                else {
                    bt->set_data();
                }
                if (bt->in.threshold_guard()) {
                    bt->set_rts(false);
                }
            }
            // TODO ths should be handled - othervise uart might be `nicelly` blocked
            if (isrReg & kLPUART_RxOverrunFlag) {
                printf("Overrun\n");
            }
            LPUART_ClearStatusFlags(BSP_BLUETOOTH_UART_BASE, isrReg);
        }
    };

M module-bsp/board/rt1051/common/board.h => module-bsp/board/rt1051/common/board.h +1 -1
@@ 227,7 227,7 @@
 * Definitions for BSP_BLUETOOTH pins configuration
 */

#define BSP_BLUETOOTH_UART_BASE   LPUART2        ///< This macro indicate port to which GSM module is connected
#define BSP_BLUETOOTH_UART_BASE   LPUART2        ///< This macro indicate port to which BT module is connected
#define BSP_BLUETOOTH_UART_CLKSRC kCLOCK_PllUsb1 ///< This macro indicate LPUART clock source

#define BSP_BLUETOOTH_UART_RTS_PORT GPIO1

A module-bsp/bsp/bluetooth/Bluetooth.cpp => module-bsp/bsp/bluetooth/Bluetooth.cpp +37 -0
@@ 0,0 1,37 @@
#include "Bluetooth.hpp"
#include <cstdarg>


namespace bsp {
    BTdev::BTdev(unsigned int in_size, unsigned int out_size, int threshold) : flog(nullptr), in(in_size, threshold), out(out_size, threshold)
    {
        is_open = false;
    }

    BTdev::~BTdev()
    {
    }

    void BTdev::log(LogLvl lvl,const char* val, ...)
    {
        if(loglvl>=lvl && flog) {
            va_list args;
            va_start(args, val);
            flog(val,args);
            va_end(args);
        }
    }

    Bluetopia::Bluetopia(unsigned int in_size, unsigned int out_size, int threshold) : BluetoothCommon(in_size,out_size, threshold),rx_thread(0), thandle(NULL)
    {
    }

    Bluetopia::~Bluetopia()
    {
    }

    Bluetopia *Bluetopia::getInstance()
    {
        return Bluetopia::getInstance();
    }
};

A module-bsp/bsp/bluetooth/Bluetooth.hpp => module-bsp/bsp/bluetooth/Bluetooth.hpp +170 -0
@@ 0,0 1,170 @@
#pragma once

#include <cstdint>      // uint32
#include <sys/types.h>  // ssize_t
#include <cstdarg>
#include <FreeRTOS.h>
#include <thread.hpp>
#include <board.h>

/// c++ low level driver overlay

namespace bsp {

    class BTdev {
        public:
            enum Error {
                Success,
                ErrorUndefined,
                ErrorTimeout,
                ErrorBSP,
            };
            enum LogLvl {
                LogNone,
                LogError,
                LogWarning,
                LogDebug,
            };
            typedef int(*LogFoo)(const char*,va_list args);
        private:
            LogFoo flog;
        public:
            LogLvl loglvl;
            bool is_open;
            static const unsigned int default_timeout_ms = 1000;
            static const unsigned int default_buff_size = 1024;
            static const unsigned int default_baudrate = 115200;
            struct _circ {
                SemaphoreHandle_t sem = 0;
                void sem_take();
                void sem_give();
                char* buff;
                volatile unsigned int head, tail, threshold;
                const unsigned int size;
                volatile unsigned int len;
                _circ(unsigned int size, int threshold=0);
                ~_circ();
                inline int push(char val) {
                    sem_take();
                    int ret=0;
                    if(len<size) {
                        buff[tail]=val;
                        ++tail;
                        ++len;
                        if(tail==size) tail=0;
                    } else {
                        ret=-1;
                    }
                    sem_give();
                    return ret;
                }
                inline int pop(char* val) {
                    sem_take();
                    int ret=0;
                    if(val!=nullptr) {
                        if(len) {
                            *val = buff[head];
                            --len;
                            ++head;
                            if(head == size) head=0;
                        } else {
                            ret =-1;
                        }
                    } else {
                        ret=-2;
                    }
                    sem_give();
                    return ret;
                }
                // reached => 1, safe => 0
                inline bool threshold_guard() {
                    return len+threshold > size;
                }
                inline void flush() {
                    sem_take();
                    len=0;
                    head=0;
                    tail=0;
                    sem_give();
                }
            } in, out;

            BTdev(unsigned int in_size=default_buff_size, unsigned int out_size=default_buff_size, int threshold=0);
            virtual ~BTdev();

            // generall
            virtual void open() = 0;    // enable device -> irq enable
            virtual void close() = 0;   // disable device -> irq disable
            virtual ssize_t read(void *buf, size_t nbytes) = 0; // read from internal in buffor
            void log(LogLvl lvl,const char* val, ...);
            // uart specyfic
    };

    // Common stuff for Bluetopia and bluekitchen +clean listing for overrrides
    class BluetoothCommon : public BTdev
    {
        public:
            static const ssize_t baudrate =115200;
            static const ssize_t off_threshold =16;
            static const ssize_t on_threshold =32;
        public:
            BluetoothCommon(unsigned int in_size=default_buff_size, unsigned int out_size=default_buff_size, int threshold=0);
            virtual ~BluetoothCommon();
            // uart specyfic Common part
            virtual void open() override;
            virtual void close() override;
            virtual ssize_t write(char *buf, size_t nbytes);
            virtual ssize_t write_blocking(char *buf, ssize_t len);
            Error flush();
            Error set_baudrate(uint32_t bd);
            Error set_rts(bool on);
            Error set_reset(bool on);
            int read_cts();
            void sleep_ms(ssize_t ms);
            void set_irq(bool enable);
            // Part to override
            virtual ssize_t read(void *buf, size_t nbytes) override = 0;

        private:
            void configure_uart_io();
            void configure_lpuart();
            void configure_cts_irq();
    };

    /// definitions needed by BT stack
    class Bluetopia : public BluetoothCommon {
        public:
            Bluetopia(unsigned int in_size=default_buff_size, unsigned int out_size=default_buff_size, int threshold=0);
            virtual ~Bluetopia();
            static Bluetopia *getInstance();

            virtual ssize_t read(void *buf, size_t nbytes) override;
            void wait_data();
            void set_data();

            void (*com_cb)(unsigned int transport_id, unsigned int datalen, unsigned char *buff, unsigned long param);
            unsigned long com_cb_param;
            long rx_thread;
            TaskHandle_t thandle;
    };

    class BlueKitchen : public BluetoothCommon {
        public:
            BlueKitchen(unsigned int in_size=default_buff_size, unsigned int out_size=default_buff_size);
            virtual ~BlueKitchen();
            static BlueKitchen *getInstance();

            virtual ssize_t read(void *buf, size_t nbytes) override;
            virtual ssize_t write_blocking(char *buf, ssize_t len) override;
            volatile uint32_t to_read_req = 0;
            volatile uint32_t to_read =0;
            volatile char* read_buff;

            void set_flowcontrol(int on);

            void (*read_ready_cb)(void);
            void (*write_done_cb)(void);
            /// to be able to trigger events on thread
            xQueueHandle qHandle = nullptr;
    };
};

M module-bsp/targets/Target_Linux.cmake => module-bsp/targets/Target_Linux.cmake +4 -0
@@ 11,12 11,15 @@ set(BOARD_SOURCES
        "${CMAKE_CURRENT_SOURCE_DIR}/board/linux/cellular/linux_cellular.cpp"
        "${CMAKE_CURRENT_SOURCE_DIR}/board/linux/harness/harness.cpp"
        "${CMAKE_CURRENT_SOURCE_DIR}/board/linux/rtc/rtc.cpp"
        "${CMAKE_CURRENT_SOURCE_DIR}/board/linux/bluetooth/test/bsp_bt.cpp"

        "${CMAKE_CURRENT_SOURCE_DIR}/board/linux/lpm/LinuxLPM.cpp"

        "${CMAKE_CURRENT_SOURCE_DIR}/board/linux/audio/linux_audiocodec.cpp"
        "${CMAKE_CURRENT_SOURCE_DIR}/board/linux/audio/LinuxCellularAudio.cpp"

        "${CMAKE_CURRENT_SOURCE_DIR}/board/linux/bluetooth/Bluetooth.cpp"

        "${CMAKE_CURRENT_SOURCE_DIR}/board/linux/usb_cdc/usb_cdc.cpp"

        "${CMAKE_CURRENT_SOURCE_DIR}/board/linux/vibrator/vibrator.cpp"


@@ 36,6 39,7 @@ set(BOARD_DIR_INCLUDES
        ${CMAKE_CURRENT_SOURCE_DIR}/board/linux/audio
        ${CMAKE_CURRENT_SOURCE_DIR}/bsp/headset

        ${CMAKE_SOURCE_DIR}/module-bluetooth/Bluetooth
        ${CMAKE_SOURCE_DIR}/module-sys/

        CACHE INTERNAL "")

M module-bsp/targets/Target_RT1051.cmake => module-bsp/targets/Target_RT1051.cmake +3 -0
@@ 92,6 92,9 @@ set(BOARD_SOURCES ${BOARD_SOURCES}

		"${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/bsp/lpm/RT1051LPM.cpp"

        "${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/bluetooth/BluetoothCommon.cpp"
        "${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/bluetooth/BlueKitchen.cpp"

		"${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/bsp/rtc/rtc.cpp"
		"${CMAKE_CURRENT_SOURCE_DIR}/board/rt1051/bsp/battery-charger/battery_charger.cpp"
		

A module-lwip/CMakeLists.txt => module-lwip/CMakeLists.txt +57 -0
@@ 0,0 1,57 @@
project(module-lwip VERSION 1.0 DESCRIPTION "LwIP port layer")


# remove -Werror for lwip
string(REPLACE "-Wno-error=format" "" LWIP_COMPILER_FLAGS "${TARGET_COMPILE_OPTIONS}")

# module-lwip/lib/lwip/src/include/lwip/err.h

include(${CMAKE_CURRENT_SOURCE_DIR}/lwip-includes.cmake)

set (SOURCES
    "${LWIP_DIR}/contrib/ports/freertos/sys_arch.c"
    "${CMAKE_CURRENT_SOURCE_DIR}/lib/dhcp-server/dhserver.c"
)

if (CMAKE_BUILD_TYPE STREQUAL "Debug")
set (LWIP_DEFINITIONS LWIP_DEBUG=1)
endif()

include(${LWIP_DIR}/src/Filelists.cmake)
include(${LWIP_DIR}/contrib/Filelists.cmake)

# for any target dependent on lwip
# target_include_directories(<app> PRIVATE ${LWIP_INCLUDE_DIRS})

# add to target
set(LWIP_LIBRARIES lwipcontribapps lwipallapps lwipcore)

### TODO maybe make it a bit shared
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${BOARD_DIR_SOURCES})
target_compile_definitions(${PROJECT_NAME} PUBLIC   ${PROJECT_CONFIG_DEFINITIONS}
                                                    ${PROJECT_TARGET}
                                                    ${TARGET_COMPILE_DEFINITIONS}
                                                    ${BOARD_DIR_DEFINITIONS}
                                                    )
target_compile_features(${PROJECT_NAME} PUBLIC ${TARGET_COMPILE_FEATURES})
target_compile_options(${PROJECT_NAME} PUBLIC ${TARGET_COMPILE_OPTIONS})
target_link_options(${PROJECT_NAME} PUBLIC ${TARGET_LINK_OPTIONS})


target_include_directories(
    ${PROJECT_NAME}
    PUBLIC
    ${BOARD_DIR_INCLUDES}
    ${CMAKE_CURRENT_SOURCE_DIR}
    ${TARGET_LIBRARIES_INCLUDES}
    ${LWIP_INCLUDE_DIRS}
)

target_link_libraries(
    ${PROJECT_NAME}
    module-bsp
    module-utils
    module-vfs
    module-sys
    ${BOARD_DIR_LIBRARIES}
    )

A module-lwip/README.md => module-lwip/README.md +20 -0
@@ 0,0 1,20 @@
# LwIP system integration
========================

# Why?

Bluetooth APN needs IP & routing and level 2 TCP/IP stack.

# How?

LwIP sources needed are added as _shallow_ submodule in lib.
Our needed sources, not from libraries are in interfaces (now only there)

* module-lwip
    One place for LwIP code
    * lib 
        Place for LwIP submodule
    * interfaces
        Our defined LwIP interfaces place. We need:
        * BNEP - bluetooth network encapsulation protocol - interface
        * PPP  - gsm interface for PPP PDP communication

A module-lwip/includes/arch/cc.h => module-lwip/includes/arch/cc.h +13 -0
@@ 0,0 1,13 @@
#pragma once

#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size)                                                               \
    u8_t variable_name[LWIP_MEM_ALIGN_BUFFER(size)] __attribute__((section(".sdram"))) __attribute__((aligned(4)));

#define LWIP_PLATFORM_ASSERT(x)                                                                                        \
    do {                                                                                                               \
        printf("Assertion \"%s\" failed at line %d in %s\n", x, __LINE__, __FILE__);                                   \
        abort();                                                                                                       \
    } while (0)

#define TCPIP_MBOX_SIZE        1028
#define TCPIP_THREAD_STACKSIZE 4096

A module-lwip/includes/lwipopts.h => module-lwip/includes/lwipopts.h +238 -0
@@ 0,0 1,238 @@
#ifndef __LWIPOPTS_H__
#define __LWIPOPTS_H__

/**
 * NO_SYS==1: Bare metal lwIP
 */
#define NO_SYS 0
/**
 * LWIP_NETCONN==0: Disable Netconn API (require to use api_lib.c)
 */
#define LWIP_NETCONN 0
/**
 * LWIP_SOCKET==0: Disable Socket API (require to use sockets.c)
 */
#define LWIP_SOCKET 0

/**
 * SYS_LIGHTWEIGHT_PROT==1: enable inter-task protection (and task-vs-interrupt
 * protection) for certain critical regions during buffer allocation, deallocation
 * and memory allocation and deallocation.
 * ATTENTION: This is required when using lwIP from more than one context! If
 * you disable this, you must be sure what you are doing!
 */
/**
 * SYS_LIGHTWEIGHT_PROT==0:
 */
#define SYS_LIGHTWEIGHT_PROT 0

/* ---------- Memory options ---------- */
/**
 * MEM_ALIGNMENT: should be set to the alignment of the CPU
 *    4 byte alignment -> #define MEM_ALIGNMENT 4
 *    2 byte alignment -> #define MEM_ALIGNMENT 2
 */
#ifndef MEM_ALIGNMENT
#define MEM_ALIGNMENT 4
#endif

/**
 * MEM_SIZE: the size of the heap memory. If the application will send
 * a lot of data that needs to be copied, this should be set high.
 */
#ifndef MEM_SIZE
#define MEM_SIZE (64 * 1024)
#endif

/* MEMP_NUM_PBUF: the number of memp struct pbufs. If the application
   sends a lot of data out of ROM (or other static memory), this
   should be set high. */
#ifndef MEMP_NUM_PBUF
#define MEMP_NUM_PBUF 15
#endif
/* MEMP_NUM_UDP_PCB: the number of UDP protocol control blocks. One
   per active UDP "connection". */
#ifndef MEMP_NUM_UDP_PCB
#define MEMP_NUM_UDP_PCB 6
#endif
/* MEMP_NUM_TCP_PCB: the number of simulatenously active TCP
   connections. */
#ifndef MEMP_NUM_TCP_PCB
#define MEMP_NUM_TCP_PCB 10
#endif
/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP
   connections. */
#ifndef MEMP_NUM_TCP_PCB_LISTEN
#define MEMP_NUM_TCP_PCB_LISTEN 6
#endif
/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP
   segments. */
#ifndef MEMP_NUM_TCP_SEG
#define MEMP_NUM_TCP_SEG 22
#endif
/* MEMP_NUM_SYS_TIMEOUT: the number of simulateously active
   timeouts. */
#ifndef MEMP_NUM_SYS_TIMEOUT
#define MEMP_NUM_SYS_TIMEOUT 10
#endif

/* ---------- Pbuf options ---------- */
/* PBUF_POOL_SIZE: the number of buffers in the pbuf pool. */
#ifndef PBUF_POOL_SIZE
#define PBUF_POOL_SIZE 9
#endif

/* PBUF_POOL_BUFSIZE: the size of each pbuf in the pbuf pool. */
/* Default value is defined in lwip\src\include\lwip\opt.h as
 * LWIP_MEM_ALIGN_SIZE(TCP_MSS+40+PBUF_LINK_ENCAPSULATION_HLEN+PBUF_LINK_HLEN)*/

/* ---------- TCP options ---------- */
#ifndef LWIP_TCP
#define LWIP_TCP 1
#endif

#ifndef TCP_TTL
#define TCP_TTL 255
#endif

/* Controls if TCP should queue segments that arrive out of
   order. Define to 0 if your device is low on memory. */
#ifndef TCP_QUEUE_OOSEQ
#define TCP_QUEUE_OOSEQ 0
#endif

/* TCP Maximum segment size. */
#ifndef TCP_MSS
#define TCP_MSS (1500 - 40) /* TCP_MSS = (Ethernet MTU - IP header size - TCP header size) */
#endif

/* TCP sender buffer space (bytes). */
#ifndef TCP_SND_BUF
#define TCP_SND_BUF (6 * TCP_MSS) // 2
#endif

/* TCP sender buffer space (pbufs). This must be at least = 2 *
   TCP_SND_BUF/TCP_MSS for things to work. */
#ifndef TCP_SND_QUEUELEN
#define TCP_SND_QUEUELEN (3 * TCP_SND_BUF) / TCP_MSS // 6
#endif

/* TCP receive window. */
#ifndef TCP_WND
#define TCP_WND (2 * TCP_MSS)
#endif

/* Enable backlog*/
#ifndef TCP_LISTEN_BACKLOG
#define TCP_LISTEN_BACKLOG 1
#endif

/* ---------- Network Interfaces options ---------- */
/* Support netif api (in netifapi.c). */
#ifndef LWIP_NETIF_API
#define LWIP_NETIF_API 0
#endif

/* ---------- ICMP options ---------- */
#ifndef LWIP_ICMP
#define LWIP_ICMP 1
#endif

/* ---------- DHCP options ---------- */
/* Define LWIP_DHCP to 1 if you want DHCP configuration of
   interfaces. DHCP is not implemented in lwIP 0.5.1, however, so
   turning this on does currently not work. */
#ifndef LWIP_DHCP
#define LWIP_DHCP 1
#endif

/* ---------- UDP options ---------- */
#ifndef LWIP_UDP
#define LWIP_UDP 1
#endif
#ifndef UDP_TTL
#define UDP_TTL 255
#endif

/* ---------- Statistics options ---------- */
#ifndef LWIP_STATS
#define LWIP_STATS 0
#endif
#ifndef LWIP_PROVIDE_ERRNO
#define LWIP_PROVIDE_ERRNO 1
#endif

/*
   --------------------------------------
   ---------- Checksum options ----------
   --------------------------------------
*/

/*
Some MCU allow computing and verifying the IP, UDP, TCP and ICMP checksums by hardware:
 - To use this feature let the following define uncommented.
 - To disable it and process by CPU comment the  the checksum.
*/
//#define CHECKSUM_BY_HARDWARE

#ifdef CHECKSUM_BY_HARDWARE
/* CHECKSUM_GEN_IP==0: Generate checksums by hardware for outgoing IP packets.*/
#define CHECKSUM_GEN_IP 0
/* CHECKSUM_GEN_UDP==0: Generate checksums by hardware for outgoing UDP packets.*/
#define CHECKSUM_GEN_UDP 0
/* CHECKSUM_GEN_TCP==0: Generate checksums by hardware for outgoing TCP packets.*/
#define CHECKSUM_GEN_TCP 0
/* CHECKSUM_CHECK_IP==0: Check checksums by hardware for incoming IP packets.*/
#define CHECKSUM_CHECK_IP 0
/* CHECKSUM_CHECK_UDP==0: Check checksums by hardware for incoming UDP packets.*/
#define CHECKSUM_CHECK_UDP 0
/* CHECKSUM_CHECK_TCP==0: Check checksums by hardware for incoming TCP packets.*/
#define CHECKSUM_CHECK_TCP 0
#else
/* CHECKSUM_GEN_IP==1: Generate checksums in software for outgoing IP packets.*/
#define CHECKSUM_GEN_IP    1
/* CHECKSUM_GEN_UDP==1: Generate checksums in software for outgoing UDP packets.*/
#define CHECKSUM_GEN_UDP   1
/* CHECKSUM_GEN_TCP==1: Generate checksums in software for outgoing TCP packets.*/
#define CHECKSUM_GEN_TCP   1
/* CHECKSUM_CHECK_IP==1: Check checksums in software for incoming IP packets.*/
#define CHECKSUM_CHECK_IP  1
/* CHECKSUM_CHECK_UDP==1: Check checksums in software for incoming UDP packets.*/
#define CHECKSUM_CHECK_UDP 1
/* CHECKSUM_CHECK_TCP==1: Check checksums in software for incoming TCP packets.*/
#define CHECKSUM_CHECK_TCP 1
#endif

/*
   ------------------------------------
   ---------- Debugging options ----------
   ------------------------------------
*/

// #define LWIP_DEBUG

// TODO: map these to <stdint.h>

#ifdef LWIP_DEBUG
// #define U8_F  "c"
// #define S8_F  "c"
// #define X8_F  "02x"
// #define U16_F "u"
// #define S16_F "d"
// #define X16_F "x"
// #define U32_F "lu"
// #define S32_F "ld"
// #define X32_F "x"
// #define SZT_F "lu"
#endif

#if (LWIP_DNS || LWIP_IGMP || LWIP_IPV6) && !defined(LWIP_RAND)
/* When using IGMP or IPv6, LWIP_RAND() needs to be defined to a random-function returning an u32_t random value*/
#include "lwip/arch.h"
u32_t lwip_rand(void);
#define LWIP_RAND() lwip_rand()
#endif

#endif /* __LWIPOPTS_H__ */

/*****END OF FILE****/

A module-lwip/lib/dhcp-server/LICENSE => module-lwip/lib/dhcp-server/LICENSE +21 -0
@@ 0,0 1,21 @@
The MIT License (MIT)

Copyright (c) 2015 Fetisov Sergey

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

A module-lwip/lib/dhcp-server/README => module-lwip/lib/dhcp-server/README +2 -0
@@ 0,0 1,2 @@
DHCP Server for lwIP from stm32 ethernet over usb (rndis + lwip) project
https://github.com/fetisov/lrndis

A module-lwip/lib/dhcp-server/dhserver.c => module-lwip/lib/dhcp-server/dhserver.c +335 -0
@@ 0,0 1,335 @@
/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 by Sergey Fetisov <fsenok@gmail.com>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

#include "dhserver.h"

/* DHCP message type */
#define DHCP_DISCOVER       1
#define DHCP_OFFER          2
#define DHCP_REQUEST        3
#define DHCP_DECLINE        4
#define DHCP_ACK            5
#define DHCP_NAK            6
#define DHCP_RELEASE        7
#define DHCP_INFORM         8

/* DHCP options */
enum DHCP_OPTIONS
{
	DHCP_PAD                    = 0,
	DHCP_SUBNETMASK             = 1,
	DHCP_ROUTER                 = 3,
	DHCP_DNSSERVER              = 6,
	DHCP_HOSTNAME               = 12,
	DHCP_DNSDOMAIN              = 15,
	DHCP_MTU                    = 26,
	DHCP_BROADCAST              = 28,
	DHCP_PERFORMROUTERDISC      = 31,
	DHCP_STATICROUTE            = 33,
	DHCP_NISDOMAIN              = 40,
	DHCP_NISSERVER              = 41,
	DHCP_NTPSERVER              = 42,
	DHCP_VENDOR                 = 43,
	DHCP_IPADDRESS              = 50,
	DHCP_LEASETIME              = 51,
	DHCP_OPTIONSOVERLOADED      = 52,
	DHCP_MESSAGETYPE            = 53,
	DHCP_SERVERID               = 54,
	DHCP_PARAMETERREQUESTLIST   = 55,
	DHCP_MESSAGE                = 56,
	DHCP_MAXMESSAGESIZE         = 57,
	DHCP_RENEWALTIME            = 58,
	DHCP_REBINDTIME             = 59,
	DHCP_CLASSID                = 60,
	DHCP_CLIENTID               = 61,
	DHCP_USERCLASS              = 77,  /* RFC 3004 */
	DHCP_FQDN                   = 81,
	DHCP_DNSSEARCH              = 119, /* RFC 3397 */
	DHCP_CSR                    = 121, /* RFC 3442 */
	DHCP_MSCSR                  = 249, /* MS code for RFC 3442 */
	DHCP_END                    = 255
};

typedef struct
{
    uint8_t  dp_op;           /* packet opcode type */
    uint8_t  dp_htype;        /* hardware addr type */
    uint8_t  dp_hlen;         /* hardware addr length */
    uint8_t  dp_hops;         /* gateway hops */
    uint32_t dp_xid;          /* transaction ID */
    uint16_t dp_secs;         /* seconds since boot began */
    uint16_t dp_flags;
    uint8_t  dp_ciaddr[4];    /* client IP address */
    uint8_t  dp_yiaddr[4];    /* 'your' IP address */
    uint8_t  dp_siaddr[4];    /* server IP address */
    uint8_t  dp_giaddr[4];    /* gateway IP address */
    uint8_t  dp_chaddr[16];   /* client hardware address */
    uint8_t  dp_legacy[192];
    uint8_t  dp_magic[4];     
    uint8_t  dp_options[275]; /* options area */
} DHCP_TYPE;

DHCP_TYPE dhcp_data;
static struct udp_pcb *pcb = NULL;
static dhcp_config_t *config = NULL;

char magic_cookie[] = {0x63,0x82,0x53,0x63};

static dhcp_entry_t *entry_by_ip(uint32_t ip)
{
	int i;
	for (i = 0; i < config->num_entry; i++)
		if (*(uint32_t *)config->entries[i].addr == ip)
			return &config->entries[i];
	return NULL;
}

static dhcp_entry_t *entry_by_mac(uint8_t *mac)
{
	int i;
	for (i = 0; i < config->num_entry; i++)
		if (memcmp(config->entries[i].mac, mac, 6) == 0)
			return &config->entries[i];
	return NULL;
}

static __inline bool is_vacant(dhcp_entry_t *entry)
{
	return memcmp("\0\0\0\0\0", entry->mac, 6) == 0;
}

static dhcp_entry_t *vacant_address(void)
{
	int i;
	for (i = 0; i < config->num_entry; i++)
		if (is_vacant(config->entries + i))
			return config->entries + i;
	return NULL;
}

static __inline void free_entry(dhcp_entry_t *entry)
{
	memset(entry->mac, 0, 6);
}

static uint8_t *find_dhcp_option(uint8_t *attrs, int size, uint8_t attr)
{
	int i = 0;
	while ((i + 1) < size)
	{
		int next = i + attrs[i + 1] + 2;
		if (next > size) return NULL;
		if (attrs[i] == attr)
			return attrs + i;
		i = next;
	}
	return NULL;
}

static int fill_options(void *dest,
	uint8_t msg_type,
	const char *domain,
	uint32_t dns,
	int lease_time,
	uint32_t serverid,
	uint32_t router,
	uint32_t subnet)
{
	uint8_t *ptr = (uint8_t *)dest;
	/* ACK message type */
	*ptr++ = 53;
	*ptr++ = 1;
	*ptr++ = msg_type;

	/* dhcp server identifier */
	*ptr++ = DHCP_SERVERID;
	*ptr++ = 4;
	*(uint32_t *)ptr = serverid;
	ptr += 4;

	/* lease time */
	*ptr++ = DHCP_LEASETIME;
	*ptr++ = 4;
	*ptr++ = (lease_time >> 24) & 0xFF;
	*ptr++ = (lease_time >> 16) & 0xFF;
	*ptr++ = (lease_time >> 8) & 0xFF;
	*ptr++ = (lease_time >> 0) & 0xFF;

	/* subnet mask */
	*ptr++ = DHCP_SUBNETMASK;
	*ptr++ = 4;
	*(uint32_t *)ptr = subnet;
	ptr += 4;

	/* router */
	if (router != 0)
	{
		*ptr++ = DHCP_ROUTER;
		*ptr++ = 4;
		*(uint32_t *)ptr = router;
		ptr += 4;
	}

	/* domain name */
	if (domain != NULL)
	{
		int len = strlen(domain);
		*ptr++ = DHCP_DNSDOMAIN;
		*ptr++ = len;
		memcpy(ptr, domain, len);
		ptr += len;
	}

	/* domain name server (DNS) */
	if (dns != 0)
	{
		*ptr++ = DHCP_DNSSERVER;
		*ptr++ = 4;
		*(uint32_t *)ptr = dns;
		ptr += 4;
	}

	/* end */
	*ptr++ = DHCP_END;
	return ptr - (uint8_t *)dest;
}

static void udp_recv_proc(void *arg, struct udp_pcb *upcb, struct pbuf *p, const struct ip4_addr *addr, u16_t port)
{
	(void) arg;
	(void) addr;

	uint8_t *ptr;
	dhcp_entry_t *entry;
	struct pbuf *pp;

	unsigned int n = p->len;
	if (n > sizeof(dhcp_data)) n = sizeof(dhcp_data);
	memcpy(&dhcp_data, p->payload, n);
	switch (dhcp_data.dp_options[2])
	{
		case DHCP_DISCOVER:
			entry = entry_by_mac(dhcp_data.dp_chaddr);
			if (entry == NULL) entry = vacant_address();
			if (entry == NULL) break;

			dhcp_data.dp_op = 2; /* reply */
			dhcp_data.dp_secs = 0;
			dhcp_data.dp_flags = 0;
			*(uint32_t *)dhcp_data.dp_yiaddr = *(uint32_t *)entry->addr;
			memcpy(dhcp_data.dp_magic, magic_cookie, 4);

			memset(dhcp_data.dp_options, 0, sizeof(dhcp_data.dp_options));

			fill_options(dhcp_data.dp_options,
				DHCP_OFFER,
				config->domain,
				*(uint32_t *)config->dns,
				entry->lease, 
				*(uint32_t *)config->addr,
				*(uint32_t *)config->addr, 
				*(uint32_t *)entry->subnet);

			pp = pbuf_alloc(PBUF_TRANSPORT, sizeof(dhcp_data), PBUF_POOL);
			if (pp == NULL) break;
			memcpy(pp->payload, &dhcp_data, sizeof(dhcp_data));
			udp_sendto(upcb, pp, IP_ADDR_BROADCAST, port);
			pbuf_free(pp);
			break;

		case DHCP_REQUEST:
			/* 1. find requested ipaddr in option list */
			ptr = find_dhcp_option(dhcp_data.dp_options, sizeof(dhcp_data.dp_options), DHCP_IPADDRESS);
			if (ptr == NULL) break;
			if (ptr[1] != 4) break;
			ptr += 2;

			/* 2. does hw-address registered? */
			entry = entry_by_mac(dhcp_data.dp_chaddr);
			if (entry != NULL) free_entry(entry);

			/* 3. find requested ipaddr */
			entry = entry_by_ip(*(uint32_t *)ptr);
			if (entry == NULL) break;
			if (!is_vacant(entry)) break;

			/* 4. fill struct fields */
			memcpy(dhcp_data.dp_yiaddr, ptr, 4);
			dhcp_data.dp_op = 2; /* reply */
			dhcp_data.dp_secs = 0;
			dhcp_data.dp_flags = 0;
			memcpy(dhcp_data.dp_magic, magic_cookie, 4);

			/* 5. fill options */
			memset(dhcp_data.dp_options, 0, sizeof(dhcp_data.dp_options));

			fill_options(dhcp_data.dp_options,
				DHCP_ACK,
				config->domain,
				*(uint32_t *)config->dns,
				entry->lease, 
				*(uint32_t *)config->addr,
				*(uint32_t *)config->addr, 
				*(uint32_t *)entry->subnet);

			/* 6. send ACK */
			pp = pbuf_alloc(PBUF_TRANSPORT, sizeof(dhcp_data), PBUF_POOL);
			if (pp == NULL) break;
			memcpy(entry->mac, dhcp_data.dp_chaddr, 6);
			memcpy(pp->payload, &dhcp_data, sizeof(dhcp_data));
			udp_sendto(upcb, pp, IP_ADDR_BROADCAST, port);
			pbuf_free(pp);
			break;

		default:
				break;
	}
	pbuf_free(p);
}

err_t dhserv_init(dhcp_config_t *c)
{
	err_t err;
	// udp_init(); already called from lwip_init
	dhserv_free();
	pcb = udp_new();
	if (pcb == NULL)
		return ERR_MEM;
	err = udp_bind(pcb, IP_ADDR_ANY, c->port);
	if (err != ERR_OK)
	{
		dhserv_free();
		return err;
	}
	udp_recv(pcb, udp_recv_proc, NULL);
	config = c;
	return ERR_OK;
}

void dhserv_free(void)
{
	if (pcb == NULL) return;
	udp_remove(pcb);
	pcb = NULL;
}

A module-lwip/lib/dhcp-server/dhserver.h => module-lwip/lib/dhcp-server/dhserver.h +64 -0
@@ 0,0 1,64 @@
/*
 * The MIT License (MIT)
 *
 * Copyright (c) 2015 by Sergey Fetisov <fsenok@gmail.com>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/*
 * version: 1.0 demo (7.02.2015)
 * brief:   tiny dhcp ipv4 server using lwip (pcb)
 * ref:     https://lists.gnu.org/archive/html/lwip-users/2012-12/msg00016.html
 */

#ifndef DHSERVER_H
#define DHSERVER_H

// #include <stdint.h>
#include <stdbool.h>
// #include <stdio.h>
#include <string.h>
#include "lwip/err.h"
#include "lwip/udp.h"
#include "netif/etharp.h"
#include "lwip/ip_addr.h"

typedef struct dhcp_entry
{
	uint8_t  mac[6];
	uint8_t  addr[4];
	uint8_t  subnet[4];
	uint32_t lease;
} dhcp_entry_t;

typedef struct dhcp_config
{
	uint8_t       addr[4];
	uint16_t      port;
	uint8_t       dns[4];
	const char   *domain;
	int           num_entry;
	dhcp_entry_t *entries;
} dhcp_config_t;

err_t dhserv_init(dhcp_config_t *config);
void dhserv_free(void);

#endif /* DHSERVER_H */

A module-lwip/lib/lwip => module-lwip/lib/lwip +1 -0
@@ 0,0 1,1 @@
Subproject commit 79cd89f99d1032cc5375569e5b24c375b9d230fa

A module-lwip/lwip-includes.cmake => module-lwip/lwip-includes.cmake +12 -0
@@ 0,0 1,12 @@
set (LWIP_DIR ${CMAKE_SOURCE_DIR}/module-lwip/lib/lwip)
set (LWIP_CONTRIB_DIR ${CMAKE_SOURCE_DIR}/module-lwip/lib/lwip/contrib)

set (LWIP_INCLUDE_DIRS
    "${LWIP_DIR}/src/include"
    "${LWIP_DIR}/contrib"
    "${LWIP_DIR}/contrib/ports/freertos/include"
    "${CMAKE_SOURCE_DIR}/module-lwip/includes/"
    "${CMAKE_SOURCE_DIR}/module-lwip/lib/"
)

set(LWIP_LIBRARIES lwipcontribapps lwipallapps lwipcore)

A module-lwip/tests/CMakeLists.txt => module-lwip/tests/CMakeLists.txt +0 -0
M module-services/CMakeLists.txt => module-services/CMakeLists.txt +5 -0
@@ 3,6 3,8 @@ cmake_minimum_required(VERSION 3.14)
project(module-services VERSION 1.0
        DESCRIPTION "Library with all services.")

include(${CMAKE_SOURCE_DIR}/module-lwip/lwip-includes.cmake)

if(${PROJECT_TARGET} STREQUAL "TARGET_RT1051")
    include(targets/Target_RT1051.cmake)
elseif(${PROJECT_TARGET} STREQUAL "TARGET_Linux")


@@ 21,6 23,8 @@ add_subdirectory( service-appmgr )
add_subdirectory( service-db )
add_subdirectory( service-cellular )
add_subdirectory( service-audio )
add_subdirectory( service-bluetooth )
add_subdirectory( service-lwip )
add_subdirectory( service-desktop )
add_subdirectory( service-fota )
add_subdirectory( service-antenna )


@@ 33,6 37,7 @@ target_compile_definitions(${PROJECT_NAME} PUBLIC ${PROJECT_TARGET})
target_compile_definitions(${PROJECT_NAME} PUBLIC ${TARGET_COMPILE_DEFINITIONS})
target_include_directories(${PROJECT_NAME} PUBLIC ${BOARD_DIR_INCLUDES})
target_include_directories(${PROJECT_NAME} PUBLIC ${PROJECT_INCLUDES})
target_include_directories(${PROJECT_NAME} PUBLIC ${LWIP_INCLUDE_DIRS})
target_compile_features(${PROJECT_NAME} PUBLIC ${TARGET_COMPILE_FEATURES})
target_compile_options(${PROJECT_NAME} PUBLIC ${TARGET_COMPILE_OPTIONS})


A module-services/service-bluetooth/CMakeLists.txt => module-services/service-bluetooth/CMakeLists.txt +19 -0
@@ 0,0 1,19 @@
include_directories( ${CMAKE_PROJECT_NAME}

	PUBLIC
		"${CMAKE_CURRENT_LIST_DIR}"
)

include_directories( ${PROJECT_NAME}

	PUBLIC
		"${CMAKE_CURRENT_LIST_DIR}"
)

message( "${PROJECT_NAME}  ${CMAKE_CURRENT_LIST_DIR}" )

target_sources( ${PROJECT_NAME}

	PRIVATE
		"${CMAKE_CURRENT_LIST_DIR}/ServiceBluetooth.cpp"
)

A module-services/service-bluetooth/ServiceBluetooth.cpp => module-services/service-bluetooth/ServiceBluetooth.cpp +101 -0
@@ 0,0 1,101 @@
#include "ServiceBluetooth.hpp"
#include "Service/Service.hpp"
#include "Service/Message.hpp"
#include "MessageType.hpp"
#include "messages/BluetoothMessage.hpp"
#include <log/log.hpp>
#include <service-lwip/ServiceLwIP.hpp>

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

ServiceBluetooth::ServiceBluetooth() : sys::Service(serviceName)
{
    LOG_INFO("[ServiceBluetooth] Initializing");
    testTimerID = CreateTimer(3000, true);
    ReloadTimer(testTimerID);
}

ServiceBluetooth::~ServiceBluetooth()
{
    LOG_INFO("[ServiceBluetooth] Cleaning resources");
}

// Invoked when timer ticked
void ServiceBluetooth::TickHandler(uint32_t id)
{}

// This code is experimental:
// this means it is an init point of bluetooth feature handling
sys::ReturnCodes ServiceBluetooth::InitHandler()
{
    LOG_ERROR("Bluetooth experimental!");
    worker = std::make_unique<BluetoothWorker>(this);

    return sys::ReturnCodes::Success;
}

sys::ReturnCodes ServiceBluetooth::DeinitHandler()
{

    return sys::ReturnCodes::Success;
}

sys::Message_t ServiceBluetooth::DataReceivedHandler(sys::DataMessage *msg, sys::ResponseMessage *resp)
{
    try {
        switch (static_cast<MessageType>(msg->messageType)) {
        case MessageType::BluetoothRequest: {
            BluetoothMessage *lmsg = dynamic_cast<BluetoothMessage *>(msg);
            LOG_INFO("Bluetooth request!");
            switch (lmsg->req) {
            case BluetoothMessage::Start:
                worker->run();
                break;
            case BluetoothMessage::Scan:
                if (worker->scan()) {
                    return std::make_shared<sys::ResponseMessage>(sys::ReturnCodes::Success);
                }
                else {
                    return std::make_shared<sys::ResponseMessage>(sys::ReturnCodes::Failure);
                }
                break;

            case BluetoothMessage::PAN: {
                /// TODO request lwip first...
                /// because TODO blocking message - wrecks system
                LOG_INFO("Request LwIP running!");
                //                    auto ret = message_lwip(this, LwIP_message::Request::Start);
                //                    if (ret != sys::ReturnCodes::Success) {
                //                        LOG_ERROR("Request for LwIP start failed");
                //                    }
                //                    else {
                /// TODO request PPP
                LOG_INFO("Start PAN");
                worker->start_pan();
                //                    }
            } break;
            case BluetoothMessage::Visible:
                worker->set_visible();
                break;

            default:
                break;
            }
            break;
        }
        default:
            LOG_INFO("BT not handled!");
            break;
        }
    }
    catch (std::exception &ex) {
        LOG_ERROR("Exception on BtService!: %s", ex.what());
    }
    return std::make_shared<sys::ResponseMessage>();
}

sys::ReturnCodes ServiceBluetooth::SwitchPowerModeHandler(const sys::ServicePowerMode mode)
{
    LOG_ERROR("TODO");
    return sys::ReturnCodes::Success;
}

A module-services/service-bluetooth/ServiceBluetooth.hpp => module-services/service-bluetooth/ServiceBluetooth.hpp +24 -0
@@ 0,0 1,24 @@
#pragma once

#include "Service/Service.hpp"
#include "Bluetooth/BluetoothWorker.hpp"
#include <memory>

class ServiceBluetooth : public sys::Service
{

  public:
    ServiceBluetooth();
    ~ServiceBluetooth();

    virtual sys::Message_t DataReceivedHandler(sys::DataMessage *msg, sys::ResponseMessage *resp) override;
    void TickHandler(uint32_t id) override;
    sys::ReturnCodes InitHandler() override;
    sys::ReturnCodes DeinitHandler() override;
    virtual sys::ReturnCodes SwitchPowerModeHandler(const sys::ServicePowerMode mode) override;

  private:
    static const char *serviceName;
    uint32_t testTimerID;
    std::unique_ptr<BluetoothWorker> worker;
};

A module-services/service-bluetooth/messages/BluetoothMessage.hpp => module-services/service-bluetooth/messages/BluetoothMessage.hpp +20 -0
@@ 0,0 1,20 @@
#pragma once

#include "Service/Message.hpp"
#include "MessageType.hpp"

class BluetoothMessage : public sys::DataMessage
{
  public:
    enum Request
    {
        None,
        Start,
        Scan,
        PAN,
        Visible,
    };
    enum Request req = Request::None;
    BluetoothMessage(enum Request req = None) : sys::DataMessage(MessageType::BluetoothRequest), req(req){};
    virtual ~BluetoothMessage() = default;
};

A module-services/service-lwip/CMakeLists.txt => module-services/service-lwip/CMakeLists.txt +10 -0
@@ 0,0 1,10 @@
message( "${PROJECT_NAME}  ${CMAKE_CURRENT_LIST_DIR}" )

include_directories( ${CMAKE_PROJECT_NAME}
    PUBLIC
    "${CMAKE_CURRENT_LIST_DIR}"
)
target_sources( ${PROJECT_NAME}
    PRIVATE
    "${CMAKE_CURRENT_LIST_DIR}/ServiceLwIP.cpp"
)

A module-services/service-lwip/ServiceLwIP.cpp => module-services/service-lwip/ServiceLwIP.cpp +110 -0
@@ 0,0 1,110 @@
#include "ServiceLwIP.hpp"
#include <log/log.hpp>
#include "MessageType.hpp"
#include "Service/Message.hpp"
#include "Service/Service.hpp"

extern "C"
{
#include "dhcp-server/dhserver.h"
#include "lwip/apps/httpd.h"
#include "lwip/init.h"
#include "lwip/opt.h"
#include "lwip/tcpip.h"
};

#define NUM_DHCP_ENTRY 3

extern "C"
{
    static dhcp_entry_t entries[NUM_DHCP_ENTRY] = {
        /* mac    ip address        subnet mask        lease time */
        {{0}, {192, 168, 7, 2}, {255, 255, 255, 0}, 24 * 60 * 60},
        {{0}, {192, 168, 7, 3}, {255, 255, 255, 0}, 24 * 60 * 60},
        {{0}, {192, 168, 7, 4}, {255, 255, 255, 0}, 24 * 60 * 60}};

    static dhcp_config_t dhcp_config = {
        {192, 168, 7, 1},
        67,             /* server address, port */
        {0, 0, 0, 0},   /* dns server */
        NULL,           /* dns suffix */
        NUM_DHCP_ENTRY, /* num entry */
        entries         /* entries */
    };
};

sys::ReturnCodes message_lwip(sys::Service *app, LwIP_message::Request req)
{
    std::shared_ptr<LwIP_message> msg = std::make_shared<LwIP_message>(req);
    auto ret                          = sys::Bus::SendUnicast(msg, "ServiceLwIP", app, 5000);
    if (ret.first != sys::ReturnCodes::Success) {
        LOG_ERROR("err: %s", c_str(ret.first));
    }
    return ret.first;
}

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

ServiceLwIP::ServiceLwIP() : sys::Service(serviceName)
{
    LOG_INFO("[ServiceLwIP] Initializing");
    testTimerID = CreateTimer(3000, true);
    ReloadTimer(testTimerID);

    LOG_INFO("Start lwip!");
    tcpip_init(nullptr, nullptr);
    // lwip_init();
    dhserv_init(&dhcp_config);
    httpd_init();
}

void ServiceLwIP::TickHandler(uint32_t id)
{}

sys::ReturnCodes ServiceLwIP::InitHandler()
{
    LOG_ERROR("LwIP experimental!");
    return sys::ReturnCodes::Success;
}

sys::ReturnCodes ServiceLwIP::DeinitHandler()
{
    LOG_ERROR("TODO");
    return sys::ReturnCodes::Success;
}

sys::Message_t ServiceLwIP::DataReceivedHandler(sys::DataMessage *msg, sys::ResponseMessage *resp)
{
    LOG_ERROR("TRY START LWIP");
    try {
        switch (static_cast<MessageType>(msg->messageType)) {
        case MessageType::LwIP_request: {
            LwIP_message *lmsg = dynamic_cast<LwIP_message *>(msg);
            switch (lmsg->req) {
            case LwIP_message::Request::Start:
                LOG_ERROR("START LWIP");
                tcpip_init(nullptr, nullptr);
                // lwip_init();
                dhserv_init(&dhcp_config);
                httpd_init();
                LOG_INFO("LwIP started!");
                break;
            default:
                LOG_ERROR("Not implemented: %d", lmsg->req);
            }
        } break;
        default:
            LOG_ERROR("Not handled messageType: %d", static_cast<int>(msg->messageType));
        }
    }
    catch (std::exception &ex) {
        LOG_ERROR("Exception on BtService!: %s", ex.what());
    }
    return std::make_shared<sys::ResponseMessage>();
}

sys::ReturnCodes ServiceLwIP::SwitchPowerModeHandler(const sys::ServicePowerMode mode)
{
    LOG_ERROR("TODO");
    return sys::ReturnCodes::Success;
}

A module-services/service-lwip/ServiceLwIP.hpp => module-services/service-lwip/ServiceLwIP.hpp +39 -0
@@ 0,0 1,39 @@
#pragma once

#include <memory>
#include "MessageType.hpp"
#include "Service/Message.hpp"
#include "Service/Service.hpp"

class LwIP_message : public sys::DataMessage
{
  public:
    enum Request
    {
        None,
        Start,
        Stop,
    };
    enum Request req = Request::None;
    LwIP_message(enum Request req = None) : sys::DataMessage(MessageType::LwIP_request), req(req){};
    virtual ~LwIP_message() = default;
};

sys::ReturnCodes message_lwip(sys::Service *app, LwIP_message::Request req);

class ServiceLwIP : public sys::Service
{
  public:
    ServiceLwIP();
    ~ServiceLwIP() = default;

    virtual sys::Message_t DataReceivedHandler(sys::DataMessage *msg, sys::ResponseMessage *resp) override;
    void TickHandler(uint32_t id) override;
    sys::ReturnCodes InitHandler() override;
    sys::ReturnCodes DeinitHandler() override;
    virtual sys::ReturnCodes SwitchPowerModeHandler(const sys::ServicePowerMode mode) override;

  private:
    static const char *serviceName;
    uint32_t testTimerID;
};

M source/main.cpp => source/main.cpp +4 -0
@@ 26,6 26,7 @@
#include "service-appmgr/ApplicationManager.hpp"
#include "service-audio/ServiceAudio.hpp"
#include "service-audio/api/AudioServiceAPI.hpp"
#include "service-bluetooth/ServiceBluetooth.hpp"
#include "service-cellular/ServiceCellular.hpp"
#include "service-cellular/api/CellularServiceAPI.hpp"
#include "service-db/ServiceDB.hpp"


@@ 33,6 34,7 @@
#include "service-desktop/ServiceDesktop.hpp"
#include "service-evtmgr/Constants.hpp"
#include "service-evtmgr/EventManager.hpp"
#include "service-lwip/ServiceLwIP.hpp"
#include "service-fota/ServiceFota.hpp"
#include "service-antenna/ServiceAntenna.hpp"



@@ 182,6 184,8 @@ int main()
        ret |= sys::SystemManager::CreateService(std::make_shared<FotaService::Service>(), sysmgr.get());
#endif
        ret |= sys::SystemManager::CreateService(std::make_shared<ServiceAudio>(), sysmgr.get());
        ret |= sys::SystemManager::CreateService(std::make_shared<ServiceBluetooth>(), sysmgr.get());
        ret |= sys::SystemManager::CreateService(std::make_shared<ServiceLwIP>(), sysmgr.get());

        // Service Desktop disabled on master - pulling read on usb driver
        // ret |= sys::SystemManager::CreateService(std::make_shared<ServiceDesktop>(), sysmgr.get());