jpiat / arduino

112 stars 70 forks source link

Emitter and Receiver in one file as Transceiver? #26

Open qulmanaqim opened 7 years ago

qulmanaqim commented 7 years ago

I have tried making a transceiver using both the emitter and receiver codes in one file but it didn't work as expected. I have tried using two interrupts using timer1 and timer3 for sample_edge and bit_emit_half but the received data was kind of scrambled. Do you have any advice in making a transceiver using the codes?

deepak0003 commented 7 years ago

hi @qulmanaqim did you find yet that transceiver?

qulmanaqim commented 7 years ago

No, I haven't. Do you have any suggestion, @deepak0003?

qulmanaqim commented 7 years ago

@jpiat , what should I change for this to work?

#include <TimerOne.h>
#include <TimerThree.h>
#include "receiver_types.h"
#include <util/atomic.h> //atomicity to prevent interrupt

#define DEBUG_HEX
//#define DEBUG_DATA
//#define DEBUG_ANALOG
//#define INT_REF /* Comment this to use AVCC reference voltage. To be used when the receiver LED generate low levels */
//#define TRANSMIT_SERIAL //uncomment to use serial mode

//This defines receiver properties
const int SENSOR_PIN = 0; //the analog pin number of the LED sensor

const int ledPin = 53; //the digital pin number of the LED emitter
const int powerPin = 11; //button power?
const int togglePin = 12; //button toggler?

#define SYMBOL_PERIOD 1000
#define SAMPLE_PER_SYMBOL 4
#define WORD_LENGTH 10 // a byte is encoded as a 10-bit value with start and stop bits
#define SYNC_SYMBOL 0xD5 // this symbol breaks the premanble of the frame
#define ETX 0x03 // End of frame symbol
#define STX 0x02 //Start or frame symbol 

enum receiver_state rframe_state = IDLE ;

// global variables for frame decoding
char eframe_buffer[38] ;
int eframe_index  = -1 ;
int eframe_size = -1 ;
char rframe_buffer[38] ;
int rframe_index  = -1 ;
int rframe_size = -1 ;

//state variables of the manchester encoder
unsigned char bit_counter = 0 ;
unsigned short data_word = 0 ;  //8bit data + start + stop
unsigned char half_bit = 0 ;
unsigned long int manchester_data ;

void to_manchester(unsigned char data, unsigned long int * data_manchester){
  unsigned int i ;
 (*data_manchester) = 0x02 ; // STOP symbol
 (*data_manchester) = (*data_manchester) << 2 ;
  for(i = 0 ; i < 8; i ++){
    if(data & 0x80) (*data_manchester) |=  0x02  ; // data LSB first
    else (*data_manchester) |= 0x01 ;
    (*data_manchester) = (*data_manchester) << 2 ;
    data = data << 1 ; // to next bit
  }
  (*data_manchester) |= 0x01 ; //START symbol
}

//emitter interrupt
void emit_half_bit(){
     if(manchester_data & 0x01){
        digitalWrite(ledPin, HIGH);
     }else{
        digitalWrite(ledPin, LOW);
     }
     bit_counter -- ;
     manchester_data = (manchester_data >> 1);
     if(bit_counter == 0){   
        //is there still bytes to send in the frame ?
        manchester_data = 0xAAAAAAAA ; // keep sending ones if nothing to send
        if(eframe_index >= 0 ){
          if(eframe_index < eframe_size){
            /*Serial.println(frame_index, DEC);
            Serial.println(frame_buffer[frame_index], HEX);*/
            to_manchester(eframe_buffer[eframe_index], &manchester_data);
            eframe_index ++ ;
          }else{
            eframe_index = -1 ;
            eframe_size = -1 ;
          }
        }
        bit_counter = WORD_LENGTH * 2 ;
        //Serial.println(manchester_data, BIN);
      }
}

void init_frame(unsigned char * frame){
  memset(frame, 0xAA, 3);
  frame[3] = SYNC_SYMBOL ;
  frame[4] = STX;
  eframe_index = -1 ;
  eframe_size = -1 ;
}

int create_frame(char * data, int data_size, unsigned char * frame){
  memcpy(&(frame[5]), data, data_size);
  frame[5+data_size] = ETX;
  return 1 ;
}

int write(char * data, int data_size){
  if(eframe_index >=  0) return -1 ;
  if(data_size > 32) return -1 ;
  create_frame(data, data_size,eframe_buffer);
  ATOMIC_BLOCK(ATOMIC_RESTORESTATE){
    eframe_index = 0 ;
    eframe_size = data_size + 6 ;
  }
  return 0 ;
}

int transmitter_available(){
  if(eframe_index >=  0) return 0 ;
  return 1 ; 
}

void init_emitter(){
  manchester_data = 0xFFFFFFFF ;
  bit_counter = WORD_LENGTH * 2 ;
}

//state variables of the thresholder
unsigned int signal_mean = 0 ;
unsigned long acc_sum = 0 ; //used to compute the signal mean value
unsigned int acc_counter = 0 ;

//manchester decoder state variable
long shift_reg = 0;

//Start of ADC managements functions
void ADC_setup(){
  ADCSRA =  bit (ADEN);                      // turn ADC on
  ADCSRA |= bit (ADPS0) |  bit (ADPS1) | bit (ADPS2);  // Prescaler of 128
  #ifdef INT_REF
  ADMUX  =  bit (REFS0) | bit (REFS1);    // internal 1.1v reference
  #else
  ADMUX  =  bit (REFS0) ;   // external 5v reference
  #endif
}

void ADC_start_conversion(int adc_pin){
  ADMUX &= ~(0x07) ; //clearing enabled channels
  ADMUX  |= (adc_pin & 0x07) ;    // AVcc and select input port
  bitSet (ADCSRA, ADSC) ;
}

int ADC_read_conversion(){
 while(bit_is_set(ADCSRA, ADSC));
 return ADC ;
}
//End of ADC management functions

#define START_SYMBOL 0x02
#define STOP_SYMBOL 0x01
#define START_STOP_MASK  ((STOP_SYMBOL << 20) | (START_SYMBOL << 18) | STOP_SYMBOL) //STOP/START/16bits/STOP
#define SYNC_SYMBOL_MANCHESTER  (0x6665) /* Sync symbol, encoded as a 16-bit Manchester value to help the decoding */
inline int is_a_word(long  * manchester_word, int time_from_last_sync, unsigned int * detected_word){
        if(time_from_last_sync >= 20  || rframe_state == IDLE){ // we received enough bits to test the sync      
            if(((*manchester_word) & START_STOP_MASK) == (START_STOP_MASK)){ // testing first position 
                  (*detected_word) = ((*manchester_word) >> 2) & 0xFFFF;
                  if(rframe_state == IDLE){
                     if((*detected_word) == SYNC_SYMBOL_MANCHESTER) return 2 ;
                  }
                  return 1 ;
                  // byte with correct framing
            }else if(rframe_state != IDLE && time_from_last_sync == 20){
               (*detected_word)= ((*manchester_word) >> 2) & 0xFFFF;
               return 1 ;
            }
          }
          return 0 ;
}

inline int insert_edge( long  * manchester_word, char edge, int edge_period, int * time_from_last_sync, unsigned int * detected_word){
   int new_word = 0 ;
   int is_a_word_value = 0 ;
   int sync_word_detect = 0 ;
   if( ((*manchester_word) & 0x01) != edge ){ //make sure we don't have same edge ...
             if(edge_period > (SAMPLE_PER_SYMBOL+1)){
                unsigned char last_bit = (*manchester_word) & 0x01 ;
                (*manchester_word) = ((*manchester_word) << 1) | last_bit ; // signal was steady for longer than a single symbol, 
                (*time_from_last_sync) += 1 ;
                is_a_word_value = is_a_word(manchester_word, (*time_from_last_sync), detected_word);
                if(is_a_word_value > 0){ //found start stop framing
                   new_word = 1 ;
                  (*time_from_last_sync) =  0 ;
                  if(is_a_word_value > 1) sync_word_detect = 1 ; //we detected framing and sync word in manchester format
                }
             }
             //storing edge value in word
             if(edge < 0){
              (*manchester_word) = ( (*manchester_word) << 1) | 0x00 ; // signal goes down
             }else{
              (*manchester_word) = ( (*manchester_word) << 1) | 0x01 ; // signal goes up
             }
             (*time_from_last_sync) += 1 ;
             is_a_word_value = is_a_word(manchester_word, (*time_from_last_sync), detected_word);
             if(sync_word_detect == 0 && is_a_word_value > 0){ //if sync word was detected at previous position, don't take word detection into account
               new_word = 1 ;
               (*time_from_last_sync) =  0 ;
             }
          }else{
            new_word = -1 ;
          }
          return new_word ;
}

#define EDGE_THRESHOLD 4 /* Defines the voltage difference between two samples to detect a rising/falling edge. Can be increased depensing on the environment */
int oldValue = 0 ;
int steady_count = 0 ;
int dist_last_sync = 0 ;
unsigned int detected_word = 0;
int new_word = 0;
char old_edge_val = 0 ;
void sample_signal_edge(){
  char edge_val ;
  //int sensorValue = analogRead(SENSOR_PIN); // this is too slow and should be replaced with interrupt-driven ADC
  int sensorValue  = ADC_read_conversion(); // read result of previously triggered conversion
  ADC_start_conversion(SENSOR_PIN); // start a conversion for next loop
  #ifndef DEBUG_DATA
  #ifdef DEBUG_ANALOG
  Serial.println(sensorValue, DEC);
  #endif
  #endif
  if((sensorValue - oldValue) > EDGE_THRESHOLD) edge_val = 1 ;
  else if((oldValue - sensorValue) > EDGE_THRESHOLD) edge_val = -1;
  else edge_val = 0 ;
  oldValue = sensorValue ;
  if(edge_val == 0 || edge_val == old_edge_val || (edge_val != old_edge_val && steady_count < 2)){
    if( steady_count < (4 * SAMPLE_PER_SYMBOL)){
      steady_count ++ ;
    }
  }else{  
          new_word = insert_edge(&shift_reg, edge_val, steady_count, &(dist_last_sync), &detected_word); 
          if(dist_last_sync > (8*SAMPLE_PER_SYMBOL)){ // limit dist_last_sync to avoid overflow problems
            dist_last_sync = 32 ;
          }
          //if(new_word >= 0){
            steady_count = 0 ;
          //}
        }
        old_edge_val = edge_val ;
}

int add_byte_to_frame(char * rframe_buffer, int * rframe_index, int * rframe_size, enum receiver_state * rframe_state ,unsigned char data){
  if(data == SYNC_SYMBOL/* && (*frame_index) < 0*/){
    (*rframe_index) = 0 ;
    (*rframe_size) = 0 ;
    (*rframe_state) = SYNC ;
    //Serial.println("SYNC");
    return 0 ;
  }
  if((*rframe_state) != IDLE){ // we are synced
  rframe_buffer[*rframe_index] = data ;
  (*rframe_index) ++ ;
    if(data == STX){
      //Serial.println("START");
      (*rframe_state) = START ;
       return 0 ;
    }else if(data == ETX){
      //Serial.println("END");
      (*rframe_size) = (*rframe_index) ;
      (*rframe_index) = -1 ;
      (*rframe_state) = IDLE ;
      //Serial.println("END");
       return 1 ;
    }else if((*rframe_index) >= 38){ //frame is larger than max size of frame ...
      (*rframe_index) = -1 ;
      (*rframe_size) = -1 ;
      (*rframe_state) = IDLE ;
      return -1 ;
    }else{
      (*rframe_state) = DATA ;
    }
    return 0 ;
  }
  return -1 ;
}

// the setup routine runs once when you press reset:
void setup() {
  // initialize serial communication at 115200 bits per second:
  Serial.begin(250000);
  pinMode(ledPin, OUTPUT);
  pinMode(togglePin, INPUT);
  pinMode(powerPin, OUTPUT);
  digitalWrite(powerPin, HIGH);
  pinMode(SENSOR_PIN, INPUT);
  ADC_setup();
  ADC_start_conversion(SENSOR_PIN);
  init_frame(eframe_buffer);
  init_emitter();
  Serial.println("Start of receiver program");
  //analogReference(INTERNAL); // internal reference is 1.1v, should give better accuracy for the mv range of the led output.
  Timer3.initialize(SYMBOL_PERIOD/SAMPLE_PER_SYMBOL); //1200 bauds oversampled by factor 4
  Timer3.attachInterrupt(sample_signal_edge);
  Timer1.initialize(SYMBOL_PERIOD); //1200 bauds oversampled by factor 4
  Timer1.attachInterrupt(emit_half_bit); 
}

char * msg = "Hello World" ;
char com_buffer [32] ;
char com_buffer_nb_bytes = 0 ;
// the loop routine runs over and over again forever:
void loop() {
  int i; 
  unsigned char received_data;
  char received_data_print ;
  int nb_shift ;
  int byte_added = 0 ;
  int buttonState = 0;   
  buttonState = digitalRead(togglePin);
  if(buttonState==LOW){
  //Serial.println("Transmitting");
  #ifdef TRANSMIT_SERIAL
  if(Serial.available() && transmitter_available()){ //constructing the data frame only if transmitter is ready to transmit
    char c = Serial.read();
    com_buffer[com_buffer_nb_bytes] = c ;
    com_buffer_nb_bytes ++ ;
    if(com_buffer_nb_bytes >= 32 || c == '\n'){
      if(write(com_buffer, com_buffer_nb_bytes) < 0){
        Serial.println("Transmitter is busy");
      }else{
        com_buffer_nb_bytes = 0 ;
      }
    }
  }
  delay(10);
  #else
    static int j = 0 ;
    memcpy(com_buffer, msg, 27); //memcpy(destination,source,length)
    com_buffer[27] = j + '0' ;
    if(write(com_buffer, 32) < 0){
      Serial.println(com_buffer);
      delay(10);
    }else{
      j ++ ; 
      if(j > 9) j = 0 ;
    }
  #endif
    }else{
  //Serial.println("Receiving");
  if(new_word == 1){
    received_data = 0 ;
    for(i = 0 ; i < 16 ; i = i + 2){ //decoding Manchester
             received_data = received_data << 1 ;
             if(((detected_word >> i) & 0x03) == 0x01){
                 digitalWrite(ledPin, HIGH);                 
                 received_data |= 0x01 ;
             }else{
                 digitalWrite(ledPin, HIGH);            
                 received_data &= ~0x01 ;
                 digitalWrite(ledPin, LOW);
             }
    }
    received_data = received_data & 0xFF ;
    #ifdef DEBUG_HEX
      digitalWrite(ledPin, HIGH);   
      Serial.print(received_data & 0xFF, HEX);
      //Serial.print(", ");
    #endif
    #ifdef DEBUG_DATA
      Serial.println((char) received_data);
    #endif
    new_word = 0 ;
    if((byte_added = add_byte_to_frame(rframe_buffer, &rframe_index, &rframe_size, &rframe_state,received_data)) > 0){
      //rframe_buffer[rframe_size-1] = '\0';
      digitalWrite(ledPin, HIGH);   
      Serial.println(&(rframe_buffer[1]));
    }
    //if(rframe_state != IDLE) Serial.println(received_data, HEX);
  }
  }
}