Radio Structures in OOP

Dependencies:   mbed mbed-rtos

modules/CommModule/CommModule.cpp

Committer:
jjones646
Date:
2015-01-15
Revision:
6:4a3dbfbc30f1
Parent:
5:146523a0d1f4

File content as of revision 6:4a3dbfbc30f1:

#include "CommModule.h"

// Set the class's constants for streamlined use in other areas of the code
const int CommModule::TX_QUEUE_SIZE = COMM_MODULE_TX_QUEUE_SIZE;
const int CommModule::RX_QUEUE_SIZE = COMM_MODULE_RX_QUEUE_SIZE;
const int CommModule::NBR_PORTS = COMM_MODULE_NBR_PORTS;

// Default constructor
CommModule::CommModule() :
    // [X] - 1.1 - Define the data queues.
    // =================
    _txQueueHelper(),
    _rxQueueHelper()
{
    // [X] - 1.2 - Create the data queues.
    // =================
    _txQueue = osMailCreate(_txQueueHelper.def(), NULL);
    _rxQueue = osMailCreate(_rxQueueHelper.def(), NULL);

    // [X] - 2.1 - Define the TX & RX task threads.
    // =================
    define_thread(_txDef, &CommModule::txThread);
    define_thread(_rxDef, &CommModule::rxThread);

    // [X] - 2.2 - Create the TX & RX threads - pass them a pointer to the created object.
    // =================
    _txID = osThreadCreate(&_txDef, (void*)this);
    _rxID = osThreadCreate(&_rxDef, (void*)this);

    _txH_called = false;
}

CommModule::~CommModule()
{
    if (_open_ports)
        delete _open_ports;
}

void CommModule::txThread(void const *arg)
{
    CommModule *inst = (CommModule*)arg;

    // Only continue past this point once at least one (1) hardware link is initialized
    osSignalWait(COMM_MODULE_SIGNAL_START_THREAD, osWaitForever);

    LOG("TX Ready!\r\n");

    while(1) {

        // When a new RTP packet is put in the tx queue, begin operations (does nothing if no new data in queue)
        osEvent evt = osMailGet(inst->_txQueue, osWaitForever);

        if (evt.status == osEventMail) {

            // Get a pointer to the packet's memory location
            RTP_t *p = (RTP_t*)evt.value.p;

            // Send the packet on the active communication link
            inst->_tx_handles[p->port].call(p);

            EVENT("Transmission:    Port: %u    Subclass: %u\r\n", p->port, p->subclass);

            // Release the allocated memory once data is sent
            osMailFree(inst->_txQueue, p);
        }
    }
}

void CommModule::rxThread(void const *arg)
{
    CommModule *inst = (CommModule*)arg;

    // Only continue past this point once at least one (1) hardware link is initialized
    osSignalWait(COMM_MODULE_SIGNAL_START_THREAD, osWaitForever);

    LOG("RX Ready!\r\n");

    RTP_t *p;
    osEvent  evt;
    while(1) {

        // Wait until new data is placed in the class's rxQueue from a CommLink class
        evt = osMailGet(inst->_rxQueue, osWaitForever);

        if (evt.status == osEventMail) {
            DigitalOut led(LED4, 1);

            // get a pointer to where the data is stored
            p = (RTP_t*)evt.value.p;

            // If there is an open socket for the port, call it.
            if (std::binary_search(inst->_open_ports->begin(), inst->_open_ports->end(), p->port)) {
                inst->_rx_handles[p->port].call();
            }

            EVENT("Reception: \r\n  Port: %u\r\n  Subclass: %u\r\n", p->port, p->subclass);

            osMailFree(inst->_rxQueue, p);  // free memory allocated for mail

        }
    }
}

void CommModule::TxHandler(void(*ptr)(RTP_t*), uint8_t portNbr)
{
    _txH_called = true;
    ready();
    _tx_handles[portNbr].attach(ptr);
}

void CommModule::RxHandler(void(*ptr)(RTP_t*), uint8_t portNbr)
{
    ready();
    _rx_handles[portNbr].attach(ptr);
}

void CommModule::RxHandler(void(*ptr)(void), uint8_t portNbr)
{
    ready();
    _rx_handles[portNbr].attach(ptr);
}


void CommModule::openSocket(CommLink *link, void(*rx)(void const *arg), uint8_t portNbr)
{
    ready();
    if (_txH_called) {
        if (std::binary_search(_open_ports->begin(), _open_ports->end(), portNbr)) {
            WARNING("Port number %u already binded to open socket.\r\n", portNbr);
        } else {
            // [X] - 1 - Add the port number to the list of active ports & keep sorted
            _open_ports->push_back(portNbr);
            std::sort(_open_ports->begin(), _open_ports->end());

            // [X] - 2 - Set the passed communication link object's pointer to the link pointers array.
            // =================
            _link[portNbr] = link;

            // [X] - 3 - Associate the given port number with the passed function pointer.
            // =================
            _rx_handles[portNbr].attach(rx);

            LOG("Port %u ready for RX.\r\n", portNbr);
        }
    }
}

void CommModule::openSocket(uint8_t portNbr)
{
    ready();
    if (_txH_called) {
        if (std::binary_search(_open_ports->begin(), _open_ports->end(), portNbr)) {
            WARNING("Port number %u already opened.\r\n", portNbr);
        } else {
            // [X] - 1 - Add the port number to the list of active ports & keep sorted
            _open_ports->push_back(portNbr);
            std::sort(_open_ports->begin(), _open_ports->end());

            LOG("Port %u opened.\r\n", portNbr);
        }
    } else {
        WARNING("Must set TX & RX callback functions before opening socket.\r\n");
    }
}

template <class T>
void openSocket(T *tptr, void(T::*mptr)(void const *arg), uint8_t portNbr)
{

}


void CommModule::ready(void)
{
    static bool isReady = false;

    if (isReady) {
        return;
    }

    isReady = true;

    _open_ports = new std::vector<uint8_t>;

    osSignalSet(_txID, COMM_MODULE_SIGNAL_START_THREAD);
    osSignalSet(_rxID, COMM_MODULE_SIGNAL_START_THREAD);
}


void CommModule::send(RTP_t& packet)
{
    // [X] - 1 - Check to make sure a socket for the port exists
    if (std::binary_search(_open_ports->begin(), _open_ports->end(), packet.port)) {

        // [X] - 1.1 - Allocate a block of memory for the data.
        // =================
        RTP_t *p = (RTP_t*)osMailAlloc(_txQueue, osWaitForever);

        // [X] - 1.2 - Copy the contents into the allocated memory block
        // =================
        p->port = packet.port;
        p->subclass = packet.subclass;
        p->data_size = packet.data_size;

        for (int i=0; i<(sizeof(packet)/sizeof(uint8_t)); i++)
            p->data[i] = packet.data[i];

        // [X] - 1.3 - Place the passed packet into the txQueue.
        // =================
        osMailPut(_txQueue, p);
    } else {
        WARNING("Failure to send packet: There is no open socket for port %u.\r\n", packet.port);
    }
}


void CommModule::receive(RTP_t& packet)
{
    // [X] - 1 - Check to make sure a socket for the port exists
    if (std::binary_search(_open_ports->begin(), _open_ports->end(), packet.port)) {

        // [X] - 1.1 - Allocate a block of memory for the data.
        // =================
        RTP_t *p = (RTP_t*)osMailAlloc(_rxQueue, osWaitForever);

        // [X] - 1.2 - Copy the contents into the allocated memory block
        // =================
        p->port = packet.port;
        p->subclass = packet.subclass;

        for (int i=0; i<packet.data_size; i++)
            p->data[i] = packet.data[i];

        // [X] - 1.3 - Place the passed packet into the txQueue.
        // =================
        osMailPut(_rxQueue, p);
    } else {
        WARNING("Received pack from unopen port %u.\r\n", packet.port);
    }
}