?lang_form? ?lang_select? ?lang_submit? ?lang_endform?
{HEADER END}
{FILE START}

library

?curdirlinks? - Rev 6

?prevdifflink? - Blame - ?getfile?

/*! \file edp.c \brief Emerald Data Protocol System. */
//*****************************************************************************
//
// File Name    : 'edp.c'
// Title                : Emerald Data Protocol System
// Author               : Pascal Stang - Copyright (C) 2003
// Created              : 2003.07.01
// Revised              : 2003.07.21
// Version              : 0.1
// Target MCU   : Atmel AVR series
// Editor Tabs  : 4
//
// This code is distributed under the GNU Public License
//              which can be found at http://www.gnu.org/licenses/gpl.txt
//
//*****************************************************************************

//----- Include Files ---------------------------------------------------------
#include <avr/io.h>             // include I/O definitions (port names, pin names, etc)
#include <avr/interrupt.h>      // include interrupt support
#include <avr/pgmspace.h>       // include program-space support

#include "global.h"             // include our global settings
#include "i2c.h"                // include I2C support
#include "rprintf.h"    // include printf function library

#include "edp.h"

// globals
// EDP master/command: response code and reply buffer
u08 EdpCommandResponseCode;
//u08 EdpCommandReplyLength;
u08 EdpCommandReplyBuffer[EDP_REPLY_BUFFER_SIZE];
u08 EdpCommandReplyChecksum;
// EDP slave: response code and reply buffer
u08 EdpSlaveResponseCode;
u08 EdpSlaveReplyLength;
u08 EdpSlaveReplyBuffer[EDP_REPLY_BUFFER_SIZE];
// EDP slave request handler function pointer
EdpSlaveHandlerFuncType edpSlaveHandlerFunc;

// functions
void edpInit(void)
{
        // initialize i2c interface and function library
        i2cInit();
        // set i2c bit rate to 30KHz
        i2cSetBitrate(30);
        // set the Slave Receive Handler function
        // (this function will run whenever a master somewhere else on the bus
        //  writes data to us as a slave)
        i2cSetSlaveReceiveHandler( edpSlaveReceiveService );
        // set the Slave Transmit Handler function
        // (this function will run whenever a master somewhere else on the bus
        //  attempts to read data from us as a slave)
        i2cSetSlaveTransmitHandler( edpSlaveTransmitService );
}

void edpSetSlaveHandler(EdpSlaveHandlerFuncType edpSlaveHandlerFunction)
{
        edpSlaveHandlerFunc = edpSlaveHandlerFunction;
}

// ************ EDP Master operations ************
u08 edpSendCommand(u08 deviceAddr, u08 cmdLength, EdpCommand* edpCommand)
{
        EdpReply* edpCommandReply = (EdpReply*)EdpCommandReplyBuffer;
        u08* sendData;
        u08* replyData;
        u08 replyLength;
        u08 checksum;

        // initialize response variables
        edpCommandReply->Length = 0;
        EdpCommandReplyChecksum = 0;

        #ifdef EDP_DEBUG
        rprintf("\r\nBegin EdpSendCommand, TWSR:0x%x\r\n",inb(TWSR));
        #endif

        // disable TWI interrupt
        cbi(TWCR, TWIE);

        // clear TWI interface
        //outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK));

        // send start condition
        i2cSendStart();
        i2cWaitForComplete();
        #ifdef EDP_DEBUG
        rprintf("Sent Start, TWSR:0x%x\r\n",inb(TWSR));
        #endif

        // send device address with write
        i2cSendByte( (deviceAddr&0xFE) );
        i2cWaitForComplete();
        #ifdef EDP_DEBUG
        rprintf("Sent Device Address+Write, TWSR:0x%x\r\n",inb(TWSR));
        #endif

        // check if device is present and live
        if( i2cGetStatus() != TW_MT_SLA_ACK)
        {
                // device did not ACK it's address, command will not continue
                // transmit stop condition
                // leave with TWEA on for slave receiving
                i2cSendStop();
                while( !(inb(TWCR) & BV(TWSTO)) );
                #ifdef EDP_DEBUG
                rprintf("No Device!, Sent Stop, TWSR:0x%x\r\n",inb(TWSR));
                #endif
                // enable TWI interrupt
                sbi(TWCR, TWIE);
                // return error
                return EDP_COMMAND_NODEV;
        }

        // send data
        sendData = (u08*)edpCommand;
        checksum = 0;
        while(cmdLength)
        {
                i2cSendByte( *sendData );
                i2cWaitForComplete();
                #ifdef EDP_DEBUG
                rprintf("Sent Data, TWSR:0x%x\r\n",inb(TWSR));
                #endif
                checksum += *sendData++;
                cmdLength--;
        }

        // send the checksum
        i2cSendByte( ~checksum );
        i2cWaitForComplete();
        #ifdef EDP_DEBUG
        rprintf("Sent Checksum, TWSR:0x%x\r\n",inb(TWSR));
        #endif

        // send repeated start condition
        i2cSendStart();
        i2cWaitForComplete();
        #ifdef EDP_DEBUG
        rprintf("Sent Repeated Start, TWSR:0x%x\r\n",inb(TWSR));
        #endif

        // send device address with read
        i2cSendByte( deviceAddr|0x01 );
        i2cWaitForComplete();
        #ifdef EDP_DEBUG
        rprintf("Sent Device Address+Read, TWSR:0x%x\r\n",inb(TWSR));
        #endif

        // read response code, return NACK
        i2cReceiveByte(FALSE);
        i2cWaitForComplete();
        #ifdef EDP_DEBUG
        rprintf("Read Data, TWSR:0x%x\r\n",inb(TWSR));
        #endif
        EdpCommandResponseCode = i2cGetReceivedByte();

        if(EdpCommandResponseCode==EDP_RESP_DATA_REPLY)
        {
                // a data reply is being sent

                // send repeated start condition
                i2cSendStart();
                i2cWaitForComplete();
                
                // send device address with read
                i2cSendByte( deviceAddr|0x01 );
                i2cWaitForComplete();

                // get length, return ACK
                i2cReceiveByte(TRUE);
                i2cWaitForComplete();
                edpCommandReply->Length = i2cGetReceivedByte();
                // set temp variables
                replyLength = edpCommandReply->Length;
                replyData = edpCommandReply->Data;

                // get data, return ACKs
                // preset checksum with the datalength byte
                checksum = replyLength;
                while(replyLength > 1)
                {
                        i2cReceiveByte(TRUE);   // receive data byte and return ACK
                        i2cWaitForComplete();
                        *replyData = i2cGetReceivedByte();
                        checksum += *replyData++;
                        replyLength--;
                }

                // get last data (actually the checksum), return NACK (last-byte signal)
                i2cReceiveByte(FALSE);
                i2cWaitForComplete();
                *replyData = i2cGetReceivedByte();
                // add received checksum+1 to our checksum, the result should be zero
                checksum += (*replyData) + 1;
                // save the reply checksum
                EdpCommandReplyChecksum = checksum;
        }
        
        // transmit stop condition
        // leave with TWEA on for slave receiving
        i2cSendStop();
        while( !(inb(TWCR) & BV(TWSTO)) );
        #ifdef EDP_DEBUG
        rprintf("Sent Stop, TWSR:0x%x\r\n",inb(TWSR));
        #endif
        
        // enable TWI interrupt
        sbi(TWCR, TWIE);

        return EDP_COMMAND_OK;
}

// get the response code and reply from last command
u08 edpGetCommandReply(u08* responseCode, EdpReply** edpReply)
{
        u08 retval=EDP_REPLY_OK;

        // get the response code from last command
        *responseCode = EdpCommandResponseCode;
        // get the reply from last command
        *edpReply = (EdpReply*)EdpCommandReplyBuffer;

        // check response code
        if(EdpCommandResponseCode == EDP_RESP_DATA_REPLY)
        {
                // there was a reply, check the checksum
                // if it's non-zero, data corruption is present
                if(EdpCommandReplyChecksum)
                        retval = EDP_REPLY_BADCHKSUM;
        }
        return retval;
}

/*
u08 edpSendCommand(u08 deviceAddr, u08 sendLength, u08* sendData)
{
        u08* replyData = EdpCommandReplyBuffer;
        u08 replyLength;
        u08 checksum;

        // initialize response variables
        EdpCommandReplyLength = 0;
        EdpCommandReplyChecksum = 0;

        #ifdef EDP_DEBUG
        rprintf("\r\nBegin EdpSendCommand, TWSR:0x%x\r\n",inb(TWSR));
        #endif

        // disable TWI interrupt
        cbi(TWCR, TWIE);

        // clear TWI interface
        //outb(TWCR, (inb(TWCR)&TWCR_CMD_MASK));

        // send start condition
        i2cSendStart();
        i2cWaitForComplete();
        #ifdef EDP_DEBUG
        rprintf("Sent Start, TWSR:0x%x\r\n",inb(TWSR));
        #endif

        // send device address with write
        i2cSendByte( (deviceAddr&0xFE) );
        i2cWaitForComplete();
        #ifdef EDP_DEBUG
        rprintf("Sent Device Address+Write, TWSR:0x%x\r\n",inb(TWSR));
        #endif

        // check if device is present and live
        if( i2cGetStatus() != TW_MT_SLA_ACK)
        {
                // device did not ACK it's address, command will not continue
                // transmit stop condition
                // leave with TWEA on for slave receiving
                i2cSendStop();
                while( !(inb(TWCR) & BV(TWSTO)) );
                #ifdef EDP_DEBUG
                rprintf("No Device!, Sent Stop, TWSR:0x%x\r\n",inb(TWSR));
                #endif
                // enable TWI interrupt
                sbi(TWCR, TWIE);
                // return error
                return EDP_COMMAND_NODEV;
        }

        // send data
        checksum = 0;
        while(sendLength)
        {
                i2cSendByte( *sendData );
                i2cWaitForComplete();
                #ifdef EDP_DEBUG
                rprintf("Sent Data, TWSR:0x%x\r\n",inb(TWSR));
                #endif
                checksum += *sendData++;
                sendLength--;
        }

        // send the checksum
        i2cSendByte( ~checksum );
        i2cWaitForComplete();
        #ifdef EDP_DEBUG
        rprintf("Sent Checksum, TWSR:0x%x\r\n",inb(TWSR));
        #endif

        // send repeated start condition
        i2cSendStart();
        i2cWaitForComplete();
        #ifdef EDP_DEBUG
        rprintf("Sent Repeated Start, TWSR:0x%x\r\n",inb(TWSR));
        #endif

        // send device address with read
        i2cSendByte( deviceAddr|0x01 );
        i2cWaitForComplete();
        #ifdef EDP_DEBUG
        rprintf("Sent Device Address+Read, TWSR:0x%x\r\n",inb(TWSR));
        #endif

        // read response code, return NACK
        i2cReceiveByte(FALSE);
        i2cWaitForComplete();
        #ifdef EDP_DEBUG
        rprintf("Read Data, TWSR:0x%x\r\n",inb(TWSR));
        #endif
        EdpCommandResponseCode = i2cGetReceivedByte();

        if(EdpCommandResponseCode==EDP_RESP_DATA_REPLY)
        {
                // a data reply is being sent

                // send repeated start condition
                i2cSendStart();
                i2cWaitForComplete();
                
                // send device address with read
                i2cSendByte( deviceAddr|0x01 );
                i2cWaitForComplete();

                // get length, return ACK
                i2cReceiveByte(TRUE);
                i2cWaitForComplete();
                replyLength = i2cGetReceivedByte();
                EdpCommandReplyLength = replyLength;

                // get data, return ACKs
                // preset checksum with the datalength byte
                checksum = replyLength;
                while(replyLength > 1)
                {
                        i2cReceiveByte(TRUE);   // receive data byte and return ACK
                        i2cWaitForComplete();
                        *replyData = i2cGetReceivedByte();
                        checksum += *replyData++;
                        replyLength--;
                }

                // get last data (actually the checksum), return NACK (last-byte signal)
                i2cReceiveByte(FALSE);
                i2cWaitForComplete();
                *replyData = i2cGetReceivedByte();
                // add received checksum+1 to our checksum, the result should be zero
                checksum += (*replyData) + 1;
                // save the reply checksum
                EdpCommandReplyChecksum = checksum;
        }
        
        // transmit stop condition
        // leave with TWEA on for slave receiving
        i2cSendStop();
        while( !(inb(TWCR) & BV(TWSTO)) );
        #ifdef EDP_DEBUG
        rprintf("Sent Stop, TWSR:0x%x\r\n",inb(TWSR));
        #endif
        
        // enable TWI interrupt
        sbi(TWCR, TWIE);

        return EDP_COMMAND_OK;
}

u08 edpGetCommandReply(u08* responseCode, u08* replyLength, u08** replyData)
{
        u08 retval=EDP_REPLY_OK;

        // get the response code and reply data from last command
        *responseCode = EdpCommandResponseCode;
        // get the reply length from last command
        *replyLength = EdpCommandReplyLength;
        // get the reply data from last command
        *replyData = EdpCommandReplyBuffer;

        // check response code
        if(EdpCommandResponseCode == EDP_RESP_DATA_REPLY)
        {
                // there was a reply, check the checksum
                // if it's non-zero, data corruption is present
                if(EdpCommandReplyChecksum)
                        retval = EDP_REPLY_BADCHKSUM;
        }
        return retval;
}
*/

// ************ EDP Slave operations ************

// this function will run when a master somewhere else on the bus
// addresses us and wishes to write data to us
void edpSlaveReceiveService(u08 receiveDataLength, u08* receiveData)
{
        u08 i,checksum;

        // initialize the reply length from this command
        EdpSlaveReplyLength = 0;
        // verify the checksum
        // initialize the checksum with 1
        checksum = 0x01;
        // sum all the data in the packet and the data's checksum
        for(i=0; i<receiveDataLength; i++)
        {
                checksum += receiveData[i];
        }
        // if the checksum is non-zero, then the data is corrupt
        if(checksum)
        {
                // set reply code
                // [FIX] which should it be?
                EdpSlaveResponseCode = EDP_RESP_DATA_CHK_ERROR;
                //EdpSlaveResponseCode = EDP_RESP_CMD_CHK_ERROR;
                return;
        }

        // make an EDP command pointer to the received I2C data
        EdpCommand* edpCommand = (EdpCommand*)receiveData;

        // if a slave handler is defined
        if(edpSlaveHandlerFunc)
        {
                // then use it
                EdpSlaveResponseCode = edpSlaveHandlerFunc(
                        receiveDataLength, edpCommand, 
                        EDP_REPLY_BUFFER_SIZE, (EdpReply*)EdpSlaveReplyBuffer);
        }
        else
        {
                // otherwise reply with unknown command
                EdpSlaveResponseCode = EDP_RESP_UNKWN_CMD;
        }
}

// this function will run when a master somewhere else on the bus
// addresses us and wishes to read data from us
u08 edpSlaveTransmitService(u08 transmitDataLengthMax, u08* transmitData)
{
        u08 i;
        u08 checksum;
        u08 transmitDataLength = 0;

        EdpReply* edpReply = (EdpReply*)EdpSlaveReplyBuffer;

        if(EdpSlaveResponseCode)
        {
                // reply code is non-zero, we must send it
                *transmitData = EdpSlaveResponseCode;
                transmitDataLength = 1;
                // reset the reply code to flag that we've sent it
                EdpSlaveResponseCode = 0;
        }
        else
        {
                // reply code already sent, now send data (if any)
                // copy length of reply to transmit buffer (+1 for checksum)
                *transmitData++ = edpReply->Length+1;
                // initialize checksum
                checksum = edpReply->Length+1;
                // copy reply buffer to the transmit buffer
                for(i=0; i<edpReply->Length; i++)
                {
                        *transmitData++ = edpReply->Data[i];
                        checksum += edpReply->Data[i];
                }
                // copy checksum to transmit buffer
                *transmitData++ = ~checksum;
                // set number of bytes to transmit
                transmitDataLength = edpReply->Length+2;
        }

        // return number of bytes written to transmit buffer
        return transmitDataLength;
}
{FILE END}
{FOOTER START}

Powered by WebSVN v2.8.3