Marcus Chang / AsyncSerial

source/AsyncSerial.cpp

Committer:
Marcus Chang
Date:
2015-03-30
Revision:
1:a3f39ec7d5f2
Parent:
0:dfed780dc91a
Child:
2:efec63739aa3

File content as of revision 1:a3f39ec7d5f2:

#include "AsyncSerial/AsyncSerial.h"

#include "mbed.h"

template<class T>
AsyncSerial::AsyncSerial(PinName tx, PinName rx, PinName rts, PinName cts)
    :   SerialBase(tx, rx),

        sendBuffer(NULL),
        sendLength(0),
        sendIndex(0),

        sendDoneHandler(NULL),
        sendObject(NULL),
        sendMember(),
        sendDoneObject(NULL),

        receiveBuffer(NULL),
        receiveMaxLength(0),
        receiveIndex(0),

        receiveDoneHandler(NULL),
        receiveObject(NULL),
        receiveMember(),
        receiveDoneObject(NULL),

        conditionBuffer(NULL),
        conditionLength(0),
        conditionIndex(0),
        timeout()
{
    SerialBase::attach<AsyncSerial>(this, &AsyncSerial::getReady, SerialBase::RxIrq);
    SerialBase::attach<AsyncSerial>(this, &AsyncSerial::putDone, SerialBase::TxIrq);
}

void AsyncSerial::putDone()
{
    if (sendLength > 0)
    {
        sendIndex++;

        if (sendIndex < sendLength)
        {
            SerialBase::_base_putc(sendBuffer[sendIndex]);
        }
        else
        {
            sendLength = 0;

            if (sendDoneHandler)
            {
                sendDoneHandler(sendBuffer, sendLength);
                sendDoneHandler = NULL;
            }
            else if (sendObject)
            {
                sendDoneObject(sendObject, sendMember, sendBuffer, sendLength);
                sendObject = NULL;
            }
        }
    }
}

void AsyncSerial::getReady()
{
    uint8_t input = SerialBase::_base_getc();

    if (receiveMaxLength > 0)
    {
        receiveBuffer[receiveIndex] = input;
        receiveIndex++;

        if (receiveIndex == receiveMaxLength)
        {
            timeout.detach();
            getDone();
        }
        else if (conditionLength > 0)
        {
            if (receiveBuffer[receiveIndex - 1] == conditionBuffer[conditionIndex])
            {
                conditionIndex++;

                if (conditionIndex == conditionLength)
                {
                    timeout.detach();
                    getDone();
                }
            }
            else
            {
                conditionIndex = 0;
            }
        }
    }
}

void AsyncSerial::getDone()
{
    receiveMaxLength = 0;

    if (receiveDoneHandler)
    {
        receiveDoneHandler(receiveBuffer, receiveIndex);
        receiveDoneHandler = NULL;
    }
    else if (receiveObject)
    {
        receiveDoneObject(receiveObject, receiveMember, receiveBuffer, receiveIndex);
        receiveObject = NULL;
    }
}

void AsyncSerial::send(send_done_t handler, uint8_t* buffer, uint16_t length)
{
    if (handler && buffer && length)
    {
        sendDoneHandler = handler;

        sendObject = NULL;
        sendMember = 0;

        send(buffer, length);
    }
}

template<typename T>
void AsyncSerial::send(T *object, void (T::*member)(void), uint8_t* buffer, uint16_t length)
{
    if (object && member && buffer && length)
    {
        sendObject = static_cast<void*>(object);
        memcpy(sendMember, &member, sizeof(member));
        sendDoneObject = &AsyncSerial::membercaller<T>;

        sendDoneHandler = 0;

        send(buffer, length);
    }
}

void AsyncSerial::send(uint8_t* buffer, uint16_t length)
{
    sendBuffer = buffer;
    sendLength = length;

    sendIndex = 0;
    SerialBase::_base_putc(sendBuffer[sendIndex]);
}



void AsyncSerial::receive(receive_done_t handler,
                          uint8_t* buffer, uint16_t maxLength,
                          const uint8_t* conditionBuffer, uint16_t conditionLength,
                          uint32_t timeoutMilli)
{
    if (handler)
    {
        receiveDoneHandler = handler;

        receiveObject = NULL;

        receive(buffer, maxLength, conditionBuffer, conditionLength, timeoutMilli);
    }
}

template<typename T>
void AsyncSerial::receive(T *object, void (T::*member)(uint8_t*, uint16_t),
                          uint8_t* buffer, uint16_t maxLength,
                          const uint8_t* conditionBuffer, uint16_t conditionLength,
                          uint32_t timeoutMilli)
{
    if (object && member && receiveBuffer && maxLength)
    {
        receiveObject = static_cast<void*>(object);
        memcpy(receiveMember, (uint8_t*) &member, sizeof(member));
        receiveDoneObject = &AsyncSerial::membercaller<T>;

        receiveDoneHandler = NULL;

        receive(buffer, maxLength, conditionBuffer, conditionLength, timeoutMilli);
    }
}

void AsyncSerial::receive(uint8_t* receiveBuffer, uint16_t maxLength,
                          const uint8_t* conditionBuffer, uint16_t conditionLength,
                          uint32_t timeoutMilli)
{
    receiveBuffer = buffer;
    receiveMaxLength = maxLength;
    receiveIndex = 0;

    conditionBuffer = _conditionBuffer;
    conditionLength = _conditionLength;
    conditionIndex = 0;

    timeout.attach_us<AsyncSerial>(this, &AsyncSerial::getDone, timeoutMilli * 1000);
}

template<typename T>
static void AsyncSerial::membercaller(void* object, uint8_t* member, uint8_t* buffer, uint16_t length)
{
    T* o = static_cast<T*>(object);
    void (T::*m)(uint8_t*, uint16_t);
    memcpy(&m, member, sizeof(m));
    (o->*m)(buffer, length);
}

int AsyncSerial::getc()
{
    return SerialBase::_base_getc();
}

int AsyncSerial::putc(int c)
{
    return SerialBase::_base_putc(c);
}