Marcus Chang / AsyncSerial

source/AsyncSerial.cpp

Committer:
Marcus Chang
Date:
2015-04-10
Revision:
10:9d3ae421081b
Parent:
9:e183765bd81b
Child:
11:6b99dbf1b65d

File content as of revision 10:9d3ae421081b:

#include "AsyncSerial/AsyncSerial.h"

#include "mbed.h"

#define MINIMUM_TIMEOUT 1

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),

        receiveHandler(),
        receiveResult(),
#if 0
        receiveDoneHandler(NULL),
        receiveObject(NULL),
        receiveMember(),
        receiveDoneObject(NULL),
#endif

        waitDoneHandler(NULL),
        waitObject(NULL),
        waitMember(),
        waitDoneObject(NULL),

        isReceiving(false),
        receiveBuffer(NULL),
        receiveMaxLength(0),
        receiveIndex(0),
        receiveStatus(AsyncSerial::RECEIVE_TIMEOUT),

        insideCondition(false),
        conditionStartBuffer(NULL),
        conditionStartLength(0),
        conditionEndBuffer(NULL),
        conditionEndLength(0),
        conditionIndex(0),
        timeout()
{
    SerialBase::attach<AsyncSerial>(this, &AsyncSerial::getReady, SerialBase::RxIrq);
    SerialBase::attach<AsyncSerial>(this, &AsyncSerial::putDone, SerialBase::TxIrq);

#if DEVICE_SERIAL_FC
//    SerialBase::set_flow_control(SerialBase::RTSCTS, rts, cts);
#endif
}

void AsyncSerial::putDone()
{
    sendIndex++;

    if (sendIndex < sendLength)
    {
        SerialBase::_base_putc(sendBuffer[sendIndex]);
    }
    else
    {
        if (sendDoneHandler)
        {
            sendDoneHandler();
        }
        else if (sendObject)
        {
            sendDoneObject(sendObject, sendMember);
        }
    }
}

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

        DEBUG("%c", input);

        if (insideCondition)
        {
            if (conditionEndBuffer != NULL)
            {
                if (input == conditionEndBuffer[conditionIndex])
                {
                    conditionIndex++;

                    if (conditionIndex == conditionEndLength)
                    {
                        receiveStatus = AsyncSerial::RECEIVE_FOUND;
                        timeout.attach_us<AsyncSerial>(this, &AsyncSerial::receiveTimeout, MINIMUM_TIMEOUT);
                    }
                }
                else
                {
                    conditionIndex = 0;
                }
            }

            if (receiveBuffer != NULL)
            {
                receiveBuffer[receiveIndex] = input;
                receiveIndex++;

                if ((receiveIndex == receiveMaxLength) && (receiveStatus != AsyncSerial::RECEIVE_FOUND))
                {
                    receiveStatus = AsyncSerial::RECEIVE_FULL;
                    timeout.attach_us<AsyncSerial>(this, &AsyncSerial::receiveTimeout, MINIMUM_TIMEOUT);
                }
            }
        }
        else
        {
            if (conditionStartBuffer != NULL)
            {
                if (input == conditionStartBuffer[conditionIndex])
                {
                    conditionIndex++;

                    if (conditionIndex == conditionStartLength)
                    {
                        insideCondition = true;
                        conditionIndex = 0;
                    }
                }
                else
                {
                    conditionIndex = 0;
                }
            }
        }
    }
}

void AsyncSerial::getDone(uint8_t status)
{
    isReceiving = false;

    DEBUG("getDone: %X %X %X\r\n", this, waitDoneHandler, waitObject);

    if ((receiveBuffer == NULL) && (conditionStartBuffer == NULL))
    {
        if (waitDoneHandler)
        {
            waitDoneHandler(status);
        }
        else if (waitObject)
        {
            waitDoneObject(waitObject, waitMember, status);
        }
    }
    else
    {
        receiveResult.buffer = receiveBuffer;
        receiveResult.length = receiveIndex;
        receiveResult.status = status;

        receiveHandler.call(&receiveResult);
    }
}

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

        sendObject = NULL;

        send(buffer, length);
    }
}

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

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

    DEBUG("send: %X\r\n", waitObject);
}

void AsyncSerial::receive(receive_done_t handler,
                          uint8_t* buffer, uint16_t maxLength,
                          const char* conditionStartBuffer, uint16_t conditionStartLength,
                          const char* conditionEndBuffer, uint16_t conditionEndLength,
                          uint32_t timeoutMilli)
{
    if (handler)
    {
        receiveDoneHandler = handler;

        receiveObject = NULL;

        receive(buffer, maxLength,
                conditionStartBuffer, conditionStartLength,
                conditionEndBuffer, conditionEndLength,
                timeoutMilli);
    }
}

void AsyncSerial::receive(uint8_t* buffer, uint16_t maxLength,
                          const char* _conditionStartBuffer, uint16_t _conditionStartLength,
                          const char* _conditionEndBuffer, uint16_t _conditionEndLength,
                          uint32_t timeoutMilli)
{
    receiveBuffer = buffer;
    receiveMaxLength = maxLength;
    receiveIndex = 0;

    conditionStartBuffer = _conditionStartBuffer;
    conditionStartLength = _conditionStartLength;
    conditionEndBuffer = _conditionEndBuffer;
    conditionEndLength = _conditionEndLength;
    conditionIndex = 0;

    if ((_conditionStartBuffer != NULL) && (_conditionStartLength != 0))
    {
        insideCondition = false;
    }
    else
    {
        insideCondition = true;
    }

    receiveStatus = AsyncSerial::RECEIVE_TIMEOUT;
    timeout.attach_us<AsyncSerial>(this, &AsyncSerial::receiveTimeout, timeoutMilli * 1000);
    isReceiving = true;

    DEBUG("receive: %p\r\n", receiveBuffer);
}


void AsyncSerial::wait(wait_done_t handler,
                       const char* conditionEndBuffer, uint16_t conditionEndLength,
                       uint32_t timeoutMilli)
{
    if (handler)
    {
        waitDoneHandler = handler;

        waitObject = NULL;

        receive(NULL, 0,
                NULL, 0,
                conditionEndBuffer, conditionEndLength,
                timeoutMilli);
    }
}

void AsyncSerial::receiveTimeout()
{
    DEBUG("timeout: %X %X\r\n", this, waitObject);

    getDone(receiveStatus);
}

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

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