//EE476 - Spring 20019
//FINAL PROJECT - Wireless email pager
//
//Ajay Deonarine (add4) and Johnny Tseng (jjt9)
//-------------------------------------------
#include <90s8515.h>
#include <stdio.h> // sprintf
#include <delay.h> // delay_ms
#include <lcd.h> // LCD driver routines
#include <stdlib.h>
//**********************************************************
//Global Declarations
//**********************************************************
//timer 1 constants
#define prescale1 1
#define clear_on_match 8
//task timers
unsigned int keypad_timer; //task
scheduleing timeout counters
unsigned int receiver_timer;
unsigned int transmitter_timer;
unsigned int checkmail;
#define keypad_ovfl 30
#define receiver_ovfl 2
#define transmitter_ovfl 2
#define checkmail_ovfl 100
//expire timers
int ACK_timer; //Ack timeout
unsigned int timeout; //receiving msg timeout
unsigned int trysend_timer;
//try send timeout
#define ACK_ovfl 5000
#define timeout_ovfl 5000
#define trysend_ovfl 5000
/*------------------------------
SUBROUTINES
-------------------------------*/
void initialize(void);
//KeyPad detect state machine
void KeyCommand(void);
void KeyPad(void); //keypad
scanning
void Release(void);
void Debounce(void);
void DetectTerm(void);
void StillPressed(void);
void DebounceRelease(void);
//Transmitter
void TrySend(void);
void SendAck(void);
void SendMsg(void);
//send msg
//Receiver
void WaitForInit(void);
void WaitForAck(void);
void ReceiveMessage(void);
//RESET
void Reset(void); //clears lcd and message
/*------------------------------
KEYPAD
STUFF
-------------------------------*/
#define maxkeys 27
//KEYPAD STATES
#define keycommand_state 0;
#define release_state 1;
#define debounce_state 2;
#define detectterm_state 3;
#define stillpressed_state 4;
#define debouncerelease_state 5;
unsigned char keypadEnable;
char keypadstate;
unsigned char key, butnum, lastnum;
unsigned char keycount;
unsigned char maybe;
unsigned char termSend, termReset, termSpace;
//key pad scan table
flash unsigned char keytbl[26]={0xee, 0xed, 0xeb, 0xde,
0xdd, 0xdb, 0xbe, 0xbd, 0xbb, 0x7e, 0x6c, 0x6d, 0x69, 0x5c, 0x5d, 0x59, 0x3c,
0x3d, 0x39, 0x7c, 0x6a, 0x6b, 0x5a, 0x7a, 0x5b, 0x3b};
flash unsigned char keymap[24]={ 'a', 'b' , 'c' , 'd' , 'e'
, 'f' , 'g' , 'h' , 'i' , 'j' , 'k' , 'l' , 'm' , 'n' , 'o' , 'p' , 'q' , 'r' ,
's' , 't' , 'u' , 'v' , 'w' , 'x'}; //missing xyz
/*------------------------------
SEND MESSAGE
STUFF
-------------------------------*/
#define max_msg_size 81 //maximum num of char the message
can have
//80
+ 1, 1 is terminating char
unsigned char compose; //0=not composing, 1=compose
mode
unsigned char reading;
unsigned char sendmessage[max_msg_size];
//unsigned char max_msg_size; //this is the maximum # of characters per message
unsigned char sendmsg_index; //current
index of the message
unsigned char readytosend; //0=no
data to send, 1=data present
/*------------------------------
READ MESSAGE
STUFF
-------------------------------*/
unsigned char receivedmessage[max_msg_size];
unsigned char receivedmsg_index; //current index of the message
unsigned char readytoread; //0=no
data to read, 1=data present
unsigned char readatleastonce=0;
/*------------------------------
RECEIVER
STUFF
-------------------------------*/
#define r_wait_for_init 0;
#define r_wait_for_ack 1;
#define r_receive_message 2;
#define r_nop 99;
unsigned char receivedByte; //the
byte read from the receiver
unsigned char r_status; //receiver
status
unsigned char receivingmsg; //1
= receiver receiving MESSAGE
//unsigned char ACKreceived;
/*------------------------------
TRANSMITTER
STUFF
-------------------------------*/
#define t_try_send 0;
#define t_send_message 1;
#define t_send_ack 2;
#define t_nop 99;
unsigned char t_status; //transmitter status
unsigned char sendingmsg; //1 =
transmitter sending MESSAGE
/*------------------------------
LCD
STUFF
-------------------------------*/
#asm
.equ
__lcd_port=0x15
#endasm
//LCD location
//for sending
char lcd_x;
char lcd_y;
/*------------end of declaration---------------*/
//**********************************************************
//timer 1 compare-match A ISR
//use timer 1 to handle date and time
interrupt [TIM1_COMPA] void cmpA_overflow(void)
{
//task timers
if
(keypad_timer>0) --keypad_timer; //to get 30ms
if
(receiver_timer>0) --receiver_timer;
if (transmitter_timer>0) --transmitter_timer;
if (checkmail>0) --checkmail;
}
//**********************************************************
//Set it all up
//**********************************************************
void initialize(void){
//set up the ports
DDRD=0x00; // PORT D is an input for the receiver
DDRA=0xff; //PORT A is an output for the
transmitter
DDRB=0xFF;
PORTB=0x00;
delay_us(15);
DDRB=0x00;
//set up timer 1
TIMSK=TIMSK | 0x40; //turn on timer 1 compare match
interrupt
OCR1A = 4000; //to
get 1ms
TCCR1B = prescale1
+ clear_on_match; //start timer1
TCNT1 = 0; //and zero the timer
//init the task
timers
keypad_timer =
keypad_ovfl;
receiver_timer =
receiver_ovfl;
transmitter_timer =
transmitter_ovfl;
ACK_timer = -1;
trysend_timer =
trysend_ovfl;
timeout =
timeout_ovfl;
//init the keypad
vars
keypadEnable = 1; //enable keypad
keycount = 0;
butnum = 99; //99 is the defined release state key
lastnum = 99;
key = 0;
maybe = 0;
termSend = 23; //set this to keytbl[29] = send
message
termReset = 24;
termSpace = 25;
//right space
//Message
initializations
compose=0;
reading=0;
sendmsg_index = 0;
readytosend=0;
receivedmsg_index =
0;
readytoread = 0;
//transmitter
initializations
t_status = t_nop;
sendingmsg=0;
//receiver
initializations
r_status =
r_wait_for_init;
receivingmsg=0;
//LCD
initializations
//LCD uses PORT C
lcd_init(20); //
initialize the LCD for 16 char wide
lcd_x=0;
lcd_y=0;
lcd_clear(); //clear it
//Initial LCD
display
lcd_gotoxy(0,0);
lcd_putsf("Hello");
lcd_gotoxy(0,1);
lcd_putsf("please press: ");
lcd_gotoxy(0,2);
lcd_putsf("'a'=read,");
lcd_gotoxy(0,3);
lcd_putsf("'b'=compose");
lcd_gotoxy(0,0);
////////////////////////////
//crank up the ISRs
#asm
clr r17
sei
#endasm
}
//**********************************************************
//MAIN
//**********************************************************
void main(void)
{
//start
initialize();
// Start LOOP - never ends
while (1) {
/*------------------------------
Check to
see if there is message
-------------------------------*/
if (checkmail ==
0) {
checkmail =
checkmail_ovfl;
if(
(keypadEnable) && (readytoread) && (!compose) &&
(!reading)) {
//write a
constant string from flash
lcd_gotoxy(0,0);
lcd_putsf("GOT
MSG!");
lcd_gotoxy(0,1);
lcd_putsf("please
press: ");
lcd_gotoxy(0,2);
lcd_putsf("'a'=read,");
lcd_gotoxy(0,3);
lcd_putsf("'b'=compose");
lcd_gotoxy(0,0);
}
}
/*------------------------------
KeyPad
Scanning Task
-------------------------------*/
if (
(keypad_timer==0) && (keypadEnable) ) {
keypad_timer = keypad_ovfl; //reload timer
if(keypadstate==0) KeyCommand();
if(keypadstate==1) Release();
if(keypadstate==2) Debounce();
if(keypadstate==3) DetectTerm();
if(keypadstate==4) StillPressed();
if(keypadstate==5) DebounceRelease();
}
/*------------------------------
Transmitter
Task
------------------------------*/
if
(transmitter_timer==0){
transmitter_timer = transmitter_ovfl;
//reload timer
if(t_status==0) TrySend();
if(t_status==1) SendMsg();
if(t_status==2)
SendAck();
}
/*------------------------------
Receiver
Task
-------------------------------*/
if
(receiver_timer==0){
receiver_timer = receiver_ovfl; //reload timer
receivedByte=PIND; //read byte at receiver
if(r_status==0) WaitForInit();
if(r_status==1) WaitForAck();
if(r_status==2) ReceiveMessage();
}
}
}
/*---------------------End
Main()---------------------------*/
/*-------------------------------------------------------------*/
//**********************************************************
//Transmitter TASK
--
//**********************************************************
//Send Ackknowledgement back
void SendAck(void){
int i=0;
DDRB=0xFF;
PORTB=0xFF; //TE =high
PORTA='A';
//send A
delay_ms(300);
PORTA='A';
//send A
delay_ms(300);
PORTA='A';
//send A
delay_ms(500);
PORTB=0x00;
DDRB=0x00;
t_status = t_nop;
receivedmsg_index=0;
//reset message:
for(i=0; i<max_msg_size; i++){
receivedmessage[i]='\0';
}
r_status = r_receive_message;
if(!compose){
lcd_clear();
lcd_putsf("Receiving...");
}
}
//Try to initialize sending
void TrySend(void){
//if not receiving
message, send X
if
(!receivingmsg){
lcd_clear();
DDRB=0xFF;
PORTB=0xFF;
PORTA='X';
delay_ms(300);
PORTA='X';
delay_ms(300);
PORTA='X';
delay_ms(500);
PORTB=0x00;
DDRB=0x00;
//initialize next
state var
sendingmsg=1;
receivingmsg=0;
r_status =
r_wait_for_ack; //change receiver
status to "wait for ack"
ACK_timer =
ACK_ovfl; //start Ack expire
timer
t_status = t_nop;
//transmitter == do nothing
}
//else don't do
anything until receiving ended
else {
t_status =
t_try_send;
trysend_timer--;
//trysend expire
if (trysend_timer == 0){
lcd_clear();
lcd_putsf("trysend timeout");
delay_ms(2000);
Reset();
}
}
}
void SendMsg(void){
DDRB=0xFF;
PORTB=0xFF; //TE =high
//sending message
here
if( (sendmsg_index
< max_msg_size-1) && (sendmessage[sendmsg_index] != 'T') ){
PORTA =
sendmessage[sendmsg_index];
sendmsg_index++;
delay_ms(300);
t_status=t_send_message;
}
//done sending
else {
//send
terminating char 'T'
PORTA =
sendmessage[sendmsg_index];
sendmsg_index++;
delay_ms(300);
//Done sending, reset
PORTB=0x00; //TE= off;
DDRB=0x00;
//Initialize next
state variables
sendmsg_index=0;
sendingmsg = 0;
lcd_clear();
lcd_gotoxy(0,0);
lcd_putsf("successful!");
t_status=t_nop;
delay_ms(2000);
Reset();
}
}
/*-------------------------------------------------------------*/
//**********************************************************
//Task Receiver --
//Wait for X from the other end to initialize
void WaitForInit(void){
//don't start
unless not sending msg, and not reading, or msg read at least once
if (!sendingmsg
&& !reading ) {
if (receivedByte
== 'X'){
delay_ms(300);
//initialize
nextstate var
receivingmsg=1;
sendingmsg=0;
r_status =
r_receive_message;
t_status =
t_send_ack;
if(!compose){
lcd_clear();
lcd_putsf("GOTX");
}
}
}
}
//Wait for Ack
void WaitForAck(void){
ACK_timer--;
//Check to see if
Ack is received
if (receivedByte ==
'A'){
delay_ms(300);
r_status = r_nop; //receiver == do nothing
t_status =
t_send_message; //transmitter == send
message
lcd_clear();
lcd_putsf("gotACK");
//Initialize next
state variables
sendingmsg=1; //sending msg
next
receivingmsg=0; //turn receiving
message off
ACK_timer =
-1; //turn off Ack expire timer
sendmsg_index=0; //initialize variable
//lcd_puts(sendmessage);
}
//If ACK not
received, and ack timer expires
else if (ACK_timer
==0){
//OUTPUT ERR and
ABORT
lcd_clear();
lcd_putsf("TIMEOUT!");
DDRB=0xFF;
PORTB=0xFF;
PORTA='Z';
delay_ms(500);
PORTB=0x00;
DDRB=0x00;
delay_ms(2000);
Reset();
}
}
//Receive message
void ReceiveMessage(void){
PORTB=0x00;
DDRB=0x00;
timeout--;
// lcd_putchar(receivedByte);
// delay_ms(300);
if (timeout == 0){
lcd_clear();
lcd_putsf("connect timeout\n");
lcd_putsf("resetting...");
delay_ms(2000);
Reset();
}
//preventing from
receiving ACk of own transmitter
else if (
(receivedByte=='A') || (receivedByte=='X')) {
//do nothing
delay_ms(100);
}
//store message
else if(
(receivedmsg_index < max_msg_size) && (receivedByte!='T') &&
(receivedByte!='A') && (receivedByte!='X') ){
timeout =
timeout_ovfl; //reset timeout expire
timer
receivedmessage[receivedmsg_index] = receivedByte;
receivedmsg_index++;
delay_ms(300);
}
//Done receiving
else {
//Initialize
nextstate var
readytoread=1;
receivedmsg_index=0;
receivingmsg = 0;
r_status =
r_wait_for_init;
}
}
/*-------------------------------------------------------------*/
/*-------------------------------------------------------------*/
//**********************************************************
//Task KeyCommand
-- keypad detection state machine
void KeyCommand(void){
//reset
sendmsg_index =0;
receivedmsg_index
=0;
butnum=99;
KeyPad();
keypadstate=release_state;
}
//STATES STARTS HERE//
//Release
void Release(){
if (butnum==99){
KeyPad();
//goto Release
State
keypadstate=release_state;
}
else{
maybe=butnum;
KeyPad();
keypadstate=debounce_state;
//goto Debounce
State
}
}
//Debounce
void Debounce(){
if
(butnum==maybe){
/////////////echo
keypad//
// printf("%d\r\n",butnum);
keypadstate=detectterm_state;
//goto DetectTerm State
}
else{
KeyPad();
keypadstate=release_state;
//goto Release
State
}
}
//DetectTerm
void DetectTerm(){
//check for term type
//go into compose
mode
if ( (butnum == 1)
&& (!compose) ){
//ready for
compose
lcd_clear();
lcd_x=0;
lcd_y=0;
compose=1;
reading=0;
}
//read message
else if (
(butnum==0) && (!compose) ) {
lcd_clear();
reading=1;
compose=0;
readatleastonce=1;
if (readytoread){
lcd_puts(receivedmessage);
}
else {
lcd_clear();
lcd_putsf("no msgs");
lcd_gotoxy(0,1);
lcd_putsf("press 'Clr' to exit");
}
}
else if ( (butnum==
termReset) ){
Reset();
}
//send message
else if ( (butnum
== termSend) && (compose) ){
//REQUEST SEND
lcd_clear();
lcd_gotoxy(0,0);
lcd_putsf("Message saved. ");
lcd_gotoxy(0,1);
lcd_putsf("Connecting.. ");
lcd_gotoxy(0,2);
lcd_putsf("Please wait... ");
//
sendmessage[sendmsg_index] = 'T'; //end
of msg
sendmsg_index++;
keypadEnable=0; //turn off
keypad
t_status = t_try_send;
}
//otherwise
else if (compose)
{
//checks to see
if message exceeds max allowable size
if (sendmsg_index
< max_msg_size - 1 ){
//echo to LCD
if(lcd_x == 20){
lcd_x==0;
lcd_y++;
}
if(butnum == termSpace){
lcd_putchar(' ');
lcd_x++;
sendmessage[sendmsg_index]=' ';
sendmsg_index++;
}
else {
lcd_putchar( keymap[butnum]);
lcd_x++;
//stores in message
sendmessage[sendmsg_index]=keymap[butnum];
sendmsg_index++;
}
} else {
//notify msg
exceed max size
//output to
lcd
lcd_clear();
lcd_putsf("msg exceeds max,
...send?");
lcd_gotoxy(0,1);
lcd_putsf("('Send'=send,
'Clr'=clr)");
}
}
//for checking
still pressed
lastnum = butnum;
KeyPad();
//goto
StillPressed State
keypadstate=stillpressed_state;
}
//StillPressed
void StillPressed(){
if (butnum ==
lastnum){
KeyPad();
keypadstate=stillpressed_state;
//goto
StillPressed State
}
else{
KeyPad();
keypadstate=debouncerelease_state;
//goto
DebounceRelease State
}
}
void DebounceRelease(void){
if (butnum ==
lastnum){
KeyPad();
keypadstate=stillpressed_state;
//goto
StillPressed State
}
else{
KeyPad();
keypadstate=release_state;
//goto to Release
State
}
}
//**********************************************************
//KeyPad -- KeyPad
Scanning
void KeyPad(void){
//get upper
nibble
DDRB= 0x0f;
PORTB = 0xf0;
delay_us(5);
key = PINB;
//get lower nibble
DDRB = 0xf0;
PORTB = 0x07; //only want
to read in the lower 3 bits
delay_us(5);
key = key | PINB;
key = key | 0x08;
//find matching keycode in keytbl
if (key != 0xff){
for (butnum=0; butnum<maxkeys; butnum++){
if (keytbl[butnum]==key)
break;
}
if (butnum==maxkeys) butnum=99; //99 = not pressed or not
matched
}
else butnum=99; //99
= not pressed or not matched
}
/////////////////////////////////////
//Reset
void Reset(void){
//reset lcd
lcd_clear(); //clear it
lcd_x=0;
lcd_y=0;
//Reinitialize
Screen
lcd_gotoxy(0,0);
lcd_putsf("Hello");
lcd_gotoxy(0,1);
lcd_putsf("please press: ");
lcd_gotoxy(0,2);
lcd_putsf("'a'=read,");
lcd_gotoxy(0,3);
lcd_putsf("'b'=compose");
lcd_gotoxy(0,0);
//reset
send/receive message var
sendmsg_index =
0;
sendingmsg = 0;
receivingmsg = 0;
receivedmsg_index =
0;
compose = 0;
reading = 0;
//resets keypad
keypadEnable=1;
keypadstate=keycommand_state;
//detect keypad again
butnum = 99;
//reset expire
timer
ACK_timer = -1;
trysend_timer =
trysend_ovfl;
timeout =
timeout_ovfl;
//reset t/r status
var
t_status = t_nop;
r_status =
r_wait_for_init;
}