APP4 S5

Dependencies:   mbed-rtos mbed

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers radio.cpp Source File

radio.cpp

00001 /*
00002 *   radio.cpp - Code de radio manchester - Jean-Philippe Fournier (fouj1807) - Jean-Pascal McGee (mcgj2701)
00003 */
00004 
00005 #include "radio.h"
00006 #include "quick_queue.h"
00007 
00008 #include "mbed.h"
00009 #include "rtos.h"
00010 
00011 #include "crc.h"
00012 // Vitesse de sortie des message manchester
00013 #define MANCHESTER_SPEED_OUT 4    
00014 
00015 // Pins de reception et d'entree
00016 #define INPUT_RADIO p18
00017 #define OUTPUT_RADIO p6
00018 
00019 ////////////////////////////////////////////////////////////////////////////
00020 ////////////////////////////////////////////////////////////////////////////
00021 ////////////////////////////////////////////////////////////////////////////
00022 ////////////////////////////////////////////////////////////////////////////
00023 
00024 // Private API enumerations
00025 // Receiver states
00026 typedef enum {
00027     in_attente = 0,
00028     in_preambule,
00029     in_data    
00030 } receive_state_t;
00031 
00032 // Emitter states
00033 typedef enum {
00034     out_preambule = 0,
00035     out_start,
00036     out_options,
00037     out_length,
00038     out_data,
00039     out_crc,
00040     out_end,
00041     out_idle
00042 } emitter_state_t;
00043 
00044 ////////////////////////////////////////////////////////////////////////////
00045 ////////////////////////////////////////////////////////////////////////////
00046 ////////////////////////////////////////////////////////////////////////////
00047 ////////////////////////////////////////////////////////////////////////////
00048 // Fonctions privee de l'API 
00049 
00050 // Setup radio output
00051 void setup_radio_out();
00052 // Setup radio input
00053 void setup_radio_in();
00054 // Fonction periodique d'envoi de messages
00055 void radio_out(void const *args);
00056 // Fonction appellee lors de l'interruption sur la pin d'entree
00057 void radio_in();
00058 // Fonction content la state machine de reception de trame
00059 bool receive_frame(byte read_byte);
00060 // Fonction de timeout de la reception de d ata manchester
00061 void stop_frame(void const *n);
00062 // Fonction du thread d'affichage dans le terminal
00063 void thread_putc();
00064 
00065 // Fonction qui cree un message et le mets dans un message
00066 void add_new_message();
00067 
00068 ////////////////////////////////////////////////////////////////////////////
00069 ////////////////////////////////////////////////////////////////////////////
00070 ////////////////////////////////////////////////////////////////////////////
00071 ////////////////////////////////////////////////////////////////////////////
00072 
00073 // TODO HOW WE DO THIS
00074 Mail<radio_message_t, MESSAGE_BUFFER_SIZE> out_mail;
00075 Mail<radio_message_t, MESSAGE_BUFFER_SIZE> in_mail;
00076 
00077 // Utilise pour les interruptions et la lecture de la valeur d'entree de la pin de reception
00078 InterruptIn input(INPUT_RADIO);
00079 // Pin de sortie de la radio, permet l'envoi de code binaire, dans ce cas, manchester
00080 DigitalOut output(OUTPUT_RADIO);
00081 
00082 // Definition des LED de debug de la radio
00083 #ifndef LED
00084 DigitalOut in_debug_led4(LED4);
00085 DigitalOut out_debug_led3(LED3);
00086 
00087 DigitalOut frame_out_end_led2(LED2);
00088 DigitalOut frame_in_end_led1(LED1);
00089 #endif
00090 
00091 // Thread d'output de debugging
00092 Thread thread;
00093 
00094 int start_speed = MANCHESTER_SPEED_OUT;
00095 
00096 byte current_state = in_attente;
00097 byte current_byte_progress = 0;
00098 
00099 // Timer d'evoi periodic de donnes vers la radio
00100 RtosTimer out_timer(radio_out, osTimerPeriodic, NULL);
00101 
00102 // Timer qui mesure le temps et cree un timer sur la reception de data, permet le timeout du
00103 // data qui arrive de la reception. Termine la reception manchester
00104 RtosTimer ticker_watch(stop_frame, osTimerOnce, NULL);
00105 
00106 // Char used by the debugging serial 
00107 volatile int debug_char_output = 0;
00108 
00109 ////////////////////////////////////////////////////////////////////////////
00110 ////////////////////////////////////////////////////////////////////////////
00111 ////////////////////////////////////////////////////////////////////////////
00112 ////////////////////////////////////////////////////////////////////////////
00113 
00114 // Setup radio input
00115 void setup_radio_in()
00116 {
00117     //thread.start(callback(thread_putc));
00118     
00119     input.rise(&radio_in);
00120     input.fall(&radio_in);       
00121 }
00122 
00123 // Setup radio output
00124 void setup_radio_out()
00125 {
00126     out_debug_led3 = 0;    
00127     frame_out_end_led2 = 0;
00128     output = 0;
00129     
00130     //add_new_message();
00131     
00132     wait(1);
00133     out_timer.start(start_speed);       
00134 }
00135 
00136 void add_new_message(){
00137 //////////////////////////////////////////////////////
00138     // Creation d'un message et insertion dans le buffer
00139     radio_message_t* message = get_new_out_message();
00140     if (message != NULL)
00141     {        
00142         message->preambule = HEADER_DELIMITER;
00143         message->start = HEADER_START;
00144         message->options = HEADER_DELIMITER;
00145         message->length = 0x3;
00146         
00147         message->data[0] = 0xC0;
00148         message->data[1] = 0xFF;    
00149         message->data[2] = 0xEE;    
00150         
00151         // Ajouter calcul
00152         message->control = 0xCE;
00153         
00154         message->end = FOOTER_END;
00155         // On avance dans le buffer;
00156         new_out_message_ready();
00157     }
00158     //////////////////////////////////////////////////////   
00159 }
00160 
00161 #define SET_VAL_BIT_MASK(val) next_value = 0x1 & val; 
00162 #define SET_VAL_SHIFT(val, shift) SET_VAL_BIT_MASK(val >> (7 - shift))
00163 #define CHECK_NEXT_STATE if (current_byte_progress > 7)     \
00164                          {                                  \
00165                                 out_current_state++;            \
00166                                 current_byte_progress = 0;  \
00167                          }
00168 
00169 // Fonction appellee periodiquement pour l'envoi du message courant
00170 void radio_out(void const *args)
00171 {
00172     static byte current_byte_progress = 0;    
00173     static byte current_byte = 0;    
00174     static byte out_current_state = out_preambule;    
00175     static bool IsBitTransition = false;
00176     static byte next_value = 0;
00177     static radio_message_t* message = NULL;
00178 
00179     out_debug_led3 = !out_debug_led3;
00180     // Si on est a la fin du packet, on retourne au debut et on reenvoye les donnees
00181     if (out_current_state > out_idle)
00182     {
00183         // Message termine
00184         message = NULL;
00185         last_out_message_read();
00186         frame_out_end_led2 = 0;
00187         
00188         // Reinitialisation des var de messages
00189         current_byte = 0;
00190         current_byte_progress = 0;
00191         out_current_state = out_preambule;
00192 
00193         out_timer.stop(); 
00194         out_timer.start(start_speed);   
00195     }
00196 
00197     if (message == NULL)
00198     {
00199         message = get_last_out_message();
00200     }
00201 
00202     if (message != NULL)
00203     {        
00204         if (!IsBitTransition)
00205         {            
00206             // Dependant du state, on progresse dans l'envoi du message
00207             switch (out_current_state) 
00208             {
00209                 case out_preambule: // preambule
00210                 {
00211                     frame_out_end_led2 = 1;
00212                     SET_VAL_SHIFT(message->preambule, current_byte_progress++);
00213                     CHECK_NEXT_STATE
00214                     break;
00215                 }        
00216                 case out_start: // start
00217                 {
00218                     SET_VAL_SHIFT(message->start, current_byte_progress++);
00219                     CHECK_NEXT_STATE
00220                     break;
00221                 }   
00222                 case out_options: // entete options
00223                 {
00224                     SET_VAL_SHIFT(message->options, current_byte_progress++);
00225                     CHECK_NEXT_STATE
00226                     break;
00227                 }             
00228                 case out_length: // entete lenght
00229                 {
00230                     SET_VAL_SHIFT(message->length, current_byte_progress++);
00231                     CHECK_NEXT_STATE
00232                     break;
00233                 }        
00234                 case out_data: // charge utile
00235                 {
00236                     SET_VAL_SHIFT(message->data[current_byte], current_byte_progress++)
00237                     if (current_byte_progress > 7)
00238                     {
00239                         current_byte++;
00240                         current_byte_progress = 0;                 
00241                         if (current_byte >= message->length)
00242                         {
00243                             current_byte = 0;
00244                             out_current_state++;
00245                         }                 
00246                     }
00247                     break;
00248                 }        
00249                 case out_crc: // controle
00250                 {
00251                     SET_VAL_SHIFT(message->control, current_byte_progress++);
00252                     CHECK_NEXT_STATE
00253                     break;
00254                 }        
00255                 case out_end: // end
00256                 {
00257                     SET_VAL_SHIFT(message->end, current_byte_progress++);
00258                     CHECK_NEXT_STATE
00259                     break; 
00260                 }
00261                 case out_idle:
00262                 {
00263                     /*out_debug_led3 = !out_debug_led3;
00264                     message = NULL;
00265                     last_out_message_read();
00266                     current_byte = 0;
00267                     current_byte_progress = 0;*/
00268                     break;
00269                 }                                         
00270             }
00271             
00272             // Changement d'etat pour permettre de faire la bonne transition de valeur
00273             if (next_value != output && out_current_state <= out_idle)
00274             {
00275                 output = !output;
00276             }
00277         }
00278         // Si on est pas dans une transitipon 
00279         else if (out_current_state != out_idle + 1)
00280         {
00281             output = !output;
00282             if (out_current_state == out_idle)
00283             {
00284                 out_current_state++;
00285             }
00286         }
00287         IsBitTransition = !IsBitTransition;    
00288     }
00289 }
00290 
00291 // Fonction appellee lors de l'interruption sur la pin d'entree
00292 void radio_in()
00293 {    
00294     // Timer utilise pour le calcul de la periode de l'horloge du code manchester
00295     static Timer timer;   
00296     // Valeur de la demi periode 
00297     static int half_period = 0;
00298     // Valeur de la periode de l'horloge
00299     static int calculated_period = 0;
00300     // 
00301     static byte current_byte = 0;
00302     
00303     in_debug_led4 = !in_debug_led4;   
00304     
00305     
00306     switch (current_state)
00307     {
00308         case in_attente:
00309         {     
00310             frame_in_end_led1 = 0;
00311             if (input == 1)
00312             {
00313                 timer.start();
00314                 current_state = in_preambule;   
00315                 current_byte_progress = 1;
00316                 frame_in_end_led1 = 1;
00317             }
00318             break;
00319         }
00320         case in_preambule:
00321         {
00322             current_byte_progress++;
00323             calculated_period = timer.read_ms();           
00324             timer.reset();
00325             if (current_byte_progress > 7)
00326             {             
00327                 half_period = calculated_period / 2;
00328                 ticker_watch.start(calculated_period + half_period);
00329                 current_byte_progress = 0;
00330                 current_byte = 0;
00331                 current_state = in_data;    
00332                 debug_char_output = calculated_period;
00333                // thread.signal_set(0x1);
00334             }
00335             break;
00336         }
00337         case in_data:
00338         {        
00339             // Si ca fait plus longtemps que la periode usuelle de reception de donne
00340             // Cela veut dire que l'on doit recommencer la reception
00341             if(timer.read_ms() > calculated_period)
00342             {
00343                 frame_in_end_led1 = 0;
00344                 timer.stop();      
00345                 timer.reset();    
00346                 if (input == 1)
00347                 {
00348                     timer.start();
00349                     current_state = in_preambule;   
00350                     current_byte_progress = 1;
00351                 }
00352                 else
00353                 {
00354                     current_state = in_attente;   
00355                     current_byte_progress = 0;
00356                 }  
00357             }
00358             // Si le temps de la demi periode est passe, donc on a une donne reele
00359             else if (timer.read_ms() > half_period)
00360             {               
00361                 current_byte = (!input << (7 - current_byte_progress)) | current_byte;
00362                 current_byte_progress++ ;                
00363                 ticker_watch.start(calculated_period + half_period);
00364                 timer.reset();      
00365                 
00366                 if (current_byte_progress > 7)
00367                 {                    
00368                     debug_char_output = current_byte;
00369                     if (receive_frame(current_byte))
00370                     {
00371                         current_state = in_attente;
00372                     }
00373                     current_byte_progress = 0;
00374                     current_byte = 0;
00375                 }
00376             }
00377             break;
00378         }
00379     }
00380 }
00381 
00382 // Fonction content la state machine de reception de trame
00383 bool receive_frame(byte read_byte)
00384 {
00385     static radio_message_t* current_message;
00386     static byte receive_current_state = out_start;
00387     static int data_index = 0;
00388 
00389     if (current_message == NULL)
00390     {
00391         current_message = get_new_in_message();
00392         receive_current_state = out_start;
00393         if (current_message == NULL){
00394             return true;
00395         }
00396     }
00397 
00398     if (current_message != NULL)
00399     {
00400         switch (receive_current_state)
00401         {
00402             case out_start:
00403             {
00404                 current_message->start = read_byte;
00405                 receive_current_state++;
00406                 break;
00407             }
00408             case out_options:
00409             {
00410                 current_message->options = read_byte;
00411                 receive_current_state++;
00412                 break;
00413             }
00414             case out_length:
00415             {
00416                 current_message->length = read_byte;
00417                 receive_current_state++;
00418                 break;
00419             }
00420             case out_data:
00421             {
00422                 current_message->data[data_index++] = read_byte;
00423                 if (data_index >= current_message->length)
00424                 {
00425                     data_index = 0;
00426                     receive_current_state++;
00427                 }
00428                 break;
00429             }
00430             case out_crc:
00431             {
00432                 current_message->control = read_byte;
00433                 receive_current_state++;
00434                 break;
00435             }
00436             case out_end:
00437             {
00438                 current_message->end = read_byte;
00439                 new_in_message_ready();
00440                 receive_current_state = out_start;
00441                 current_message = NULL;
00442                 return true;
00443                 break;
00444             }
00445 
00446         }
00447     }
00448     return false;
00449 }
00450 
00451 // Fonction de timeout de la reception de data manchester
00452 void stop_frame(void const *n)
00453 {
00454     frame_in_end_led1 = 0;
00455     current_state = in_attente;
00456     current_byte_progress = 0;
00457     ticker_watch.stop();
00458 }   
00459     
00460 // Fonction du thread d'affichage dans le terminal
00461 /*
00462 void thread_putc()
00463 {
00464     while(true)
00465     {
00466         Thread::signal_wait(0x1);
00467         debug_output.printf("0x%c\n\r", debug_char_output);    
00468     }   
00469 }*/
00470 
00471 ////////////////////////////////////////////////////////////////////////////
00472 ////////////////////////////////////////////////////////////////////////////
00473 ////////////////////////////////////////////////////////////////////////////
00474 ////////////////////////////////////////////////////////////////////////////
00475 
00476 /*
00477 * Public API function
00478 */
00479 
00480 /*
00481 *   Inits the radio system and begins receiving manchester coded messages
00482 *   Sends buffered messages
00483 */
00484 void init_radio_system()
00485 {
00486    init_crc_module();
00487    setup_radio_in();   
00488    setup_radio_out(); 
00489 }
00490 
00491 
00492 
00493 bool send_message(char* buffer, int length)
00494 {
00495     //////////////////////////////////////////////////////
00496     // Creation d'un message et insertion dans le buffer
00497     radio_message_t* message = get_new_out_message();
00498     if (length <= MAX_MESSAGE_LENGTH && message != NULL)
00499     {        
00500         message->preambule = HEADER_DELIMITER;
00501         message->start = HEADER_START;
00502         message->options = HEADER_DELIMITER;
00503         message->length = length;
00504         
00505         for (int i = 0; i < length; i++){
00506             message->data[i] = buffer[i];
00507         }         
00508         
00509         // Ajouter calcul du CRC
00510         message->control = get_crc_value(message->data, message->length);//0xCE;
00511         
00512         message->end = FOOTER_END;
00513         // On avance dans le buffer;
00514         return new_out_message_ready();
00515     }
00516     return false;
00517     //////////////////////////////////////////////////////   
00518 }
00519 
00520 bool get_message(radio_message_t* message)
00521 {
00522     radio_message_t* received_message;
00523     // Si un message a ete recu par la radio
00524     if((received_message = get_last_in_message()) != NULL)
00525     {
00526         // Si la valeur de CRC est valide par rapport a ce qui est calcule
00527         if (get_crc_value(received_message->data, received_message->length) == received_message->control)
00528         {
00529             message->preambule = received_message->preambule;
00530             message->start = received_message->start;
00531             message->options = received_message->options;
00532             message->length = received_message->length;
00533             // memcopy
00534             memcpy(message->data, received_message->data, received_message->length);
00535             
00536             message->control = received_message->control;
00537             message->end = received_message->end;
00538             
00539             last_in_message_read();
00540             return true;
00541         }
00542     }
00543     return false;
00544 }
00545 
00546 ////////////////////////////////////////////////////////////////////////////
00547 ////////////////////////////////////////////////////////////////////////////
00548 ////////////////////////////////////////////////////////////////////////////
00549 ////////////////////////////////////////////////////////////////////////////