;*************** Mini Area Network ***************************************** ;intial commented version April 24, 2000 3:16 pm .nolist .include "c:\AVRtools\appnotes\8515def.inc" .list .def save = r1 ;save SREG .def zero = r2 ;null value .def temp = r16 ;temporary variable .def userid = r17 ;user id .def newbuf = r18 ;pointer to newest message .def oldbuf = r19 ;pointer to oldest message .def count = r20 .def char = r21 ;empty for now .def rcvbuf = r22 ;offset to receive (user) buffer .def printbuf = r23 ;buffer being printed .def TXbusy = r24 ;transmitting flag for UART .def RXchar = r25 ;received character from UART .def fullbuf = r26 ;buffer full flag .def TXflash = r27 ;set if transmitted string is in flash, clear otherwise .def YL = r28 .def YH = r29 .def ZL = r30 .def ZH = r31 .equ idnum = 17 .equ device1 = 17 ;user identification number .equ device2 = 18 ;user identification number .equ device3 = 19 ;user identification number .equ device4 = 20 ;user identification number .equ baud96 = 25 ;baud rate .equ enter = 13 ;enter key .equ bkspace = 8 ;backspace .equ start = 2 ;start of text .equ null = 0 ;end of text .equ ack = 6 ;acknowledge .equ token = 11 ;token .equ notoken = 12 .equ char = ' ' ;first character in ascii table .equ idaddend = 127 ;last character in ascii table .equ escape = 27 ;escape .equ bufmax = 150 ;biggest offset for pointer to message .equ bufsize = 25 ;size of each message buffer .equ azero = '0' ;*************************************************************************** .dseg stringbuf: .byte 150 userbuf: .byte 25 ;*************************************************************************** .cseg .org $0000 rjmp RESET reti reti reti reti reti reti reti reti rjmp UARTRX rjmp UARTEM reti reti userid: .db "User ", 0x00 punct: .db ": ", 0x00 crlf: .db 0x0d, 0x0a, 0x00 chat: .db "Chat Room -- 1", 0x00 havetoken: .db "I am the token", 0x00 ;*************************************************************************** RESET: ;ALWAYS setup a stack pointer ldi Temp, LOW(RAMEND) ;setup stack pointer out SPL, Temp ldi Temp, HIGH(RAMEND) out SPH, Temp ;setup Transmit Port ser temp ;set PORTC as output pins out DDRA, temp ;setup Master ID Port clr temp out DDRB, temp ;setup Receive Port clr temp ;set PORTC as input pins out DDRC, temp ;setup UART Port ser temp ;set PORTD as output pins out DDRD, temp ;setupt UART ldi temp, 0b10011000 ;set UART Empty and UART Recieve Interrupt out UCR, temp ldi temp, baud96 ;set UART Baud Rate out UBRR, temp ;initialize variables clr newbuf ;clear registers ldi oldbuf, 200 clr temp clr zero clr rcvbuf clr fullbuf clr count ldi ZL, low(stringbuf) ldi ZH, high(stringbuf) sei ;clear RAM RAMclear: inc count ldi RXchar, 'w' rcall putc st Z+, zero cpi count, 150 breq _startup rjmp RAMclear ;*************************************************************************** ;Loop Initialization Procedure _startup: ldi printbuf, 0 rcall _refresh ldi RXchar, 'z' rcall putc ldi ZL, low(chat<<1) ldi ZH, high(chat<<1) lpm out UDR, r0 ;trigger the UART TX ser TXflash ser TXbusy ;and set the TX busy flag sbi UCR, UDRIE ;enable the TXempty interrupt rcall TXwait ldi ZL, low(crlf<<1) ldi ZH, high(crlf<<1) lpm out UDR, r0 ;trigger the UART TX ser TXflash ser TXbusy ;and set the TX busy flag sbi UCR, UDRIE ;enable the TXempty interrupt rcall TXwait _initialize: ldi userid, idnum ;simple user id sbis PINB, 0 ;identify master rjmp _mastertoken ;initialize as master in temp, PINC cpi temp, token breq _slavetoken ;initialize as slave rjmp _initialize _mastertoken: ldi RXchar, 'h' rcall putc ser temp out DDRB, temp ldi temp, token out PORTA, temp ;transmit token in temp, PINC cpi temp, token breq _masterack ;until receive token rjmp _mastertoken _masterack: ldi RXchar, 'i' rcall putc ldi temp, ack out PORTA, temp ;transmit acknowledge in temp, PINC cpi temp, ack brne _masterack ;until receive acknowledge rjmp _txstart _slavetoken: ldi RXchar, 'h' rcall putc ser temp out DDRB, temp ldi temp, token out PORTA, temp ;transmit token in temp, PINC cpi temp, ack breq _slaveack ;until receive acknowledge rjmp _slavetoken _slaveack: ldi RXchar, 'i' rcall putc ldi temp, ack out PORTA, temp ;transmit acknowledge in temp, PINC cpi temp, ack breq _slaveack rjmp _mainloop ;until receive non-acknowledge ;*************************************************************************** ;Main Loop Procedure _mainloop: in temp, PINC ;ldi RXchar, 'm' ;rcall putc cpi temp, device1 breq _jmpreceive ;receive text cpi temp, device2 breq _jmpreceive ;receive text cpi temp, device3 breq _jmpreceive ;receive text cpi temp, device4 breq _jmpreceive ;receive text cpi temp, token breq _jmptransmit ;transmit text ;out PORTA, temp ;mov RXchar, temp ;rcall putc rjmp _mainloop _jmpreceive: ;ldi RXchar, 'r' ;rcall putc rjmp _receive ;jump to code _jmptransmit: ;ldi RXchar, 't' ;rcall putc rjmp _transmit ;jump to code ;*************************************************************************** ;Receive Character Procedure _receive: _rxallocbuf: in temp, PINC ;receive sender id out PORTA, temp ;transmit sender id subi temp, -azero ;convert sender id to simple sender id ldi ZL, low(stringbuf) ;allocate new buffer for sender message ldi ZH, high(stringbuf) add ZL, newbuf adc ZH, zero st Z+, temp ;sender id into first character of sender message _rxchar: ;ldi RXchar, 'c' ;rcall putc in temp, PINC mov RXchar, temp rcall putc out PORTA, temp ;ldi RXchar, 'p' ;rcall putc cpi temp, device1 breq _rxchar ;wait for character to start receiving cpi temp, device2 breq _rxchar ;wait for character to start receiving cpi temp, device3 breq _rxchar ;wait for character to start receiving cpi temp, device4 breq _rxchar ;wait for character to start receiving cpi temp, ack breq _rxchar st Z+, temp ;place character in buffer cpi temp, null breq _rxend ;if end of text send handle appropriately _rxack: ldi RXchar, 'k' rcall putc in temp, PINC ;receive acknowledgement of recieving character out PORTA, temp ;transmit acknowledgement of receiving character cpi temp, ack brne _rxack ;receive acknowledge until non-acknowledge character rjmp _rxchar ;send next character _rxend: ldi RXchar, 'e' rcall putc in temp, PINC cpi temp, null breq _rxend ;wait until non-enter character to return to main loop mov printbuf, oldbuf ;rcall _refresh ;refresh screen with new message subi newbuf, -bufsize ;update the pointer to the newest message in the buffer ldi temp, bufmax cpse newbuf, temp clr newbuf subi oldbuf, -bufsize ;update the pointer to the oldest message in the buffer ldi temp, bufmax cpse oldbuf, temp clr oldbuf rjmp _mainloop ;*************************************************************************** ;Transmit Character Procedure _transmit: _rxtoken: ;ldi RXchar, 'w' ;rcall putc ldi temp, notoken out PORTA, temp ;transmit notoken in temp, PINC cpi temp, ack brne _rxtoken ;until receive notoken _txstart: out PORTB, fullbuf tst fullbuf ;check if user text buffer full brne _txallocbuf ;if full transmit identification rjmp _txtoken ;else transmit token _txallocbuf: ldi ZL, low(userbuf) ;prepare to read own user buffer ldi ZH, high(userbuf) ldi YL, low(stringbuf) ;prepare to load string buffer for received messages ldi YH, high(stringbuf) add YL, newbuf ;allocate new buffer for own user message adc YH, zero st Y, userid ;store user id in the string buffer (may over write old id) _txid: ldi RXchar, 'i' rcall putc mov temp, userid out PORTA, temp ;transmit user identification in temp, PINC cp temp, userid breq _txchar ;until receive user identification rjmp _txid ;transmit identification again _txchar: ld char, Z ;load character to transmit mov RXchar, char rcall putc out PORTA, char ;transmit character in temp, PINC cpi temp, null ;if receive end of text breq _txend ;end transmission cp temp, char ;if receive character back ;ldi RXchar, 'x' ;rcall putc ;mov RXchar, temp ;rcall putc breq _txack ;transmit acknowledge rjmp _txchar ;otherwise transmit chacter again _txack: ldi RXchar, 'j' rcall putc st Y, char ;store character into own user buffer ldi temp, ack ;load acknowledge character out PORTA, temp in temp, PINC cpi temp, ack breq _txnextchar ;if acknowledge transmit next character rjmp _txack ;otherwise transmist acknowledge again _txnextchar: ldi RXchar, 'r' rcall putc adiw ZL, 1 ;increment to transmit the next character adiw YL, 1 ;increment to receive the next character rjmp _txchar ;transmit next character _txend: ldi RXchar, 'x' rcall putc mov printbuf, oldbuf ldi printbuf, 0 rcall _refresh ;refresh the screen clr fullbuf ;subi newbuf, -bufsize ;update the pointer to the newest message in the buffer ;ldi temp, bufmax ;cpse newbuf, temp clr newbuf ldi RXchar, 'g' rcall putc ;subi oldbuf, -bufsize ;update the pointer to the oldest message in the buffer ;ldi temp, bufmax ;cpse oldbuf, temp ;clr oldbuf _txtoken: ;ldi RXchar, 'o' ;rcall putc ldi temp, token out PORTA, temp ;pass token to next user in temp, PINC cpi temp, notoken brne _txtoken ;until receive notoken ldi temp, ack out PORTA, temp ;send acknowledge to next user rjmp _mainloop ;return to main loop ;*************************************************************************** ;UART Interface Procedure _refresh: push temp ldi RXchar, 'n' rcall putc ldi RXchar, 'n' rcall putc ldi RXchar, 'n' rcall putc ldi ZL, low(stringbuf) ;prepare to print out messages ldi ZH, high(stringbuf) add ZL, printbuf ;print out oldest message adc ZH, zero ld r0, Z+ out UDR, r0 clr TXflash ser TXbusy sbi UCR, UDRIE rcall TXwait subi printbuf, -bufsize ;ldi temp, bufmax ;cpi printbuf, bufmax ;brne _noreset ;clr printbuf ;clear if printbuf greater than 200 to get all messages _noreset: ;cp printbuf, oldbuf ;check if printed all the messages in string buffer cpi printbuf, 100 brlt _refresh ;if not repeat loop again pop temp ret ;if so done printing the buffer ;*************************************************************************** ;Interrupt Service Routines ;UART Receive Complete Interrupt UARTRX: in save, SREG push temp push ZL push ZH in temp, UDR mov RXchar, temp rcall putc ;transmit one char ldi ZL, low(userbuf) ;download pointer to user buffer ldi ZH, high(userbuf) add ZL, rcvbuf ;add offset to pointer adc ZH, zero st Z+, temp inc rcvbuf cpi temp, enter ;if "enter" character message end brne exit ser fullbuf ;ldi RXchar, 'f' ;rcall putc ldi temp, 0x0d ;store the carriage return line feed and a st Z+, temp ;null character ldi temp, 0x0a st Z+, temp ldi temp, 0x00 st Z+, temp clr rcvbuf exit: pop ZH pop ZL pop temp out SREG, save reti ;UART Transmit Register Empty Interrupt UARTEM: in save, SREG ;save SREG tst TXflash breq TXram inc ZL ;output next character lpm ;and put it in r0 rjmp TXfls TXram: inc ZL ld r0, Z TXfls: tst r0 ;check if terminating character breq TXend out UDR, r0 rjmp TXexit TXend: clr TXbusy ;exit wait loop if terminating character cbi UCR, UDRIE ;disable UART UDR empty interrupt TXexit: out SREG, save ;load SREG reti ;*************************************************************************** ;Subroutines TXwait: tst TXbusy ;wait in loop until terminating character ldi RXchar, 'f' rcall putc brne TXwait ret putc: sbis USR, UDRE ;check empty flag rjmp putc out UDR, RXchar ;transmit one char ret getc: sbis USR, RXC ;check receive flag rjmp getc in RXchar, UDR ;receive one char ret