mirror of
https://github.com/arduino/Arduino.git
synced 2024-11-29 10:24:12 +01:00
219 lines
7.0 KiB
C
Executable File
219 lines
7.0 KiB
C
Executable File
/*! \file stxetx.c \brief STX/ETX Packet Protocol Implementation Library. */
|
|
//*****************************************************************************
|
|
//
|
|
// File Name : 'stxetx.c'
|
|
// Title : STX/ETX Packet Protocol Implementation Library
|
|
// Author : Pascal Stang - Copyright (C) 2002
|
|
// Created : 10/9/2002
|
|
// Revised : 6/30/2003
|
|
// Version : 0.1
|
|
// Target MCU : any
|
|
// Editor Tabs : 4
|
|
//
|
|
// Description : This library provides a set of functions needed to send and
|
|
// receive STX/ETX packets. STX/ETX is a simple packet protocol that can
|
|
// be wrapped around user data for one or more of the following reasons:
|
|
//
|
|
// 1. packetization is needed
|
|
// - Using packets can be helpful if your data naturally forms
|
|
// little "bunches" or if different types of data must be sent
|
|
// over the same channel (a serial cable, for example). If your
|
|
// data forms "bunches", you can send user data inside STX/ETX
|
|
// packets with a predetermined structure, like an array of A/D
|
|
// conversion results. If you need a way to tell the receiver
|
|
// what kind of data you're sending, you can use the TYPE field
|
|
// in the STX/ETX packet.
|
|
// 2. error checking is needed
|
|
// - STX/ETX packets will add a checksum to your data. This
|
|
// allows the receiver to verify that data was received correctly
|
|
// and is error-free. Packets which are corrupted in transmission
|
|
// and fail the the checksum test are automatically discarded.
|
|
// Error checking is especially useful when the data transmission
|
|
// channel is unreliable or noisy (examples: radio, infrared, long
|
|
// cables, etc)
|
|
//
|
|
// STX/ETX packets have the following structure:
|
|
//
|
|
// [STX][status][type][length][user data...][checksum][ETX]
|
|
//
|
|
// All fields are 1 byte except for user data which may be 0-255 bytes.
|
|
// Uppercase fields are constant (STX=0x02, ETX=0x03), lowercase fields
|
|
// vary. The length field is the number of bytes in the user data area.
|
|
// The checksum is the 8-bit sum of all bytes between but not including
|
|
// STX/ETX.
|
|
//
|
|
// This code is distributed under the GNU Public License
|
|
// which can be found at http://www.gnu.org/licenses/gpl.txt
|
|
//
|
|
//*****************************************************************************
|
|
|
|
#include "global.h"
|
|
#include "stxetx.h"
|
|
//#include "rprintf.h"
|
|
|
|
// function pointer to data output routine
|
|
static void (*stxetxDataOut)(unsigned char data);
|
|
|
|
// received packet data buffer
|
|
unsigned char stxetxRxPacket[STXETX_MAXRXPACKETSIZE];
|
|
|
|
// functions
|
|
|
|
|
|
// Initialize STX/ETX packet protocol library
|
|
void stxetxInit(void (*dataout_func)(unsigned char data))
|
|
{
|
|
stxetxDataOut = dataout_func;
|
|
}
|
|
|
|
// Send/Create STX/ETX packet
|
|
void stxetxSend(unsigned char status, unsigned char type, unsigned char datalength, unsigned char* dataptr)
|
|
{
|
|
unsigned char checksum = 0;
|
|
unsigned short i;
|
|
|
|
// write packet header
|
|
stxetxDataOut(STX);
|
|
stxetxDataOut(status);
|
|
stxetxDataOut(type);
|
|
stxetxDataOut(datalength);
|
|
// update checksum
|
|
checksum += status + type + datalength;
|
|
// copy data into packet
|
|
for(i = 0; i < datalength; i++)
|
|
{
|
|
stxetxDataOut(*dataptr);
|
|
checksum += *dataptr;
|
|
dataptr++;
|
|
}
|
|
// write packet trailer
|
|
stxetxDataOut(checksum);
|
|
stxetxDataOut(ETX);
|
|
}
|
|
|
|
// process buffer containing STX/ETX packets
|
|
unsigned char stxetxProcess(cBuffer* rxBuffer)
|
|
{
|
|
unsigned char foundpacket = FALSE;
|
|
unsigned short i;
|
|
unsigned char length, checksum;
|
|
//unsigned char type;
|
|
|
|
// process the buffer
|
|
// go through buffer looking for packets
|
|
// the STX must be located at least STXETX_HEADERLENGTH+STXETX_TRAILERLENGTH from end
|
|
// otherwise we must not have a complete packet
|
|
while( rxBuffer->datalength >= ((u16)STXETX_HEADERLENGTH+(u16)STXETX_TRAILERLENGTH) )
|
|
{
|
|
// look for a potential start of packet
|
|
if(bufferGetAtIndex(rxBuffer, 0) == STX)
|
|
{
|
|
// if this is a start, then get the length
|
|
length = bufferGetAtIndex(rxBuffer, STXETX_LENGTHOFFSET);
|
|
|
|
// now we must have at least STXETX_HEADERLENGTH+length+STXETX_TRAILERLENGTH in buffer to continue
|
|
if(rxBuffer->datalength >= ((u16)STXETX_HEADERLENGTH+length+(u16)STXETX_TRAILERLENGTH))
|
|
{
|
|
// check to see if ETX is in the right position
|
|
if(bufferGetAtIndex(rxBuffer, STXETX_HEADERLENGTH+length+STXETX_TRAILERLENGTH-1) == ETX)
|
|
{
|
|
// found potential packet
|
|
// test checksum
|
|
checksum = 0;
|
|
// sum data between STX and ETX, not including checksum itself
|
|
// (u16) casting needed to avoid unsigned/signed mismatch
|
|
for(i = 0; i<((u16)STXETX_HEADERLENGTH+length+(u16)STXETX_TRAILERLENGTH-(u16)STXETX_NOETXSTXCHECKSUM); i++)
|
|
{
|
|
checksum += bufferGetAtIndex(rxBuffer, i+STXETX_STATUSOFFSET);
|
|
}
|
|
// compare checksums
|
|
if(checksum == bufferGetAtIndex(rxBuffer, STXETX_CHECKSUMOFFSET+length))
|
|
{
|
|
//we have a packet!
|
|
foundpacket = TRUE;
|
|
|
|
// copy data to buffer
|
|
// (don't copy STX, ETX, or CHECKSUM)
|
|
for(i = 0; i < ((u16)STXETX_HEADERLENGTH+length-1); i++)
|
|
{
|
|
stxetxRxPacket[i] = bufferGetAtIndex(rxBuffer, i+1);
|
|
}
|
|
|
|
// debug
|
|
//rprintf("STXETX Received packet type: 0x%x\n", bufferGetAtIndex(rxBuffer, STXETX_TYPEOFFSET));
|
|
|
|
// dump this packet from the
|
|
bufferDumpFromFront(rxBuffer, STXETX_HEADERLENGTH+length+STXETX_TRAILERLENGTH);
|
|
|
|
// done with this processing session
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
// checksum bad
|
|
//rprintf("STXETX Received packet with bad checksum\r\n");
|
|
// for now, we dump these
|
|
// dump this STX
|
|
bufferGetFromFront(rxBuffer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// no ETX or ETX in wrong position
|
|
// dump this STX
|
|
bufferGetFromFront(rxBuffer);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// not enough data in buffer to decode pending packet
|
|
// wait until next time
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// this is not a start, dump it
|
|
bufferGetFromFront(rxBuffer);
|
|
}
|
|
}
|
|
|
|
// check if receive buffer is full with no packets decoding
|
|
// (ie. deadlocked on garbage data or packet that exceeds buffer size)
|
|
if(!bufferIsNotFull(rxBuffer))
|
|
{
|
|
// dump receive buffer contents to relieve deadlock
|
|
bufferFlush(rxBuffer);
|
|
}
|
|
|
|
return foundpacket;
|
|
}
|
|
|
|
unsigned char stxetxGetRxPacketStatus(void)
|
|
{
|
|
// return the packet's status
|
|
// (subtract 1 from the offset because the STX has already been discarded)
|
|
return stxetxRxPacket[STXETX_STATUSOFFSET-1];
|
|
}
|
|
|
|
unsigned char stxetxGetRxPacketType(void)
|
|
{
|
|
// return the packet's type
|
|
// (subtract 1 from the offset because the STX has already been discarded)
|
|
return stxetxRxPacket[STXETX_TYPEOFFSET-1];
|
|
}
|
|
|
|
unsigned char stxetxGetRxPacketDatalength(void)
|
|
{
|
|
// return the packet's datalength
|
|
// (subtract 1 from the offset because the STX has already been discarded)
|
|
return stxetxRxPacket[STXETX_LENGTHOFFSET-1];
|
|
}
|
|
|
|
unsigned char* stxetxGetRxPacketData(void)
|
|
{
|
|
// return a pointer to the packet's data payload
|
|
// (subtract 1 from the offset because the STX has already been discarded)
|
|
return stxetxRxPacket+STXETX_DATAOFFSET-1;
|
|
}
|