Below you will find implementations of the Amulet UART protocol written in C, BASIC, and assembly. Please note that these code snippets are presented here to illustrate the workings of the protocol, not serve as a model implementation.
/********************************************************************
*MAIN ROUTINE - initializes RingBuffer and sets the baud to 9600, then
*stays in an infinite loop polling the serial line to see if anything
*has been received, and then handling the byte received.
*NOTE: the serIn() function simply checks the serial line to see if
*anything is there, if not it returns
***********************************************************************/
int main()
{
rbInit(buffer);
setbaud(BAUD9600);
while(1)
{
serIn(&buffer);
}
return(0);
}
/**************************************************************************
*Checks to see if anything is waiting on the serial line to be handled,
*if so, it puts it at the end of the Ringbuffer, otherwise it does nothing
*and returns
**************************************************************************/
void serIn(RingBuf *buf)
{
if ((SCSR & RDRF) != 0)
{
tail = buf->tail;
buf->serData[tail++]
= SCDR;
buf->tail =
(tail & RB_SIZE_MASK);
parseSerial();
}
}
/*************************************************************************
*This function acts as the byte handler to the bytes that serIn() puts
*in the Ringbuffer. Checks to see if valid request type has been
*received and then sets server response value. Using a standard state
*machine, the program proceeds to set variables to hold the values of
*the next byte received on the serial lines and when the correct number
*of bytes have been received (3 bytes for all request types except
*setByte which needs 5 bytes) later calls functions that put the
*variables back out on the serial line for output
*************************************************************************/
void parseSerial(void)
{
static char caseType;
newByte = byteFromBuf(&buffer);
if((newByte
>= 0xD0) && (newByte <= 0xD8))
{
serverResp = respMake(newByte);
caseType = serverResp;
}
else if(state == 0)
caseType = 0x00;
if((state==0)
&& ((caseType >= 0xD0) && (caseType <= 0xD5)))
{
state++;
}
else if(state == 1)
{
hiNib = newByte;
state++;
}
else if(state == 2)
{
loNib = newByte;
if(caseType
== 0xD5)
{
state++;
}
else
{
state
= 0;
}
switch(caseType)
{
case
0xD0:
getByte();
break;
case
0xD1:
getString();
break;
case
0xD2:
getWord();
break;
case
0xD8:
invokeRPC();
break;
}
}
else if((state == 3) && (caseType ==
0xD5))
{
setValHi = newByte;
state++;
}
else if(state == 4)
{
setValLo = newByte;
state = 0;
setByte();
}
}
/*********************************
*Hex to ascii conversion routine
**********************************/
char hex2ascii(char hex)
{
return ((hex < 0x0A) ? (hex + '0') : (hex
+ ('A' - 0x0A)));
}
/*********************************
*Ascii to hex conversion routine
**********************************/
char ascii2hex(char ascii)
{
return((ascii <= '9') ? (ascii - '0') : (ascii
- ('A' - 0x0A)));
}
/*************************************************************************
*Handler for a getByte function request
* Format of request string is three bytes => 0xD0 vH vL, where v = variable being requested,
*
vH is ASCII version of high nibble of v and vL is ASCII of low nibble
of v.
* Returns five bytes => 0xE0 vH vL NH NL,
* where N = value
of variable v (low byte),
* NH is ASCII version of high nibble of N and NL is ASCII of low nibble
of N.
********************************************************************************/
void getByte(void)
{
char index, byteValue, valueHiNib, valueLoNib;
index = ascii2hex(hiNib) << 4;
index |= ascii2hex(loNib);
byteValue = byteData[index];
valueHiNib = hex2ascii(byteValue >> 4);
valueLoNib = hex2ascii(byteValue & 0x0f);
putchar(serverResp);
putchar(hiNib);
putchar(loNib);
putchar(valueHiNib);
putchar(valueLoNib);
}
/******************************************************************************
*Handler for a getString function request
* Format of request string is three bytes => 0xD2 vH vL, where v = index
of string variable,
* vH is ASCII version of high nibble of v and
vL is ASCII of low nibble of v.
* Returns variable number of byte: 0xE2 vH vL String+Null to client
*
* This routine is only looking to respond with one of two strings. Therefore,
it
* is only looking at the least significant nibble of string variable
index.
*
* Uses putchar from ICC C library to put individual characters onto serial
line
*******************************************************************************/
void getString(void)
{
putchar(serverResp);
putchar(hiNib);
putchar(loNib);
if(loNib == 0x30)
{
putstring(string1);
}
if(loNib == 0x31)
{
putstring(string2);
}
}
/**********************************************************************
*Handler for a setByte function request
* Format of request string is five bytes => 0xD5 vH vL NH NL, where v = index
of byte variable,
* vH is ASCII version of high nibble of v and
vL is ASCII of low nibble of v,
* N = value of variable v,
* NH is ASCII version of high nibble of N
and NL is ASCII of low nibble of N.
* Returns five bytes =>
0xE5 vH vL NH NL,
* where P vH vL NH NL are all duplicates of the bytes
that were in the request string.
***********************************************************************/
void setByte(void)
{
char index, hexVal;
index = ascii2hex(hiNib) << 4;
index |= ascii2hex(loNib);
hexVal = ascii2hex(setValHi) << 4;
hexVal |= ascii2hex(setValLo);
byteData[index] = hexVal;
putchar(serverResp);
putchar(hiNib);
putchar(loNib);
putchar(setValHi);
putchar(setValLo);
}
/*******************************************************************************
*Handler for a getWord function request
* Format of request string is three bytes => 0xD1 vH vL, where v = index
of word variable,
* vH is ASCII version of high nibble of v and
vL is ASCII of low nibble of v.
* Returns seven bytes => 0xE1 vH vL PH PL NH NL,
* where P = value of variable v
(high byte), N = value of variable v (low byte),
* PH is ASCII version of high nibble of P and PL is ASCII of low nibble
of P,
* NH is ASCII version of high nibble of N and NL is ASCII of low
nibble of N.
********************************************************************************/
void getWord(void)
{
char index, valMSBhinib, valMSBlonib, valLSBhinib,
valLSBlonib;
unsigned int wordValue;
index = ascii2hex(hiNib) << 4;
index |= ascii2hex(loNib);
wordValue = wordData[index];
valMSBhinib = hex2ascii((char)((wordValue >>
12) & 0x0f));
valMSBlonib = hex2ascii((char)((wordValue >>
8) & 0x0f));
valLSBhinib = hex2ascii((char)((wordValue >>
4) & 0x0f));
valLSBlonib = hex2ascii((char)(wordValue &
0x0f));
putchar(serverResp);
putchar(hiNib);
putchar(loNib);
putchar(valMSBhinib);
putchar(valMSBlonib);
putchar(valLSBhinib);
putchar(valLSBlonib);
}
/*******************************************************************************
*Handler for an invokeRPC function
* Format of request string is three bytes => 0xD8 rH rL, where r = index
of RPC,
* rH is ASCII version of high nibble of r and rL is ASCII of
low nibble of r.
* Returns three bytes => 0xD8 rH rL,
* where rH rL are duplicates
of the bytes that were in the request string.
********************************************************************************/
void invokeRPC(void)
{
char rpc, valMSBhinib, valMSBlonib, valLSBhinib,
valLSBlonib;
unsigned int wordValue;
rpc = ascii2hex(hiNib) << 4;
rpc |= ascii2hex(loNib);
performRPC[rpc]; // this
code could do any number of things based upon
//
which Remote Procedure Call is requested.
putchar(serverResp);
putchar(hiNib);
putchar(loNib);
}
/*********************************************
*Function to take a byte out of the buffer
**********************************************/
char byteFromBuf(RingBuf *buf)
{
char byte;
head = buf->head;
byte = buf->serData[head];
buf->head = (head + 1) & RB_SIZE_MASK;
return byte;
}
/*********************************************************************************
*Function to assign a serverResp value based on the byte taken out of the
buffer
**********************************************************************************/
char respMake(char byte)
{
// Response is always 0x10 greater than the
command opcode
return (byte + 0x10);
}
/**********************************************
*Function to put a string onto the serial line
**********************************************/
void putstring(char *str)
{
char iloop;
char index = 0;
char value;
for(iloop=0; iloop <= strlen(str); iloop++)
{
value = str[index];
putchar(value);
index++;
}
}
------------------------------------------------------------------------------------------------------------------------------------------
The following BASIC source code was taken from actual server implementation based on a Basic Stamp interfaced to an Analog Devices ADXL202EB accelerometer.
'*********************************************************************************************************************
'* The main loop of this code waits for valid Client Start of Message (CSOM)
characters then jumps to the appropriate
'* service routine
'*********************************************************************************************************************
incoming
VAR byte(6) ' Incoming buffer
'********************************************************************************************************************
'
serin Rpin, Baudmode, [STR incoming\L\E]
' serin = receive asynchronous
serial data
' Rpin = Rx (instruct BASIC Stamp to use dedicated serial-input
pin)
' Baudmode = N9600 (9600 baud, 8-bit data, no-parity, true
polarity)
' [STR amuletMsg\L\E] = receive string of length L or until end
character E is received into amuletMsg array
'
' The command serin Rx,
N9600, [STR incoming\L\E]
' will poll the serial line looking for serial
data up to length L or until end character E is encountered.
' Incoming data
will be stored in the amuletMsg
array.
'********************************************************************************************************************
serial_in:
SERIN 16, 84, [RxType, VarType1, VarType2, SetVar1, SetVar2]
SERIN 16, 84, [STR incoming\6\0] '* Read a
max of 6 bytes or stop when received a null termination character
RxType = incoming(0)
VarType1 = incoming(1)
VarType2 = incoming(2)
IF RxType = $D5 THEN setByte 'asking for a setByte
IF RxType = $D0 THEN getByte 'asking for a getByte
IF RxType = $D2 THEN getString 'asking for a getString
IF RxType = $D1 THEN getWord 'asking for a getWord
IF RxType > $D5 THEN serial_in 'value on line is
not a function, go back to wait for
'another
command
'******************************************************************************
'* Handler for a getByte function request
'* Format of request string = 0xD0xx, where xx = variable being requested
'* Returns 0xE0xxNN, where NN equals the HEX data of the variable xx
'******************************************************************************
getByte:
ServerResp1 = $E0
IF
VarType2 = "5" THEN RateReturn
IF VarType2 = "6" THEN TimeReturn
IF VarType2 = "7" THEN VariableReturn
'Variable
5 is being requested so return value stored for rate (in register B20)
RateReturn:
SEROUT 16,84,[ServerResp1,
VarType1, VarType2, HEX2 B20]
GOTO serial_in
'Variable 6 is being requested so return value
stored for time (in register B22)
TimeReturn:
SEROUT 16,84,[ServerResp1,
VarType1, VarType2, HEX2 B22]
GOTO serial_in
'Variable
7 is being requested so return value stored for variable (in register B21)
VariableReturn:
SEROUT 16,84,[ServerResp1,
VarType1, VarType2, HEX2 B21]
GOTO serial_in
'****************************************************************************
* Handler for a getString function request
'* Format of request string = 0xD2xx, where xx = index of string variable
'* Returns 0xE2xxString+Null to client
'* Returns requested data back to the screen
'****************************************************************************
getString:
ServerResp1 = $E2
IF
VarType2 = "2" THEN Author_string
IF VarType2 = "3" THEN Company_string
Author_string:
SEROUT 16,84,[ServerResp1,
VarType1, VarType2, "Jacob Horn", NULL]
GOTO serial_in
Company_string:
SEROUT 16,84,[ServerResp1,
VarType1, VarType2, "Amulet Technologies",
NULL]
GOTO serial_in
'***********************************************************************
'* Handler for a setByte function request
'* Format of request string = 0xD5xxNN, where xx = variable to be set
'* and NN = HEX data
'* Returns 0xE5xxNN to client
'***********************************************************************
setByte:
ServerResp1 = $E5
IF VarType2 = "5" THEN Rate
IF VarType2 = "6" THEN Time
'Variable
5 has been called to be set
Rate:
'Choose which
parameter associated with rate is to be set, using NN values
IF incoming(4) = "0"
THEN one
IF incoming(4) = "1"
THEN two
IF incoming(4) = "2"
THEN five
IF incoming(4) = "3"
THEN ten
one:
B20
= 1
GOTO
setByteResp
two:
B20
= 2
GOTO
setByteResp
five:
B20
= 5
GOTO
setByteResp
ten:
B20
= 10
GOTO
setByteResp
'Variable
6 has been called to be set
Time:
'Once again, choose
which parameter is to be set using NN values
IF incoming(4) = "0"
THEN tenSeconds
IF incoming(4) = "1"
THEN thirtySeconds
IF incoming(4) = "2"
THEN fortyfiveSeconds
IF incoming(4) = "3"
THEN sixtySeconds
tenSeconds:
B22
= 10
GOTO
setByteResp
thirtySeconds:
B22
= 30
GOTO
setByteResp
fortyfiveSeconds:
B22
= 45
GOTO
setByteResp
sixtySeconds:
B22
= 60
GOTO
setByteResp
setByteResp:
SEROUT 16,84,[ServerResp1,
VarType1, VarType2, incoming(3), incoming(4)]
GOTO serial_in
'*********************************************************************************************
'* Handler for a getWord function request
'* Format of request string = 0xD1xx, where xx = variable being requested
'* Returns 0xE1xxPPNN, where PP = high byte of variable xx, and NN = low byte
of variable xx
'*********************************************************************************************
getWord:
ServerResp1 = $E1
IF
VarType2 = "1" THEN YWORDvariable
'Pulse X port pin, read, and save out x acceleration
values
PULSIN 4,1,xWord
ServerResp2
= xWord.HIGHBYTE
ServerResp3 = xWord.LOWBYTE
'server data sent out over RS232 to client
SEROUT 16,84,[ServerResp1, VarType1, VarType2,
HEX2 ServerResp2,
HEX2 ServerResp3]
GOTO serial_in
YWORDvariable:
PULSIN 2,1,yWord
ServerResp2 =
yWord.HIGHBYTE
ServerResp3 =
yWord.LOWBYTE
SEROUT
16,84,[ServerResp1, VarType1, VarType2, HEX2 ServerResp2,
HEX2
ServerResp3]
GOTO serial_in
END
-------------------------------------------------------------------------------------------------------------------------------------------
The following assembly code snippets were taken from an actual server implementation based on Atmel's AVR 8-bit RISC microcontroller (Part# AT90LS4433).
;********************************************************************
;Main loop of program. Waits for valid Client Start Of Message (CSOM)
;characters, then vectors to the appropriate service routine.
;********************************************************************
.equ GetCommand = 0xD0
.equ GetResponse = 0xE0
.equ StringCommand = 0xD2
.equ StringResponse = 0xE2
.equ SetCommand = 0xD5
.equ SetResponse = 0xE5
.equ InvokeCommand = 0xD8
.equ InvokeResponse = 0xE8
try_again:
rcall getch ;Go and wait until a character is present in the buffer
cpi buffer,GetCommand ;Is it a get command?
brne is_it_S ;Not get command, so check others
rjmp handleG
is_it_String:
cpi buffer,StringCommand;Is it a string command?
brne is_it_S ;Not string command, so check for set
rjmp handleString
is_it_S:
cpi buffer,SetCommand ;Is it a set command?
brne is_it_I ;Not set command, so check for I
rjmp handleS
is_it_I:
cpi buffer,InvokeCommand ;Is it an invoke command?
brne try_again ;Not a valid request so start over and wait for next character
rjmp handleI
;********************************************************************
;Handle Get Byte command to get variable data
; Format of request string = 0xD0xx
; where xx = variable requested
; Returns 0xE0xxNN to client where NN = HEX data of variable (xx)
;********************************************************************
handleG:
rcall getByte ;Read both nibbles of xx and assemble into a byte. Return in buffer.
brcc try_again ;If carry cleared, then invalid value, so start over
mov which,buffer
ldi buffer,GetResponse
rcall putch ;Acknowledge valid command
mov buffer,which
swap buffer ;Rotate MSNibble into LSNibble position
rcall nib2ascii ;Convert LSNibble of buffer to an ASCII character
rcall putch ;Echo back MSNibble of variable (xx)
mov buffer,which
rcall nib2ascii ;Convert LSNibble of buffer to an ASCII character
rcall putch ;Echo back LSNibble of variable (xx)
rcall get_varH ;Go get data (msn) for variable (xx)
rcall putch ;Transfer data to the client
rcall get_varL ;Go get data (lsn) for variable (xx)
rcall putch ;Transfer data to the client
rjmp try_again ;Done with Get command so start over
;Handle String command to tx a string back.
; Format of request string = 0xD2xx
; where xx = index of string variable
; Returns 0xE2xxString+Null to host.
;******************************************************
handleString:
rcall getByte ;Read both nibbles of xx and assemble into a byte. Return in buffer.
brcc try_again ;If carry cleared, then invalid value and start over
mov which,buffer
ldi buffer,StringResponse
rcall putch ;Acknowledge valid command
mov buffer,which
swap buffer ;Rotate MSNibble into LSNibble position
rcall nib2ascii ;Convert LSNibble of buffer to an ASCII character
rcall putch ;Echo back MSNibble of variable (xx)
mov buffer,which
rcall nib2ascii ;Convert LSNibble of buffer to an ASCII character
rcall putch ;Echo back LSNibble of variable (xx)
... ;To simplify this snippet, all the code which looks up the string(xx)
... ;in a look-up table was left out
icall ;Time to go pound the null terminated string out
rjmp try_again ;Done with string command so start over
;****************************************
;Handle S command to Set variable data
; Format of request string = 0xD5xxNN
; where xx = variable to set
; NN = HEX data for variable (xx)
; Returns 0xE5xxNN to client
;****************************************
handleS:
rcall getByte ;Read both nibbles of xx and assemble into a byte. Return in buffer.
brcc try_again ;If carry cleared, then invalid value, so start over
mov which,buffer
rcall getByte ;Read both nibbles of NN and assemble into a byte. Return in buffer.
brcc try_again ;If carry cleared, then invalid value, so start over
mov what,buffer
;This is where we would use the value of xx, now stored in 'which', to determine
;where to store the value of NN, now stored in 'what'. For the sake of brevity,
;this example only handles xx=00, while all other xx are ignored.
cpi which,0 ;If offset is zero, then VAR0 is the variable to set
brne try_again
sts VAR0,what ;Set VAR0
ldi buffer,SetResponse
rcall putch ;Acknowledge valid command
mov buffer,which
swap buffer ;Rotate MSNibble into LSNibble position
rcall nib2ascii ;Convert LSNibble of buffer to an ASCII character
rcall putch ;Echo back MSNibble of variable (xx)
mov buffer,which
rcall nib2ascii ;Convert LSNibble of buffer to an ASCII character
rcall putch ;Echo back LSNibble of variable (xx)
mov buffer,what
swap buffer ;Rotate MSNibble into LSNibble position
rcall nib2ascii ;Convert LSNibble of buffer to an ASCII character
rcall putch ;Echo back MSNibble of variable (NN)
mov buffer,what
rcall nib2ascii ;Convert LSNibble of buffer to an ASCII character
rcall putch ;Echo back LSNibble of variable (NN)
rjmp try_again ;Done with Set command so start over
;**************************************
;Handle I command to Invoke a function
; Format of request string = 0xD8xx
; where xx = function to invoke
; Returns 0xE8xx to client
;**************************************
handleI:
rcall getByte ;Read both nibbles of xx and assemble into a byte. Return in buffer.
brcc try_again ;If carry cleared, then invalid value, so start over
mov which,buffer
... ;To simplify this snippet, all the code which looks up the function(xx)
... ;in a look-up table was left out
icall ;Time to go execute the function (xx)
ldi buffer,InvokeResponse
rcall putch ;Acknowledge valid command
mov buffer,which
swap buffer ;Rotate MSNibble into LSNibble position
rcall nib2ascii ;Convert LSNibble of buffer to an ASCII character
rcall putch ;Echo back MSNibble of variable (xx)
mov buffer,which
rcall nib2ascii ;Convert LSNibble of buffer to an ASCII character
rcall putch ;Echo back LSNibble of variable (xx)
rjmp try_again ;Done with Invoke command so start over
Amulet HTMLCompiler,
Copyright © 2000-2004 by
Amulet Technologies, LLC
Back to Welcome - Contact Amulet - Amulet Home