Open qulmanaqim opened 7 years ago
hi @qulmanaqim did you find yet that transceiver?
No, I haven't. Do you have any suggestion, @deepak0003?
@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);
}
}
}
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?