Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
lifiReceiver.cpp
- Committer:
 - JongYongPark
 - Date:
 - 2019-04-06
 - Revision:
 - 14:07669aafe0e4
 - Parent:
 - 12:df54493ec7e4
 - Child:
 - 16:c551ee1092f5
 
File content as of revision 14:07669aafe0e4:
#include "app.h"
//#include "../arduino.h"
//#include "mbed.h"
//#include <string>
#include "lifiTranceiver.h"
#include "lifiTranceiverLocal.h"
//#define USE_SLOW_TXRX_DEMO
//#define USE_SERIAL_COMMAND
//// OLED를 활성화 시키면 FreeRTOS가 정상 동작 안한다. 이문제는 다음에 해결하기로 하자.
//// 한글 입력이 잘 되네.
// TODO 1 :  ADCREF 3.3 Volt - Done
// TODO 2 :  Check Max/Max ADC
///////////////////////////////////////////////////////
///////// HEADER //////////////////////////////////////
enum op_mode {
	OP_HF, OP_LF, OP_PLOT_ADC, OP_RESERVED
};
enum receiver_state {
	IDLE_STATE = 0, //waiting for sync
	SYNC_STATE, //synced, waiting for STX
	START_STATE, //STX received
	LENGTH_LSB_STATE,
	LENGTH_MSB_STATE,
	DATA_STATE, //receiving DATA
	END_STATE
};
///////////////////////////////////////////////////////
////////////  GLOBAL VARIABLES   //////////////////////
unsigned char incomingByte;
int lines = 0;
int chars = 0;
////////////
//manechester decoder state variable
//long shift_reg = 0;
//
//int oldValue = 0 ;
//int steady_count = 0 ;
//int dist_last_sync = 0 ;
//unsigned int detected_word = 0;
//int new_word = 0;
//int old_edge_val = 0 ;
//int probe_adc_high = 0;
//int probe_adc_low = 0;
//int probe_adc_gap = 0;
struct RX_VARS {
	int sensorValue;
	int oldValue;
	int edge_val;
	int steady_count;
	int dist_last_sync;
	unsigned int detected_word;
	int new_word;
	long shift_reg;
	int old_edge_val;
	int probe_adc_high;
	int probe_adc_low;
	int probe_adc_gap;
	enum receiver_state frame_state;
	unsigned char rx_frame_buffer[FRAME_BUFFER_SIZE];
	//////////// keep received message
	bool is_valid;
	bool is_received;
	unsigned char rx_frame_buffer_received[FRAME_BUFFER_SIZE];
	int probe_adc_high_received;
	int probe_adc_low_received;
	int probe_adc_gap_received;
	///////////
	// no auxiliary security header
	int rx_frame_index;
	int rx_frame_size;
	uint16_t length;
	uint16_t received_data_count;
};
// __attribute__((packed));
static RX_VARS rx_vars[LIFI_MIMO_CHANNEL_NUM];
//static int adc_read_value=0;
inline int is_a_word_4ch(int channel, long * manchester_word,
		int time_from_last_sync, unsigned int * detected_word) {
#if RX_DEBUG_BIN
	printf("\t %d[%4x] ",channel+1, *detected_word );
#endif
	if (time_from_last_sync >= 20
			|| rx_vars[channel].frame_state == IDLE_STATE) { // 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 (rx_vars[channel].frame_state == IDLE_STATE) {
				if ((*detected_word) == SYNC_SYMBOL_MANCHESTER) {
					return 2;
				}
			}
			return 1;
			// byte with correct framing
		} else if (rx_vars[channel].frame_state != IDLE_STATE
				&& time_from_last_sync == 20) {
			(*detected_word) = ((*manchester_word) >> 2) & 0xFFFF;
			return 1;
		}
	}
	return 0;
}
inline int insert_edge_4ch(int channel, long * manchester_word, int 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) { //mak sure we don't have same edge ...
		if (edge_period > (LIFI_RX_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_4ch(channel, 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
#if RX_DEBUG_BIN
							printf("\n%dS",channel+1);
#endif
				}
			}
		}
		/////////////////////////////
		//storing edge value in word
		if (edge < 0) {
			(*manchester_word) = ((*manchester_word) << 1) | 0x00; // signal goes down
#if RX_DEBUG_BIN
					printf("%d[0]",channel+1);
#endif
		} else {
			(*manchester_word) = ((*manchester_word) << 1) | 0x01; // signal goes up
#if RX_DEBUG_BIN
					printf("%d[1]",channel+1);
#endif
		}
		/////////////////////////////////////
		(*time_from_last_sync) += 1;
		is_a_word_value = is_a_word_4ch(channel, 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;
#if RX_DEBUG_BIN
			printf("%dD",channel+1);
#endif
		}
	} else {
		new_word = -1;
#if RX_DEBUG_BIN
		printf("%d_",channel+1);
#endif
	}
	return new_word;
}
void sample_signal_edge_4ch(int channel, int sensorValue) {
	rx_vars[channel].sensorValue = sensorValue;
	//int sensorValue = analogRead(SENSOR_PIN_PORT); // this is too slow and should be replaced with interrupt-driven ADC
	//t sensorValue  = LifiRx_AdcRead(0); // read result of previously triggered conversion
	//ADC_start_conversion(SENSOR_PIN); // start a conversion for next loop
#if RX_DEBUG_ANALOG_SENSOR_VALUE
	printf(" adc:%d ",rx_vars[channel].sensorValue);
#endif
	if ((rx_vars[channel].sensorValue - rx_vars[channel].oldValue)
			> LIFI_RX_EDGE_THRESHOLD) {
		rx_vars[channel].edge_val = 1;
#if RX_DEBUG_EDGE
		printf("%d/ %d-%d",channel+1,rx_vars[channel].sensorValue,rx_vars[channel].oldValue);
#endif
		if (rx_vars[channel].probe_adc_high < rx_vars[channel].sensorValue)
			rx_vars[channel].probe_adc_high = rx_vars[channel].sensorValue;
	} else if ((rx_vars[channel].oldValue - rx_vars[channel].sensorValue)
			> LIFI_RX_EDGE_THRESHOLD) {
		rx_vars[channel].edge_val = -1;
#if RX_DEBUG_EDGE
		printf("%d| %d-%d",channel+1,rx_vars[channel].oldValue,rx_vars[channel].sensorValue);
#endif
		if (rx_vars[channel].probe_adc_low > rx_vars[channel].sensorValue)
			rx_vars[channel].probe_adc_low = rx_vars[channel].sensorValue;
	} else {
#if RX_DEBUG_EDGE
		printf("%d=",channel+1);
#endif
		rx_vars[channel].edge_val = 0;
	}
	/////////////
	rx_vars[channel].oldValue = rx_vars[channel].sensorValue;
	if (rx_vars[channel].edge_val == 0
			|| rx_vars[channel].edge_val == rx_vars[channel].old_edge_val
			|| (rx_vars[channel].edge_val != rx_vars[channel].old_edge_val
					&& rx_vars[channel].steady_count < 2)) {
		if (rx_vars[channel].steady_count < (4 * LIFI_RX_SAMPLE_PER_SYMBOL)) {
#if RX_DEBUG_EDGE
			printf("%d+",channel+1);
#endif
			rx_vars[channel].steady_count++;
		}
	} else {
#if RX_DEBUG_EDGE
		if(rx_vars[channel].edge_val == 1) printf("%dH",channel+1);
		else if(rx_vars[channel].edge_val == -1) printf("%dL",channel+1);
#endif
		//inline int insert_edge_4ch(int channel, long  * manchester_word, int edge, int edge_period, int * time_from_last_sync, unsigned int * detected_word)
		rx_vars[channel].new_word = insert_edge_4ch(channel,
				&rx_vars[channel].shift_reg, rx_vars[channel].edge_val,
				rx_vars[channel].steady_count,
				&(rx_vars[channel].dist_last_sync),
				&rx_vars[channel].detected_word);
		if (rx_vars[channel].dist_last_sync > (8 * LIFI_RX_SAMPLE_PER_SYMBOL)) { // limit dist_last_sync to avoid overflow problems
			rx_vars[channel].dist_last_sync = 32;
#if RX_DEBUG_FRAME
//            println("\t %dRESET avoid overlow ",channel+1);
#endif
		}
//        if(new_word >= 0) {
#if RX_DEBUG_FRAME
//            println("\t %dRESET COUNTER ",channel+1);
#endif
		rx_vars[channel].steady_count = 0;
//    }
	}
	rx_vars[channel].old_edge_val = rx_vars[channel].edge_val;
#if (USE_MBED_OS5 && USE_LIFI_RX_CHECK_QUEUE)        
	if((rx_vars[channel].new_word == 1) && (channel == LIFI_ACTUAL_MAX_CHANNEL_NUM_INDEX))
	{
		//printf("!");
		// https://os.mbed.com/forum/bugs-suggestions/topic/28244/?page=1#comment-53612
		lifi_tx_check_queue.call(LifiRx_LoopOOK);
	}
#endif      
}
int add_byte_to_frame(int channel, unsigned char * rx_frame_buffer,
		int * rx_frame_index, int * rx_frame_size,
		enum receiver_state * frame_state, unsigned char data) {
	if (data == SYNC_SYMBOL/* && (*rx_frame_index) < 0*/) {
		(*rx_frame_index) = 0;
		(*rx_frame_size) = 0;
		(*frame_state) = SYNC_STATE;
#if RX_DEBUG_FRAME
		printf("\n%dSYNC ",channel+1);
#endif
		return 0;
	}
	if ((*frame_state) != IDLE_STATE) { // we are synced
		rx_frame_buffer[*rx_frame_index] = data;
		(*rx_frame_index)++;
		if ((*frame_state) == SYNC_STATE) {
			if (data == STX) {
#if RX_DEBUG_FRAME
				printf("%dSTART ",channel+1);
#endif
				(*frame_state) = START_STATE;
				return 0;
			} else if (data == SYNC_SYMBOL) {
				// do nothing
			} else {
				printf(
						"\n Error # got wrong data after SYNC. it should be STX");
			}
		} else if ((*frame_state) == START_STATE) {
#if RX_DEBUG_FRAME
			printf("%dLENGTH_LSB ",channel+1);
#endif
			(*frame_state) = LENGTH_LSB_STATE;
			rx_vars[channel].length = data;
		} else if ((*frame_state) == LENGTH_LSB_STATE) {
#if RX_DEBUG_FRAME
			printf("%dLENGTH_MSB ",channel+1);
#endif
			(*frame_state) = LENGTH_MSB_STATE;
			rx_vars[channel].length = rx_vars[channel].length + (data << 8);
		} else if ((*frame_state) == LENGTH_MSB_STATE) {
#if RX_DEBUG_FRAME
			printf("%dD=%c[%x] ",channel+1,data,data);
#endif
			(*frame_state) = DATA_STATE;
			rx_vars[channel].received_data_count = 1;
		} else if ((*frame_state) == DATA_STATE) {
#if RX_DEBUG_FRAME
			printf("%dD=%c[%x] ",channel+1,data,data);
#endif
//            (*frame_state) = DATA_STATE ;
			rx_vars[channel].received_data_count++;
			if (rx_vars[channel].received_data_count
					>= rx_vars[channel].length) {
				(*frame_state) = END_STATE;
			}
		} else if ((*frame_state) == END_STATE) {
			if (data == ETX) {
#if RX_DEBUG_FRAME
				printf("%dEND IDLE ",channel+1);
#endif
				(*rx_frame_size) = (*rx_frame_index);
				(*rx_frame_index) = -1;
				(*frame_state) = IDLE_STATE;
				return 1;
			} else {
				printf("\n Error # got wrong data. it should be ETX");
				return 1;
			}
		} else if ((*rx_frame_index) >= FRAME_BUFFER_SIZE) { //frame is larger than max size of frame ...
#if RX_DEBUG_FRAME
		printf("%dIDLE - over FRAME_BUFFER_SIZE ",channel+1);
#endif
			(*rx_frame_index) = -1;
			(*rx_frame_size) = -1;
			(*frame_state) = IDLE_STATE;
			return -1;
		} else {
			printf("\n Error # unknown state");
			return 1;
		}
		return 0;  // normal
	}
	return -1;  // error
}
int counter = 0;
void setup_ADC() {
//
//    if( (m_op_mode != OP_HW_TEST) &&  (m_op_mode != OP_PLOT_ADC))
//    {
//        //analogReference(INTERNAL); // internal reference is 1.1v, should give better accuracy for the mv range of the led output.
//        Timer1.initialize(LIFI_RX_SYMBOL_PERIOD_US/LIFI_RX_SAMPLE_PER_SYMBOL); //1200 bauds oversampled by factor 4
//        Timer1.attachInterrupt(sample_signal_edge);
//    }
}
// the setup routine runs once when you press reset:
//bool isValidNumber(string str)
//{
//    bool isNum=true;
//    for(byte i=0; i<str.length(); i++) {
//        //isNum = isDigit(str.charAt(i)) || str.charAt(i) == '+' || str.charAt(i) == '.' || str.charAt(i) == '-';
////       isNum = isDigit(str.charAt(i)); // || str.charAt(i) == '+' || str.charAt(i) == '.' || str.charAt(i) == '-';
//        if(!isNum) return false;
//    }
//    return isNum;
//}
void rx_loop_ook_4ch(int channel) {
	int i;
	unsigned char received_data;
	//unsigned char received_data_print ;
	//int nb_shift ;
	int byte_added = 0;
	int valid_chars;
	if (rx_vars[channel].new_word == 1) {
		received_data = 0;
		for (i = 0; i < 16; i = i + 2) { //decoding Manchester
			received_data = received_data << 1;
			if (((rx_vars[channel].detected_word >> i) & 0x03) == 0x01) {
				received_data |= 0x01;
			} else {
				received_data &= ~0x01;
			}
		}
		received_data = received_data & 0xFF;
#if RX_DEBUG_MAIN_LOOP
//        printf("%dRx:%c[%x]",,channel+1,(unsigned char) received_data,received_data & 0xFF);
#endif
		rx_vars[channel].new_word = 0;
		if ((byte_added = add_byte_to_frame(channel,
				rx_vars[channel].rx_frame_buffer,
				&rx_vars[channel].rx_frame_index,
				&rx_vars[channel].rx_frame_size, &rx_vars[channel].frame_state,
				received_data)) > 0) {
			valid_chars = 1;
			rx_vars[channel].rx_frame_buffer[rx_vars[channel].rx_frame_size - 1] =
					'\0';
#if RX_DEBUG_MAIN_LOOP
			//printf("%dAdc[Max=%d Min=%d]",channel+1,rx_vars[channel].probe_adc_high,rx_vars[channel].probe_adc_low);
#endif
			rx_vars[channel].probe_adc_high_received =
					rx_vars[channel].probe_adc_high;
			rx_vars[channel].probe_adc_low_received =
					rx_vars[channel].probe_adc_low;
			rx_vars[channel].probe_adc_gap_received =
					rx_vars[channel].probe_adc_high
							- rx_vars[channel].probe_adc_low;
			rx_vars[channel].probe_adc_high = 0;
			rx_vars[channel].probe_adc_low = 1024;
			for (int i = 1; i < (rx_vars[channel].rx_frame_size - 1); i++) {
				if ((rx_vars[channel].rx_frame_buffer[i] < ' ')
						|| (rx_vars[channel].rx_frame_buffer[i] > '~')) {
					valid_chars = 0;
					break;
				} else {
				}
			}
			memcpy(rx_vars[channel].rx_frame_buffer_received,
					rx_vars[channel].rx_frame_buffer, FRAME_BUFFER_SIZE);
			rx_vars[channel].is_received = true;
			if (valid_chars) {
//                //println(&(rx_frame_buffer[1]));
//                //stringReceive = string(&(rx_frame_buffer[1]));
//                //stringReceive = stringReceive.toUpperCase();
//                //println(stringReceive);
//                printf("\nMSG(ch_%d)[%s]",channel, rx_vars[channel].rx_frame_buffer);
				rx_vars[channel].is_valid = true;
			} else {
//                printf("\nMSG_Invalid(ch_%d)[%s]",channel, rx_vars[channel].rx_frame_buffer);
				rx_vars[channel].is_valid = false;
			}
		}
		//if(frame_state != IDLE_STATE) println(received_data, HEX);
	}
}
void print_4ch_message() {
	int channel = LIFI_CHANNEL_1;
	for (; channel <= LIFI_ACTUAL_MAX_CHANNEL_NUM_INDEX; channel++) {
		if (rx_vars[channel].is_received == false)
			return;
	}
#if RX_DEBUG_MAIN_LOOP    
	printf("\n{{{");
	printf("\nMSG valid=%d, (ch_%d)[len:%d/%d][%s] Adc[Max=%d Min=%d Gap=%d]",
			rx_vars[LIFI_CHANNEL_1].is_valid,
			rx_vars[LIFI_CHANNEL_1].received_data_count,
			rx_vars[LIFI_CHANNEL_1].length, LIFI_CHANNEL_1,
			rx_vars[LIFI_CHANNEL_1].rx_frame_buffer_received,
			rx_vars[LIFI_CHANNEL_1].probe_adc_high_received,
			rx_vars[LIFI_CHANNEL_1].probe_adc_low_received,
			rx_vars[LIFI_CHANNEL_1].probe_adc_gap_received);
#endif    
	rx_vars[LIFI_CHANNEL_1].is_received = false;
	if (Lifi_IsChannelAvailable(LIFI_CHANNEL_2)) {
#if RX_DEBUG_MAIN_LOOP   
		printf(
				"\nMSG valid=%d, (ch_%d)[len:%d/%d][%s] Adc[Max=%d Min=%d Gap=%d]",
				rx_vars[LIFI_CHANNEL_2].is_valid,
				rx_vars[LIFI_CHANNEL_2].received_data_count,
				rx_vars[LIFI_CHANNEL_2].length, LIFI_CHANNEL_2,
				rx_vars[LIFI_CHANNEL_2].rx_frame_buffer_received,
				rx_vars[LIFI_CHANNEL_2].probe_adc_high_received,
				rx_vars[LIFI_CHANNEL_2].probe_adc_low_received,
				rx_vars[LIFI_CHANNEL_2].probe_adc_gap_received);
#endif   
		rx_vars[LIFI_CHANNEL_2].is_received = false;
	}
	if (Lifi_IsChannelAvailable(LIFI_CHANNEL_3)) {
#if RX_DEBUG_MAIN_LOOP   
		printf(
				"\nMSG valid=%d, (ch_%d)[len:%d/%d][%s] Adc[Max=%d Min=%d Gap=%d]",
				rx_vars[LIFI_CHANNEL_3].is_valid,
				rx_vars[LIFI_CHANNEL_3].received_data_count,
				rx_vars[LIFI_CHANNEL_3].length, LIFI_CHANNEL_3,
				rx_vars[LIFI_CHANNEL_3].rx_frame_buffer_received,
				rx_vars[LIFI_CHANNEL_3].probe_adc_high_received,
				rx_vars[LIFI_CHANNEL_3].probe_adc_low_received,
				rx_vars[LIFI_CHANNEL_3].probe_adc_gap_received);
#endif   
		rx_vars[LIFI_CHANNEL_3].is_received = false;
	}
	if (Lifi_IsChannelAvailable(LIFI_CHANNEL_4)) {
#if RX_DEBUG_MAIN_LOOP   
		printf(
				"\nMSG valid=%d, (ch_%d)[len:%d/%d][%s] Adc[Max=%d Min=%d Gap=%d]",
				rx_vars[LIFI_CHANNEL_4].is_valid,
				rx_vars[LIFI_CHANNEL_4].received_data_count,
				rx_vars[LIFI_CHANNEL_4].length, LIFI_CHANNEL_4,
				rx_vars[LIFI_CHANNEL_4].rx_frame_buffer_received,
				rx_vars[LIFI_CHANNEL_4].probe_adc_high_received,
				rx_vars[LIFI_CHANNEL_4].probe_adc_low_received,
				rx_vars[LIFI_CHANNEL_4].probe_adc_gap_received);
#endif   
		rx_vars[LIFI_CHANNEL_4].is_received = false;
	}
#if RX_DEBUG_MAIN_LOOP    
	printf("\n}}}");
#endif
}
void LifiRx_LoopOOK() {
	//printf("!");
	// for 1 channel, it works well.
	// data corrupted when open 2 channels
	// LIFI_RX_SYMBOL_PERIOD_SEC  (0.01)  = works well for 2 channels *********
	rx_loop_ook_4ch(LIFI_CHANNEL_1);
	if (Lifi_IsChannelAvailable(LIFI_CHANNEL_2))
		rx_loop_ook_4ch(LIFI_CHANNEL_2);
	if (Lifi_IsChannelAvailable(LIFI_CHANNEL_3))
		rx_loop_ook_4ch(LIFI_CHANNEL_3);
	if (Lifi_IsChannelAvailable(LIFI_CHANNEL_4))
		rx_loop_ook_4ch(LIFI_CHANNEL_4);
	print_4ch_message();
}
// the loop routine runs over and over again forever:
void LifiRx_SampleSignalEdge() {
	int sensorValue, sensorValue2, sensorValue3, sensorValue4;
	sensorValue = LifiRx_AdcRead(LIFI_CHANNEL_1);
	if (Lifi_IsChannelAvailable(LIFI_CHANNEL_2))
		sensorValue2 = LifiRx_AdcRead(LIFI_CHANNEL_2);
	if (Lifi_IsChannelAvailable(LIFI_CHANNEL_3))
		sensorValue3 = LifiRx_AdcRead(LIFI_CHANNEL_3);
	if (Lifi_IsChannelAvailable(LIFI_CHANNEL_4))
		sensorValue4 = LifiRx_AdcRead(LIFI_CHANNEL_4);
	sample_signal_edge_4ch(LIFI_CHANNEL_1, sensorValue);
	if (Lifi_IsChannelAvailable(LIFI_CHANNEL_2))
		sample_signal_edge_4ch(LIFI_CHANNEL_2, sensorValue2);
	if (Lifi_IsChannelAvailable(LIFI_CHANNEL_3))
		sample_signal_edge_4ch(LIFI_CHANNEL_3, sensorValue3);
	if (Lifi_IsChannelAvailable(LIFI_CHANNEL_4))
		sample_signal_edge_4ch(LIFI_CHANNEL_4, sensorValue4);
}
void LifiRx_Init() {
	rx_vars[LIFI_CHANNEL_1].rx_frame_index = -1;
	rx_vars[LIFI_CHANNEL_2].rx_frame_index = -1;
	rx_vars[LIFI_CHANNEL_3].rx_frame_index = -1;
	rx_vars[LIFI_CHANNEL_4].rx_frame_index = -1;
	rx_vars[LIFI_CHANNEL_1].rx_frame_size = -1;
	rx_vars[LIFI_CHANNEL_2].rx_frame_size = -1;
	rx_vars[LIFI_CHANNEL_3].rx_frame_size = -1;
	rx_vars[LIFI_CHANNEL_4].rx_frame_size = -1;
	rx_vars[LIFI_CHANNEL_1].is_received = false;
	rx_vars[LIFI_CHANNEL_2].is_received = false;
	rx_vars[LIFI_CHANNEL_3].is_received = false;
	rx_vars[LIFI_CHANNEL_4].is_received = false;
}