Subversion Repositories HomeAutomation

Rev

Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

#include "DownloadState.h"



static HexFile * hf;
//static CSerial * serial;
static SerialConnection * serial;

static HANDLE  hRunMutex;                   // "Keep Running" mutex 

void downloadState(void *pMyID);

typedef enum { SEND_START, WAIT_ACK, SEND_PGM_DATA, WAIT_OWN_PACKET, WAIT_PGM_ACK, RESEND_ADDR, WAIT_DONE, SEND_DONE, DONE, WAIT_ADDR_ACK,DEBUG_STATE1,DEBUG_STATE2 } dState;


void downloadState(void *pMyID)
{
    long lLastError = 0;

    dState pgs = SEND_START;
    DWORD t = 0;
    CanProtoMessage * outCm = (CanProtoMessage *)malloc(sizeof(CanProtoMessage));
    CanProtoMessage * cm = (CanProtoMessage *)malloc(sizeof(CanProtoMessage));
    unsigned char data[8];
    unsigned char byteSent = 0;
    unsigned long currentAddress = 0;
    unsigned char bytesToWrite[PACKET_LENGTH];

    while ( WaitForSingleObject( hRunMutex, 75L ) == WAIT_TIMEOUT )
    {

        bool hasMessage = serial->getMessage(cm);
        if (hasMessage) 
        {
            unsigned char *dtmp = cm->getData();
            for(int i=0;i<8;i++) data[i]=dtmp[i];
            printf("[%ld] Has message\n",GetTickCount());
        }

        switch(pgs)
        {
             case SEND_START:
                // Send boot start packet to target.
                // and wait for ack.
                currentAddress = hf->getAddrLower();
                data[RID_INDEX] = TARGET_ID;
                data[ADDRU_INDEX] = (unsigned char)((currentAddress & 0xFF0000) >> 16);
                data[ADDRH_INDEX] = (unsigned char)((currentAddress & 0xFF00) >> 8);
                data[ADDRL_INDEX] = (unsigned char)(currentAddress & 0xFF);
                outCm = &CanProtoMessage::CanProtoMessage(FUNCT_BOOTLOADER, FUNCC_BOOT_INIT, MY_NID, MY_ID, 8, data);
                outCm->getBytes(bytesToWrite);
                serial->write(bytesToWrite,PACKET_LENGTH);
                t = GetTickCount();
                pgs = WAIT_ACK;
            break;


            case WAIT_ACK:
                
                // Check for timeout, resend start packet in that case..
                if ((GetTickCount() - t) > TIMEOUT_MS)
                {
                    pgs = SEND_START;
                }

                // If received ack.
                if (hasMessage && cm->getFunct() == FUNCT_BOOTLOADER && cm->getFuncc() == FUNCC_BOOT_ACK && cm->getNid() == MY_NID && cm->getSid() == TARGET_ID)
                {
                    // If no error
                    if (data[ERR_INDEX] == ERR_NO_ERROR)
                    {
                        // Start sending program data..
                        byteSent = 0;
                        pgs = SEND_PGM_DATA;
                    }
                    else 
                    { 
                        // else resend start..
                        pgs = SEND_START;
                    }
                }
            break;

            case SEND_PGM_DATA:
                // Send program data.
                for (int i = 0; i < 8; i++)
                { 
                    // Populate data.
                    data[i] = hf->getByte(currentAddress + i + byteSent);
                }
                outCm = &CanProtoMessage::CanProtoMessage(FUNCT_BOOTLOADER, (unsigned int)((unsigned int)((unsigned int)(floor(((double)byteSent/8.0)))<<2) + (FUNCC_BOOT_PGM)), MY_NID, MY_ID, 8, data);
                outCm->getBytes(bytesToWrite);
                serial->write(bytesToWrite,PACKET_LENGTH);
                t = GetTickCount();
                pgs = WAIT_OWN_PACKET;
            break;

            case WAIT_OWN_PACKET:
                // Wait reciving own packet, if timeout, resend last.
                if ((GetTickCount() - t) > TIMEOUT_MS)
                {
                    //pgs = dState.SEND_PGM_DATA;
                    pgs = RESEND_ADDR;
                }

                // If received own packet..
                if (hasMessage && outCm->equals(cm))
                {

                    byteSent += 8;

                    // Check if 64 bytes sent or not..
                    if (byteSent == 64)
                    {
                        // Yes, wait for ack.
                        t = GetTickCount();
                        pgs = WAIT_PGM_ACK;
                    }
                    else
                    { 
                        // No, send more.
                        pgs = SEND_PGM_DATA;
                    }

                }
            break;


            case WAIT_PGM_ACK:
                // Wait for pgm ack.
                if ((GetTickCount() - t) > 2*TIMEOUT_MS)
                {
                    // Woops, error. Resend address and start over.
                    pgs = RESEND_ADDR;
                }

                // If received ack.
                if (hasMessage && cm->getFunct() == FUNCT_BOOTLOADER && cm->getFuncc() == FUNCC_BOOT_ACK && cm->getNid() == MY_NID && cm->getSid() == TARGET_ID)
                {
                    // If no error
                    if (data[ERR_INDEX] == ERR_NO_ERROR)
                    {
                        currentAddress += 64;
                        // Check if end.
                        if (currentAddress > hf->getAddrUpper())
                        {
                            // Yes, we are done, send done.
                            pgs = SEND_DONE;
                        }
                        else
                        { 
                            // More to write.
                            byteSent = 0;
                            pgs = SEND_PGM_DATA;
                        }
                    }
                    else
                    {
                        // else resend start..
                        pgs = RESEND_ADDR;
                    }
                }
            break;


            case SEND_DONE:
                // Send done
                outCm = &CanProtoMessage::CanProtoMessage(FUNCT_BOOTLOADER, FUNCC_BOOT_DONE, MY_NID, MY_ID, 8, data);
                outCm->getBytes(bytesToWrite);
                serial->write(bytesToWrite,PACKET_LENGTH);
                t = GetTickCount();
                pgs = WAIT_DONE;
            break;

            case RESEND_ADDR:
                // Resend addr.
                data[RID_INDEX] = TARGET_ID;
                data[ADDRU_INDEX] = (byte)((currentAddress & 0xFF0000) >> 16);
                data[ADDRH_INDEX] = (byte)((currentAddress & 0xFF00) >> 8);
                data[ADDRL_INDEX] = (byte)(currentAddress & 0xFF);
                outCm = &CanProtoMessage::CanProtoMessage(FUNCT_BOOTLOADER, FUNCC_BOOT_ADDR, MY_NID, MY_ID, 8, data);
                outCm->getBytes(bytesToWrite);
                serial->write(bytesToWrite,PACKET_LENGTH);
                t = GetTickCount();
                pgs = WAIT_ADDR_ACK;
            break;


            case WAIT_ADDR_ACK:
                // Check for timeout, resend addr packet in that case..
                if ((GetTickCount() - t) > TIMEOUT_MS)
                {
                    pgs = RESEND_ADDR;
                }

                // If received ack.
                if (hasMessage && cm->getFunct() == FUNCT_BOOTLOADER && cm->getFuncc() == FUNCC_BOOT_ACK && cm->getNid() == MY_NID && cm->getSid() == TARGET_ID)
                {
                    // If no error
                    if (data[ERR_INDEX] == ERR_NO_ERROR)
                    {
                        // Start sending program data..
                        byteSent = 0;
                        pgs = SEND_PGM_DATA;
                    }
                    else
                    {
                        // else resend addr..
                        pgs = RESEND_ADDR;
                    }
                }
            break;

            case WAIT_DONE:
                // Check for timeout, resend done packet in that case..
                if ((GetTickCount() - t) > TIMEOUT_MS)
                {
                    pgs = SEND_DONE;
                }

                // If received ack.
                if (hasMessage && cm->getFunct() == FUNCT_BOOTLOADER && cm->getFuncc() == FUNCC_BOOT_ACK && cm->getNid() == MY_NID && cm->getSid() == TARGET_ID)
                {
                    // If no error
                    if (data[ERR_INDEX] == ERR_NO_ERROR)
                    {
                        // Start sending program data..
                        byteSent = 0;
                        pgs = DONE;
                    }
                    else
                    {
                        // else resend addr..
                        pgs = RESEND_ADDR;
                    }
                }
            break;

            case DONE:
                downloadStop();
                printf("DONE!\n");
            break;
        }
    }

    return;
}


void downloadStart(SerialConnection * ser,HexFile *hex)
{
    hf = hex;
    serial = ser;
    hRunMutex = CreateMutex( NULL, TRUE, NULL );      // Set 
    _beginthread( downloadState, 0, 0 );

}

void downloadStop( void )
{
    ReleaseMutex( hRunMutex );
    CloseHandle( hRunMutex );
}