/* * Intergalactical Positioning System (IPS) * Alfa 2 team * */ /* Includes */ #include #include __USING_SYS /* Definitions */ const unsigned char SELF = %SELF%; const unsigned int PROPORCAO = 10; const unsigned int ACK_TIMEOUT = 2 * PROPORCAO; const unsigned int FAIR_TIMEOUT = 10 * PROPORCAO; /* Protocol definitions */ const unsigned char DATA_PROTOCOL = 0xFF; const unsigned char CONTROL_PROTOCOL = 0xFE; const unsigned char KLINGOM_PROTOCOL = 0xFD; /* LEDs definitions */ const char RCVD_MASK = 0x01; const char SENT_MASK = 0x04; const char DETECTED_MASK = 0x02; /* PDU structure */ typedef struct PDU { unsigned short beacon_rssi[4]; unsigned short target_rssi; unsigned int pdu_type; unsigned char source; unsigned int serial; }; /* Enumerations */ enum States { WAITING_ACK, WAITING_PREV, WAITING_SEND }; unsigned enum Pdu_types { NIL, DATA, ACK, RETRANS }; /* Variables */ int mask; int state; int status; int ack_timer; int fair_timer; unsigned char * prev; unsigned char * next; unsigned char * addr; unsigned char * prot; PDU * pdu; PDU * pdu_rcvd; NIC * nic; /* Change current state to new_state */ void switch_to_state(int new_state) { state = new_state; } void blink(int led_mask) { mask = mask ^ led_mask; CPU::out8(Machine::IO::PORTA, mask); } void send(unsigned int type, const unsigned char prot, unsigned char * addr) { pdu->pdu_type = type; nic->send(*addr, prot, pdu, sizeof(PDU)); blink(SENT_MASK); if (type == DATA) { for (int i = 0; i < 4; i++) pdu->beacon_rssi[i] = 0; pdu->target_rssi = 0; } } void receive() { status = nic->receive(addr, prot, pdu_rcvd, NIC::MTU); blink(RCVD_MASK); *addr = pdu_rcvd->source; if(status != 0) { if (*prot == DATA_PROTOCOL || *prot == CONTROL_PROTOCOL) pdu->beacon_rssi[*addr] = nic->statistics().last_rssi; else if (*prot == KLINGOM_PROTOCOL) { pdu->target_rssi = nic->statistics().last_rssi; blink(DETECTED_MASK); } } } void clear_rcvd() { pdu_rcvd->pdu_type = NIL; pdu_rcvd->source = SELF; } int main() { /* Alloc some memory to structs and objects */ pdu = (PDU *) malloc(sizeof(PDU)); pdu_rcvd = (PDU *) malloc(sizeof(PDU)); nic = new NIC(); /* AVR compiler's bug, needs a malloc in chars!! */ addr = (unsigned char *) malloc(sizeof(char)); prot = (unsigned char *) malloc(sizeof(char)); prev = (unsigned char *) malloc(sizeof(char)); next = (unsigned char *) malloc(sizeof(char)); /* Set previous and next beacons */ *prev = (unsigned char) (SELF + 3) % 4; *next = (unsigned char) (SELF + 1) % 4; /* Set Source */ pdu->source = SELF; /* All rssi's start with zero */ pdu->target_rssi = 0; for(int i = 0; i < 4; i++) pdu->beacon_rssi[i] = 0x0000; /* My rssi is 0xFFFF */ pdu->beacon_rssi[SELF] = 0xFFFF; // doesn't make any difference... pdu->serial = 0; /* Init some variables */ mask = 0x00; ack_timer = 0; fair_timer = 0; /* Set direction to output */ CPU::out8(Machine::IO::DDRA, 0xff); /* Select my initial state */ if(SELF != 0) switch_to_state(WAITING_PREV); else { /* First packet... Starting IPS :-) */ send(DATA, DATA_PROTOCOL, next); switch_to_state(WAITING_ACK); } /* Infinite loop */ while(true) { /* Receives a packet */ clear_rcvd(); receive(); switch (state) { case WAITING_ACK: if (status) ack_timer++; else ack_timer += PROPORCAO; if(pdu_rcvd->pdu_type == ACK && *addr == *next) { switch_to_state(WAITING_PREV); ack_timer = 0; } else if(pdu_rcvd->pdu_type == DATA && *addr == *prev) { pdu->serial = pdu_rcvd->serial + 1; switch_to_state(WAITING_SEND); ack_timer = 0; } else if(pdu_rcvd->pdu_type == RETRANS && *addr == *prev) send(ACK, CONTROL_PROTOCOL, prev); /* Ack not received, it needs a retransmission */ if(ack_timer >= ACK_TIMEOUT) { send(RETRANS, CONTROL_PROTOCOL, next); ack_timer = 0; } break; case WAITING_PREV: if((pdu_rcvd->pdu_type == DATA || pdu_rcvd->pdu_type == RETRANS) && *addr == *prev) { send(ACK, CONTROL_PROTOCOL, prev); if (pdu_rcvd->serial >= pdu->serial) { pdu->serial = pdu_rcvd->serial + 1; switch_to_state(WAITING_SEND); } } break; case WAITING_SEND: if(status) fair_timer++; else fair_timer += PROPORCAO; if(pdu_rcvd->pdu_type == RETRANS && *addr == *prev) send(ACK, CONTROL_PROTOCOL, prev); if(fair_timer >= FAIR_TIMEOUT) { send(DATA, DATA_PROTOCOL, next); switch_to_state(WAITING_ACK); fair_timer = 0; } break; } } }