App1_S5
/
APP4_IRQ
APP4 S5
radio.cpp
- Committer:
- Cheroukee
- Date:
- 2017-10-22
- Revision:
- 13:b44c1f678aff
- Parent:
- 12:e21604b50719
File content as of revision 13:b44c1f678aff:
/* * radio.cpp - Code de radio manchester - Jean-Philippe Fournier (fouj1807) - Jean-Pascal McGee (mcgj2701) */ #include "radio.h" #include "quick_queue.h" #include "mbed.h" #include "rtos.h" #include "crc.h" // Vitesse de sortie des message manchester #define MANCHESTER_SPEED_OUT 4 // Pins de reception et d'entree #define INPUT_RADIO p18 #define OUTPUT_RADIO p6 //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // Private API enumerations // Receiver states typedef enum { in_attente = 0, in_preambule, in_data } receive_state_t; // Emitter states typedef enum { out_preambule = 0, out_start, out_options, out_length, out_data, out_crc, out_end, out_idle } emitter_state_t; //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // Fonctions privee de l'API // Setup radio output void setup_radio_out(); // Setup radio input void setup_radio_in(); // Fonction periodique d'envoi de messages void radio_out(void const *args); // Fonction appellee lors de l'interruption sur la pin d'entree void radio_in(); // Fonction content la state machine de reception de trame bool receive_frame(byte read_byte); // Fonction de timeout de la reception de d ata manchester void stop_frame(void const *n); // Fonction du thread d'affichage dans le terminal void thread_putc(); // Fonction qui cree un message et le mets dans un message void add_new_message(); //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // TODO HOW WE DO THIS Mail<radio_message_t, MESSAGE_BUFFER_SIZE> out_mail; Mail<radio_message_t, MESSAGE_BUFFER_SIZE> in_mail; // Utilise pour les interruptions et la lecture de la valeur d'entree de la pin de reception InterruptIn input(INPUT_RADIO); // Pin de sortie de la radio, permet l'envoi de code binaire, dans ce cas, manchester DigitalOut output(OUTPUT_RADIO); // Definition des LED de debug de la radio #ifndef LED DigitalOut in_debug_led4(LED4); DigitalOut out_debug_led3(LED3); DigitalOut frame_out_end_led2(LED2); DigitalOut frame_in_end_led1(LED1); #endif // Thread d'output de debugging Thread thread; int start_speed = MANCHESTER_SPEED_OUT; byte current_state = in_attente; byte current_byte_progress = 0; // Timer d'evoi periodic de donnes vers la radio RtosTimer out_timer(radio_out, osTimerPeriodic, NULL); // Timer qui mesure le temps et cree un timer sur la reception de data, permet le timeout du // data qui arrive de la reception. Termine la reception manchester RtosTimer ticker_watch(stop_frame, osTimerOnce, NULL); // Char used by the debugging serial volatile int debug_char_output = 0; //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// // Setup radio input void setup_radio_in() { //thread.start(callback(thread_putc)); input.rise(&radio_in); input.fall(&radio_in); } // Setup radio output void setup_radio_out() { out_debug_led3 = 0; frame_out_end_led2 = 0; output = 0; //add_new_message(); wait(1); out_timer.start(start_speed); } void add_new_message(){ ////////////////////////////////////////////////////// // Creation d'un message et insertion dans le buffer radio_message_t* message = get_new_out_message(); if (message != NULL) { message->preambule = HEADER_DELIMITER; message->start = HEADER_START; message->options = HEADER_DELIMITER; message->length = 0x3; message->data[0] = 0xC0; message->data[1] = 0xFF; message->data[2] = 0xEE; // Ajouter calcul message->control = 0xCE; message->end = FOOTER_END; // On avance dans le buffer; new_out_message_ready(); } ////////////////////////////////////////////////////// } #define SET_VAL_BIT_MASK(val) next_value = 0x1 & val; #define SET_VAL_SHIFT(val, shift) SET_VAL_BIT_MASK(val >> (7 - shift)) #define CHECK_NEXT_STATE if (current_byte_progress > 7) \ { \ out_current_state++; \ current_byte_progress = 0; \ } // Fonction appellee periodiquement pour l'envoi du message courant void radio_out(void const *args) { static byte current_byte_progress = 0; static byte current_byte = 0; static byte out_current_state = out_preambule; static bool IsBitTransition = false; static byte next_value = 0; static radio_message_t* message = NULL; out_debug_led3 = !out_debug_led3; // Si on est a la fin du packet, on retourne au debut et on reenvoye les donnees if (out_current_state > out_idle) { // Message termine message = NULL; last_out_message_read(); frame_out_end_led2 = 0; // Reinitialisation des var de messages current_byte = 0; current_byte_progress = 0; out_current_state = out_preambule; out_timer.stop(); out_timer.start(start_speed); } if (message == NULL) { message = get_last_out_message(); } if (message != NULL) { if (!IsBitTransition) { // Dependant du state, on progresse dans l'envoi du message switch (out_current_state) { case out_preambule: // preambule { frame_out_end_led2 = 1; SET_VAL_SHIFT(message->preambule, current_byte_progress++); CHECK_NEXT_STATE break; } case out_start: // start { SET_VAL_SHIFT(message->start, current_byte_progress++); CHECK_NEXT_STATE break; } case out_options: // entete options { SET_VAL_SHIFT(message->options, current_byte_progress++); CHECK_NEXT_STATE break; } case out_length: // entete lenght { SET_VAL_SHIFT(message->length, current_byte_progress++); CHECK_NEXT_STATE break; } case out_data: // charge utile { SET_VAL_SHIFT(message->data[current_byte], current_byte_progress++) if (current_byte_progress > 7) { current_byte++; current_byte_progress = 0; if (current_byte >= message->length) { current_byte = 0; out_current_state++; } } break; } case out_crc: // controle { SET_VAL_SHIFT(message->control, current_byte_progress++); CHECK_NEXT_STATE break; } case out_end: // end { SET_VAL_SHIFT(message->end, current_byte_progress++); CHECK_NEXT_STATE break; } case out_idle: { /*out_debug_led3 = !out_debug_led3; message = NULL; last_out_message_read(); current_byte = 0; current_byte_progress = 0;*/ break; } } // Changement d'etat pour permettre de faire la bonne transition de valeur if (next_value != output && out_current_state <= out_idle) { output = !output; } } // Si on est pas dans une transitipon else if (out_current_state != out_idle + 1) { output = !output; if (out_current_state == out_idle) { out_current_state++; } } IsBitTransition = !IsBitTransition; } } // Fonction appellee lors de l'interruption sur la pin d'entree void radio_in() { // Timer utilise pour le calcul de la periode de l'horloge du code manchester static Timer timer; // Valeur de la demi periode static int half_period = 0; // Valeur de la periode de l'horloge static int calculated_period = 0; // static byte current_byte = 0; in_debug_led4 = !in_debug_led4; switch (current_state) { case in_attente: { frame_in_end_led1 = 0; if (input == 1) { timer.start(); current_state = in_preambule; current_byte_progress = 1; frame_in_end_led1 = 1; } break; } case in_preambule: { current_byte_progress++; calculated_period = timer.read_ms(); timer.reset(); if (current_byte_progress > 7) { half_period = calculated_period / 2; ticker_watch.start(calculated_period + half_period); current_byte_progress = 0; current_byte = 0; current_state = in_data; debug_char_output = calculated_period; // thread.signal_set(0x1); } break; } case in_data: { // Si ca fait plus longtemps que la periode usuelle de reception de donne // Cela veut dire que l'on doit recommencer la reception if(timer.read_ms() > calculated_period) { frame_in_end_led1 = 0; timer.stop(); timer.reset(); if (input == 1) { timer.start(); current_state = in_preambule; current_byte_progress = 1; } else { current_state = in_attente; current_byte_progress = 0; } } // Si le temps de la demi periode est passe, donc on a une donne reele else if (timer.read_ms() > half_period) { current_byte = (!input << (7 - current_byte_progress)) | current_byte; current_byte_progress++ ; ticker_watch.start(calculated_period + half_period); timer.reset(); if (current_byte_progress > 7) { debug_char_output = current_byte; if (receive_frame(current_byte)) { current_state = in_attente; } current_byte_progress = 0; current_byte = 0; } } break; } } } // Fonction content la state machine de reception de trame bool receive_frame(byte read_byte) { static radio_message_t* current_message; static byte receive_current_state = out_start; static int data_index = 0; if (current_message == NULL) { current_message = get_new_in_message(); receive_current_state = out_start; if (current_message == NULL){ return true; } } if (current_message != NULL) { switch (receive_current_state) { case out_start: { current_message->start = read_byte; receive_current_state++; break; } case out_options: { current_message->options = read_byte; receive_current_state++; break; } case out_length: { current_message->length = read_byte; receive_current_state++; break; } case out_data: { current_message->data[data_index++] = read_byte; if (data_index >= current_message->length) { data_index = 0; receive_current_state++; } break; } case out_crc: { current_message->control = read_byte; receive_current_state++; break; } case out_end: { current_message->end = read_byte; new_in_message_ready(); receive_current_state = out_start; current_message = NULL; return true; break; } } } return false; } // Fonction de timeout de la reception de data manchester void stop_frame(void const *n) { frame_in_end_led1 = 0; current_state = in_attente; current_byte_progress = 0; ticker_watch.stop(); } // Fonction du thread d'affichage dans le terminal /* void thread_putc() { while(true) { Thread::signal_wait(0x1); debug_output.printf("0x%c\n\r", debug_char_output); } }*/ //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// /* * Public API function */ /* * Inits the radio system and begins receiving manchester coded messages * Sends buffered messages */ void init_radio_system() { init_crc_module(); setup_radio_in(); setup_radio_out(); } bool send_message(char* buffer, int length) { ////////////////////////////////////////////////////// // Creation d'un message et insertion dans le buffer radio_message_t* message = get_new_out_message(); if (length <= MAX_MESSAGE_LENGTH && message != NULL) { message->preambule = HEADER_DELIMITER; message->start = HEADER_START; message->options = HEADER_DELIMITER; message->length = length; for (int i = 0; i < length; i++){ message->data[i] = buffer[i]; } // Ajouter calcul du CRC message->control = get_crc_value(message->data, message->length);//0xCE; message->end = FOOTER_END; // On avance dans le buffer; return new_out_message_ready(); } return false; ////////////////////////////////////////////////////// } bool get_message(radio_message_t* message) { radio_message_t* received_message; // Si un message a ete recu par la radio if((received_message = get_last_in_message()) != NULL) { // Si la valeur de CRC est valide par rapport a ce qui est calcule if (get_crc_value(received_message->data, received_message->length) == received_message->control) { message->preambule = received_message->preambule; message->start = received_message->start; message->options = received_message->options; message->length = received_message->length; // memcopy memcpy(message->data, received_message->data, received_message->length); message->control = received_message->control; message->end = received_message->end; last_in_message_read(); return true; } } return false; } //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////