/* * Intergalactical Positioning System (IPS) * Alfa 2 team * */ /* Includes */ #include #include __USING_SYS /* SELF number */ const unsigned char SELF = 0; /* Timeout times */ const unsigned int RATIO = 10; const unsigned int ACK_TIMEOUT = 2 * RATIO; const unsigned int FAIR_TIMEOUT = 10 * RATIO; /* Protocol numbers */ const unsigned char DATA_PROTOCOL = 0xFF; const unsigned char CONTROL_PROTOCOL = 0xFE; const unsigned char KLINGOM_PROTOCOL = 0xFD; /* LEDs */ const char RCVD_MASK = 0x01; const char DETECTED_MASK = 0x02; const char SENT_MASK = 0x04; /* PDU structure */ typedef struct PDU { unsigned int beacon_rssi[4]; unsigned int target_rssi; unsigned int pdu_type; unsigned int source; unsigned int serial; }; enum States { WAITING_ACK, WAITING_PREV, WAITING_SEND }; unsigned enum Pdu_types { NIL, DATA, ACK, RETRANS }; int actual_mask; int state; int status; int timer; unsigned int previous; unsigned int next; unsigned char * prot; PDU * pdu; PDU * pdu_rcvd; NIC * nic; void switch_to_state(int new_state) { state = new_state; timer = 0; } void blink(int led_mask) { actual_mask = actual_mask ^ led_mask; CPU::out8(Machine::IO::PORTA, actual_mask); } void send(unsigned int type, const unsigned char prot, unsigned int dest) { pdu->pdu_type = type; nic->send(dest, prot, pdu, sizeof(PDU)); blink(SENT_MASK); if (type == DATA) { for (int i = 0; i < 4; i++) pdu->beacon_rssi[i] = 0; pdu->beacon_rssi[SELF] = 0xFFFF; pdu->target_rssi = 0; } } void receive() { unsigned char source_mac; status = nic->receive(&source_mac, prot, pdu_rcvd, NIC::MTU); blink(RCVD_MASK); if(status == 0) { timer += RATIO; pdu_rcvd->pdu_type = NIL; } else { timer++; if (*prot == DATA_PROTOCOL || *prot == CONTROL_PROTOCOL) pdu->beacon_rssi[pdu_rcvd->source] = nic->statistics().last_rssi; else if (*prot == KLINGOM_PROTOCOL) { pdu->target_rssi = nic->statistics().last_rssi; blink(DETECTED_MASK); } } } int main() { pdu_rcvd = (PDU *) malloc(sizeof(PDU)); // buffer for the received pdu nic = new NIC(); // radio interface /* LEDs initial state */ CPU::out8(Machine::IO::DDRA, 0xff); actual_mask = 0x00; /* AVR compiler's bug, needs a malloc in chars!! */ prot = (unsigned char *) malloc(sizeof(char)); /* Set previous and next beacons numbers */ previous = (SELF + 3) % 4; next = (SELF + 1) % 4; /* init PDU */ pdu = (PDU *) malloc(sizeof(PDU)); pdu->target_rssi = 0; for(int i = 0; i < 4; i++) pdu->beacon_rssi[i] = 0x0000; pdu->beacon_rssi[SELF] = 0xFFFF; // for source identification pdu->serial = 0; pdu->source = SELF; /* STATE MACHINE */ /* Initial state selection */ if(SELF != 0) switch_to_state(WAITING_PREV); else { /* First packet... Starting IPS :-) */ send(DATA, DATA_PROTOCOL, next); switch_to_state(WAITING_ACK); } while(true) { receive(); switch (state) { case WAITING_ACK: if(pdu_rcvd->pdu_type == ACK && pdu_rcvd->source == next) switch_to_state(WAITING_PREV); else if((pdu_rcvd->pdu_type == DATA || pdu_rcvd->pdu_type == RETRANS) && pdu_rcvd->source == previous) { send(ACK, CONTROL_PROTOCOL, previous); /* must check serial number because pdu_rcvd may be in the next round. this fact happens when many RETRANS/ACK packets are lost */ if(pdu_rcvd->serial >= pdu->serial) { pdu->serial = pdu_rcvd->serial + 1; switch_to_state(WAITING_SEND); } } if (timer >= ACK_TIMEOUT) { send(RETRANS, CONTROL_PROTOCOL, next); /* just to restart the timer (in fact its a state transition) */ switch_to_state(WAITING_ACK); } break; case WAITING_PREV: if((pdu_rcvd->pdu_type == DATA || pdu_rcvd->pdu_type == RETRANS) && pdu_rcvd->source == previous) { send(ACK, CONTROL_PROTOCOL, previous); /* must check serial number because pdu_rcvd may be in the previous round. this fact happens when many RETRANS/ACK packets are lost */ if (pdu_rcvd->serial >= pdu->serial) { pdu->serial = pdu_rcvd->serial + 1; switch_to_state(WAITING_SEND); } } break; case WAITING_SEND: if(pdu_rcvd->pdu_type == RETRANS && pdu_rcvd->source == previous) send(ACK, CONTROL_PROTOCOL, previous); if (timer >= FAIR_TIMEOUT) { send(DATA, DATA_PROTOCOL, next); switch_to_state(WAITING_ACK); } } } }