/* ~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~= * ADAPTATION DU PROTOCOLE Gnutella POUR CAPTEURS MSP430-CC2500 * ~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~=~= * Utilise mrfi et bsp * * code fortement inspiré des travaux de Thomas Watteyne * https://cnx.org/contents/NUQaoek8@10.6:f0_AL5uL@3/4-2-Simple-Tx-Rx * * Gnutella original * https://courses.cs.washington.edu/courses/cse522/05au/gnutella_protocol_0.4.pdf * */ #include //#include #include #include uint8_t *Flash_Addr = (uint8_t *)0x10F0; static uint8_t Mac_Address[MRFI_ADDR_SIZE]; //=================================================================== // MACROS UTILES //=================================================================== #define TURN_OFF_LEDS() P1OUT &= ~0x03 /* turn off LEDs */ #define TURN_OFF_RED_LED() P1OUT &= ~0x01 #define TURN_OFF_GREEN_LED() P1OUT &= ~0x02 #define TURN_ON_LEDS() P1OUT |= 0x03 #define TURN_ON_RED_LED() P1OUT |= 0x01 #define TURN_ON_GREEN_LED() P1OUT |= 0x02 #define WAIT_() for (uint16_t i = 0; i < 65535; i++){__no_operation();} //=================================================================== // CONSTANTES UTILES //=================================================================== // byte index of 'total length' field #define TOTAL_LENGTH_BYTE 0 // starting byte index of 'source address' field #define SRC_ADDR_BYTE_START (TOTAL_LENGTH_BYTE+1) // ending byte index of 'source address' field #define SRC_ADDR_BYTE_END (SRC_ADDR_BYTE_START+MRFI_ADDR_SIZE-1) // starting byte index of 'destination address' field #define DST_ADDR_BYTE_START (SRC_ADDR_BYTE_END+1) // ending byte index of 'destination address' field #define DST_ADDR_BYTE_END (DST_ADDR_BYTE_START+MRFI_ADDR_SIZE-1) // byte index of 'flag' field #define FLAG_BYTE (DST_ADDR_BYTE_END+1) // byte index of 'time to live' field #define TTL_BYTE (FLAG_BYTE+1) // byte index of 'hops' field #define HOPS_BYTE (TTL_BYTE+1) // byte index of 'descriptor id' field #define SEQUENCE_ID_BYTE (HOPS_BYTE+1) // starting byte index of 'payload' field #define PAYLOAD_BYTE_START (SEQUENCE_ID_BYTE+1) // ending byte index of 'payload' field #define PAYLOAD_BYTE_END 28 #define MAX_PEERS 8 #define PING 0 // flag ping #define PONG 1 // flag pong #define QUERY 2 // flag query #define QUERY_HIT 3 // flag query hit // ttl #define TTL 3 // history size #define HISTORY_SIZE 20 #define DELAY 50 //=================================================================== // VARIABLES GLOBALES //=================================================================== // table des adresses uint8_t Peers[MAX_PEERS + 1][4] = {{0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}, {0, 0, 0, 0}}; //indice du peer à qui le packet doit être envoyé uint8_t peer_index = 0; // packet qui contient la data pour le query mrfiPacket_t packetSearch; // debut du bit output uint8_t index_output = 13; // valeur à changer (ou pas) à chaque fois qu'on flash un capteur, pour simuler une donnée uint8_t myData[] = "DAAAAAAAAAAAAAAA"; // historique des sequence ID messages recus uint8_t history_id[HISTORY_SIZE]; // historique des adresses sources des messages recus uint8_t* history_addr[HISTORY_SIZE]; // indice de l'id d'historique en cours (historique = tableau cyclique) uint8_t history_index = 0; // sequence id uint8_t sequence_id = 1; //=================================================================== // FONCTIONS UTILES //=================================================================== /** Actually retrieve Device unique identifier written on Flash **/ void retrieve_mac_address(){ uint8_t *dst = Mac_Address; uint8_t *src = Flash_Addr; uint8_t len = sizeof(Mac_Address); while(len--) { *dst++ = *src++; // Back up default MAC address data in RAM } } /** Affiche une chaîne de caractère sur le port série @param string : la chaîne à afficher @param length : la longueur de la chaîne **/ void TXString(char *string, int length) { int pointer; for (pointer = 0; pointer < length; pointer++) { UCA0TXBUF = string[pointer]; while (!(IFG2 & UCA0TXIFG)) ; // USCI_A0 TX buffer ready? } } /** Affiche un entier (uint8_t) sur le port série @param nbr : l'entier à afficher **/ void TXInt(uint8_t nbr) { UCA0TXBUF = nbr; while (!(IFG2 & UCA0TXIFG)) ; // USCI_A0 TX buffer ready? } /** Compare deux pointeurs de uint8_t. retourne 1 si ils sont égaux, 0 sinon. peut être utilisé pour comparer des adresses mac par exemple @param addr1 : la première adresse @param addr2 : la 2e adresse **/ uint8_t compare(uint8_t* addr1, uint8_t* addr2){ uint8_t len = 4; for (uint8_t i = 0; i < len; i++) { if(addr1[i] != addr2[i]){ return 0; } } return 1; } /** * Affiche la table des adresses du capteur (Peers) **/ void print_addr_table() { for (uint8_t i = 0; i <= MAX_PEERS; i++) { TXString((char*){" "},1); TXString((char*)Peers[i], 4); TXString((char*){"\n\r"},2); } } /** * retourne true si l'addr passé en param existe dans la table des adresses connues (Peers) **/ uint8_t addr_exists_in_table(uint8_t *addr) { for (uint8_t i = 0; i <= MAX_PEERS; i++) { if(compare(addr, Peers[i])) return 1; } return 0; } /** * Ajoute une adresse dans la table des adresses **/ void add_addr_in_table(uint8_t *addr) { peer_index++; //print_peer_index(); debug for (uint8_t i = 0; i < MRFI_ADDR_SIZE; i++) { Peers[peer_index][i] = addr[i]; } } /** * Met à jour l'historique des adresses recus */ void update_history(uint8_t *addr, uint8_t seq_id){ // mise a jour de l historique history_id[history_index] = seq_id; history_addr[history_index] = addr; history_index = (history_index+1)%HISTORY_SIZE; } /** * retourne 1 si le message est present dans l historique, sinon 0 * pour avoir un ID unique, on concatene l adresse source avec le numero de sequence recu **/ uint8_t message_in_history(uint8_t *addr, uint8_t id) { for (uint8_t i = 0; i < HISTORY_SIZE; i++) if(compare(addr, history_addr[i]) && (id == history_id[i])) return 1; return 0; } /** * Fait clignoter les leds. **/ void blink_init(void) { uint16_t i, j; TURN_OFF_LEDS(); for (j = 0; j < 5; j++) { /* blink LEDs alternatively */ P1OUT ^= 0x01; for (i = 0; i < 65535; i++) { __no_operation(); } P1OUT ^= 0x02; for (i = 0; i < 65535; i++) { __no_operation(); } } TURN_OFF_LEDS(); } /** * Permet au capteur d'attendre un temps aléatoire **/ void wait_random() { uint8_t nb = rand()%(MAX_PEERS*4); for (uint8_t j = 0; j < nb; j++) { for (uint8_t k = 0; k < 3; k++) { WAIT_(); } } } /** * permet de préparer un paquet pour l'envoi **/ void prepare_packet(mrfiPacket_t *packet, uint8_t flag, uint8_t *dest_addr) { // la taille du packet mrfi packet->frame[0] = PAYLOAD_BYTE_END; //mon adresse comme adresse source for ( uint8_t i = SRC_ADDR_BYTE_START; i <= SRC_ADDR_BYTE_END; i++) { packet->frame[i] = Mac_Address[i-SRC_ADDR_BYTE_START]; } // si il y a une adresse dest, la mettre dans le packet if(dest_addr != NULL) { for ( uint8_t i = DST_ADDR_BYTE_START; i <= DST_ADDR_BYTE_END; i++) { packet->frame[i] = dest_addr[i-(MRFI_ADDR_SIZE + 1)]; } } // le FLAG packet->frame[FLAG_BYTE] = flag; // le ttl packet->frame[TTL_BYTE] = TTL; // le hop packet->frame[HOPS_BYTE] = 0; // sequence id packet->frame[SEQUENCE_ID_BYTE] = sequence_id; sequence_id++; if(sequence_id >= 255) { sequence_id = 0; } //mise à jour de l'historique des messages //update_history(Mac_Address, sequence_id); } //=================================================================== // MAIN //=================================================================== int main(void) { BSP_Init(); blink_init(); retrieve_mac_address(); //Initilisation du port série pour l'entrée sortie P3SEL |= 0x30; // P3.4,5 = USCI_A0 TXD/RXD UCA0CTL1 = UCSSEL_2; // SMCLK UCA0BR0 = 0x41; // 9600 from 8Mhz UCA0BR1 = 0x3; UCA0MCTL = UCBRS_2; UCA0CTL1 &= ~UCSWRST; // Initialize USCI state machine //Interuption pour les entrées sur le terminal // A activer pour mettre des inputs si besoin IE2 |= UCA0RXIE; // Enable USCI_A0 RX interrupt // initialisation de la payload du packet for (uint8_t i = PAYLOAD_BYTE_START; i <= PAYLOAD_BYTE_END; i++) { packetSearch.frame[i] = ' '; } // notre adresse mac dans la table d'adresses for (uint8_t i = 0; i < MRFI_ADDR_SIZE; i++) { Peers[0][i] = Mac_Address[i]; } //seed int seed = Mac_Address[0]; seed = (seed >> 8) | Mac_Address[1]; srand(seed); P1DIR &= ~0x04; P1REN |= 0x04; P1OUT |= 0x04; P1IE |= 0x04; MRFI_Init(); MRFI_SetLogicalChannel(2); // mrfiSpiWriteReg(CHANNR,0x10); MRFI_WakeUp(); MRFI_RxOn(); __bis_SR_register(GIE); return 0; } //=================================================================== // RECEPTION D'UN PAQUET //=================================================================== void MRFI_RxCompleteISR() { //print de mon addresse TXString((char*){"MY ADDR : "}, 10); TXString((char*)Mac_Address, 4); TXString((char*){"\n\r"}, 2); mrfiPacket_t packet; uint8_t flag; uint8_t ttl; uint8_t hops; uint8_t _sequence_id; // recup du packet; MRFI_Receive(&packet); uint8_t src_addr[MRFI_ADDR_SIZE]; // recup de l'adresse source du packet for (uint8_t i = SRC_ADDR_BYTE_START; i <= SRC_ADDR_BYTE_END; i++) { src_addr[i-SRC_ADDR_BYTE_START] = packet.frame[i]; } //recup du flag, ttl, hops, seq id flag = packet.frame[FLAG_BYTE]; ttl = packet.frame[TTL_BYTE]; hops = packet.frame[HOPS_BYTE]; _sequence_id = packet.frame[SEQUENCE_ID_BYTE]; ttl--; hops++; if(ttl > 0 && !message_in_history(src_addr, _sequence_id)) { // mise à jour de l'historique des messages reçus //update_history(src_addr, _sequence_id); // differents traitement selon du flag if(flag == PING){ /* si on recoit un ping, on regarde si l'adresse source du packet est dans notre table - si oui, on ne fait rien - si il n'y a plus de place dans la table, on ne fait rien - sinon , (on broadcast le message et) on save l'addr source dans la table et on envoi un pong à destination de l'emetteur */ if(!addr_exists_in_table(src_addr) && peer_index < MAX_PEERS) { TXString((char*){"PING\n\r"}, 6); // ajout de l'adresse source du packet à la table des adresses add_addr_in_table(src_addr); //print de ma table d'addrs print_addr_table(); mrfiPacket_t packet_to_send; prepare_packet(&packet_to_send, PONG, src_addr); //envoi du pong wait_random(); MRFI_Transmit(&packet_to_send, MRFI_TX_TYPE_FORCED); //forward du ping recu TXString((char*){"FORWARD\n\r"}, 9); wait_random(); packet.frame[TTL_BYTE] = ttl; MRFI_Transmit(&packet, MRFI_TX_TYPE_FORCED); } else if (addr_exists_in_table(src_addr)) { TXString((char*){"ADDRESS EXISTS\n\r"}, 16); TXString((char*){"DROP\n\r"}, 6); } else { TXString((char*){"NOT ENOUGH SPACE IN TABLE\n\r"}, 27); TXString((char*){"DROP\n\r"}, 6); } } else if (flag == PONG) { /* Si l'addr dest du pong nous est destiné, on enregistre l'addr source dans notre table sinon on fait rien (on forward juste) */ TURN_ON_GREEN_LED(); uint8_t dest_addr[MRFI_ADDR_SIZE]; for ( uint8_t i = DST_ADDR_BYTE_START; i <= DST_ADDR_BYTE_END; i++) { dest_addr[i-DST_ADDR_BYTE_START] = packet.frame[i]; } if(compare(dest_addr, Mac_Address) && !addr_exists_in_table(src_addr) && peer_index < MAX_PEERS) { TXString((char*){"PONG\n\r"}, 6); add_addr_in_table(src_addr); //print de ma table d'addrs print_addr_table(); } else { //forward du pong recu TXString((char*){"FORWARD\n\r"}, 9); wait_random(); packet.frame[TTL_BYTE] = ttl; MRFI_Transmit(&packet, MRFI_TX_TYPE_FORCED); } TURN_OFF_GREEN_LED(); } else if (flag == QUERY) { /* Si on a la ressource de la payload, répondre à celui qui envoi avec un QUERY_HIT /!\ l'addr source doit être connue du capteur Si on a pas la ressource on forward */ mrfiPacket_t packet; MRFI_Receive(&packet); uint8_t data[] = {" "}; // recup de la payload for (uint8_t i = PAYLOAD_BYTE_START; i <= PAYLOAD_BYTE_END; i++) { data[i-PAYLOAD_BYTE_START] = packet.frame[i]; } if(addr_exists_in_table(src_addr) && compare(data, myData)) { // TODO changer le nom de cette fct de comparaison // j'ai la data, je send un query hit TXString((char*){"QUERY_HIT\n\r"}, 11); prepare_packet(&packet, QUERY_HIT, src_addr); //envoi wait_random(); MRFI_Transmit(&packet, MRFI_TX_TYPE_FORCED); } else if(!addr_exists_in_table(src_addr)) { TXString((char*){"UNKNOWN\n\r"}, 9); TXString((char*){"DROP\n\r"}, 6); } else if(!compare(data, myData)) { TXString((char*){"NO DATA\n\r"}, 9); TXString((char*){"FORWARD\n\r"}, 9); //forward du query recu wait_random(); packet.frame[TTL_BYTE] = ttl; MRFI_Transmit(&packet, MRFI_TX_TYPE_FORCED); } } else if (flag == QUERY_HIT) { /* Si on est le destinataire du message, on affiche la payload sur minicom sinon on forward */ uint8_t dest_addr[MRFI_ADDR_SIZE]; for ( uint8_t i = DST_ADDR_BYTE_START; i <= DST_ADDR_BYTE_END; i++) { dest_addr[i-DST_ADDR_BYTE_START] = packet.frame[i]; } if(compare(dest_addr, Mac_Address)) { char output[] = {" \n\r"}; for (uint8_t i = PAYLOAD_BYTE_START; i <= PAYLOAD_BYTE_END; i++) { output[i-PAYLOAD_BYTE_START] = packet.frame[i]; } wait_random(); TXString((char*){"RECEIVED : "}, 11); TXString(output, sizeof(output)); } else { //forward du query recu TXString((char*){"FORWARD\n\r"}, 9); wait_random(); packet.frame[TTL_BYTE] = ttl; MRFI_Transmit(&packet, MRFI_TX_TYPE_FORCED); } } } else if(ttl <= 0){ TXString((char*){"TTL <= 0\n\r"}, 10); TXString((char*){"DROP\n\r"}, 6); } else if(message_in_history(src_addr, _sequence_id)){ TXString((char*){"MESSAGE ALREADY RECEIVED\n\r"}, 26); TXString((char*){"DROP\n\r"}, 6); } } //=================================================================== // APPUI SUR BOUTON //=================================================================== __attribute__((interrupt(PORT1_VECTOR))) void Port_1(void) { // envoi d'un packet soit en broadcast, soit à une adresse P1IFG &= ~0x04; mrfiPacket_t packet; packet.frame[0] = 8 + 20; //mon adresse comme adresse source for ( uint8_t i = SRC_ADDR_BYTE_START; i <= SRC_ADDR_BYTE_END; i++) { packet.frame[i] = Mac_Address[i-SRC_ADDR_BYTE_START]; } //specifier qu'on fait un ping packet.frame[FLAG_BYTE] = PING; //packet.frame[10] = 15; //TTL MRFI_Transmit(&packet, MRFI_TX_TYPE_FORCED); } //=================================================================== // SAISIE SUR MINICOM //=================================================================== __attribute__((interrupt(USCIAB0RX_VECTOR))) void USCI0RX_ISR(void) { /* TODO quand on appui sur entrée (\r) envoyer un paquet avec : - adresse source : Mac_adress - adresse destination : vide - FLAG : QUERY - TTL - HOPS - numéro de séquence - payload : le truc saisi */ char rx = UCA0RXBUF; uint8_t i; packetSearch.frame[index_output] = rx; index_output++; if (rx == '\r' || index_output == 29) { prepare_packet(&packetSearch, QUERY, NULL); TXString((char*){"\n\rQUERY\n\r"}, 9); MRFI_Transmit(&packetSearch, MRFI_TX_TYPE_FORCED); index_output = 13; for (i = PAYLOAD_BYTE_START; i <= PAYLOAD_BYTE_END; i++) { packetSearch.frame[i] = ' '; } } TXString(&rx, 1); }