Radio control: use the Jeti protocol to communicate between a DIY sensor and a Jeti receiver (using 9 bits one wire serial)

Dependencies:   mbed

Revision:
0:32193823db59
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/JetiC.cpp	Tue Oct 29 19:39:38 2013 +0000
@@ -0,0 +1,342 @@
+/*======== communication between a sensor (processor  32 bits) and a  Jeti Duplex receiver==============
+_____Jeti Data communication protocol______________________
+The communication from the RX module to the JetiBox
+1. It is 1-wire serial communication (9600 Bauds 9bits+parity + 2 stops))
+2. 1 message sent  consists of 34 byte, 2 control character (start=0xfe finish=0xff) and 32 bytes text between these control characters.
+4. 1 Byte consists of 13 bits in the format: T-D-D-D-D-D-D-D-D-I-P-S-S    (LSB first= T-0-1-2-3-4-5-6-7-I-P-S-S)
+        where: T = startbit, D =  8 data bits, I control characters or text ( 1=text, 0=control), P = parity based odd , S = stop bit (two).
+5. The JetiBox answers each message (34 byte)  with one byte  ACK message (with I=0: control byte)
+    0xF0 =11110000 if no button (four bits with value 1 if the button is NOT pushed
+    bit 4 =Right , Bit 5 = Up (or Back) , Bit 6 = Down or Select und Bit 7 Left
+6.a short delay  is needed between the received message and the ACK message
+     from the end of 0xff to begin of ACK :3,9 msec (mesured with Saleae)
+         -TU module waits 21 msec and  reply with a new 34 bytes message => total length = 79 msec
+
+    If there is no ACK, the TU module waits 25 msec and resend the message
+
+____hardware_________________________
+- a Mbed processor 
+- one pin of the processor provides the signal (Tx and Rx) to the receiver or to a JetiBox
+- I use a safety resistor 1k to 4.7k between the Pin and the Rx
+
+___tested with 
+1) a JetiBox directly connected to the Mbed processor and to a 4.8V battery
+2) a a JeTi receiver , a transmitter with a Jeti TU module
+
+The processor:  MBED  lpc1768 or LPC11u34 (The same program exists with a Ardiono Pro Mini 3.3V - with native 9 bits)
+
+___communication between the sensor programs and the Jeti interface________________
+- start the Jeti interface with a instance of the class JetiC, - afterwards the interface is running automatically  with interrupts
+- process the answer from the JetiBox
+   isAnswer() returns True when a answer message is received
+   getAnswer() returns the answer code (look at main.cpp)
+
+
+*/
+/*============================================================================
+ Copyright (C) 2013 Robert Spilleboudt
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+============================================================================*/
+
+#include "core.h"
+
+#define UART_PIN  p29     //pin for tx or rx , connect to the RX module through a 4.7k resitance
+#define UART_W1 96       /* this is the pulse width , the theoretical value  is 104(microsec) for 9600 bauds but there are some bugs...
+   Online compiler mbed.org
+     with mbed 1768 use the theoretical value 104 
+	 with mbed 11u24     use 96
+	Offline compiler code sourcery (2012/03)
+	  mbed 1768 use 96
+	  for the 11u24: not tested because  the .bin size is too great
+*/
+extern  instr_data rc; //common data  for all the programs
+/*-------------data for the interrupts are here---------------------------*/
+volatile uint8_t UART_pos;
+/*Normal text message
+* UART_pos = 0 -> start sending data with this interrupt enabled, start byte with 9.bit=0
+* UART_pos = 1-32 -> send display data with 9.bit=1
+* UART_pos = 33 -> send end byte with 9.bit=0
+* UART_pos = 34 -> set sendpos=0 and disable this interrupt
+Special message when returning to the expander :\x7E\x01\x31
+* UART_pos =100  start sending data with this interrupt enabled, start byte with 9.bit=0 , value \x7E
+* UART_pos =101  send \x01 with 9.bit=1
+* UART_pos =102  send \x31 with 9.bit=1
+ending with 34 to disble the interrupt
+*/
+volatile unsigned 	char JETI_buffer[33]; // the message from the sensot to the JetiBox
+volatile  unsigned char   UART_data ; //character transmitted or received, being filled bit / bit
+volatile bool UART_isanswer; 
+DigitalInOut UART_pin(UART_PIN); // pin connected to the signal from Rx module
+InterruptIn  UART_startBit(UART_PIN) ; //interrupt to detect the start bit (RX)
+Timeout      UART_nextBit; // pulse duration
+Timeout      UART_nextTx; //next start of transmission
+Ticker         UART_ticker; //ticker period= 1 msec
+volatile int	      UART_Tx_start;//msec counter to the next start of  a tx message
+
+//---------busy statistic----------------------------------------------
+//char processing
+volatile int   UART_counter;//within a char : next bit position value 0..8 (9 bits)+ 9=parity  10,11=stop  FOR  RX or TX
+bool textchar ; //true if text, false if control
+bool UART_errorchar ;// true if error (parity, stop bit)
+uint8_t    UART_parity;
+void ISRstartBit() ;
+void ISRdataBitRx();
+void ISRdataBitTx();
+//----interrupt routines ---------------------------------------------------------------------------------------
+void UART_tickerAdd(){ //call every msec
+    UART_Tx_start--;
+	if( UART_Tx_start<=0){//start the Tx message
+		UART_pos = 0;
+		UART_counter= -1;
+		UART_nextTx.attach_us(&ISRdataBitTx , 1000); 
+		UART_Tx_start=10000; //the  next start  is not yet scheduled
+		UART_startBit.fall(NULL); // no RX start bit interrupt
+		UART_pin.output();
+	    UART_pin=1;
+		UART_isanswer=false;
+	}
+}
+
+void ISRstartBit() { //Rx detect the start bit, start timeout to read the first data bit
+	UART_nextBit.attach_us(&ISRdataBitRx , UART_W1);
+	UART_counter= -1;//preparing for the first data bit
+	UART_data=0 ;//received data
+	UART_errorchar = false;
+	UART_parity=0;
+	UART_startBit.fall(NULL);  // detach the  ISRstartBit
+	UART_Tx_start =10000; // no not start Tx during the Rx receive
+}
+void ISRdataBitRx() { //nextbit timeout in Rx mode
+	UART_counter++;
+	if(UART_counter< 12) { //this is not the last bit of a character     - immediatly start the next timer interrupt
+		UART_nextBit.attach_us(&ISRdataBitRx , UART_W1);  // next bit
+	}
+	int pinread = UART_pin.read();
+	if(UART_counter<8) {    // process  the first 8 databits
+		UART_data = (UART_data >> 1);   //Right shift RX_data so the new bit can be masked into the Rx_data byte.
+		if(pinread==1) {
+			UART_data |= 0x80;               //Set MSB of RX data if received bit == 1.
+			UART_parity++;
+		}
+		return;
+	}
+	if(UART_counter==8)    {    // control bit
+		textchar = pinread;
+		UART_parity +=pinread;
+		return;
+	}
+	if(UART_counter==9)    { //parity
+		UART_parity +=pinread;
+		if(UART_parity%2 ==0) { //UART_errorchar=true;
+			UART_errorchar=true;
+		}
+		return;
+	}
+	if(UART_counter==10 || UART_counter==11)   {  //stop bits
+		if(pinread==0) {
+			UART_errorchar=true;
+		}
+		return;
+	}
+	//the bits of one UART character are received 
+	UART_Tx_start =25 ; //this start the Tx within 25 msec//restart the TX message after 25 msec
+
+	if(UART_errorchar || textchar) {
+		//rc.jetiptr->stat.UART_err ++;
+		//rc.jetiptr->status=0;
+		return; //do not process a incorrect answer
+	}
+	UART_isanswer=true;
+	rc.jetiptr->buttons= UART_data;
+}
+
+
+void ISRdataBitTx() { //nextbit timeout in Tx mode
+	int txpin =0;
+	if(UART_counter== -1) { //start a new char UART_data with the correct textchar
+		switch(UART_pos) { // UART_data = next char to transmit
+		case 0:// start TX message
+			UART_startBit.fall(NULL);
+			UART_pin.output();
+			UART_pin=0;  //begin the start bit
+			UART_data = 0xFE;
+			textchar = false;
+			UART_pos++;
+			break;
+		case 33: // send end byte with 9.bit=0
+			UART_data = 0xFF;
+			textchar = false;
+			UART_pos++;
+			break;
+		case 34: // all data sent
+			// listen to RX
+			UART_pin.input();
+			UART_pin.mode(PullUp);
+			//UART_pin.mode(PullNone);
+			UART_startBit.fall(& ISRstartBit);//detect the next received start bit
+			UART_Tx_start =25 ; //this start the Tx within 25 msec//restart the TX message after 25 msec
+			return;
+		case 100:
+			UART_data = 0x7E;
+			textchar = false;
+			UART_pos++;
+			break;
+		case 101:
+			UART_data = 0x01;
+			textchar = true;
+			UART_pos++;
+			break;
+		case 102:
+			UART_data = 0x31;
+			textchar = true;
+			UART_pos=34;
+			break;
+
+		default: // set 9.bit=1 text message
+			textchar = true;
+			UART_data = JETI_buffer[UART_pos-1]; // send byte from LCD buffer
+			UART_pos++;     // increment to next byte
+		}
+		//the start bit
+		txpin=0;
+		UART_parity=0;
+	}
+	// write each bit, beginning with LSB
+	if(UART_counter >=0 && UART_counter<8) {   //data bits 0..7
+		int out = UART_data & 0x01;
+		txpin=out;
+		UART_parity += out;
+		UART_data = (UART_data >>1);
+	}
+	if(UART_counter==8) {   //control bit
+		if(textchar)
+			txpin =1;
+		else
+			txpin=0;
+		UART_parity += txpin;
+
+	}
+	if(UART_counter==9) {   //parity bit
+		UART_parity++;
+		txpin= UART_parity%2;
+	}
+	if(UART_counter<10) {
+		UART_nextBit.attach_us(&ISRdataBitTx , UART_W1);  //next tx bit
+		UART_counter++;
+	} else { //stop  bits
+		UART_counter=-1; //to start the next char
+		txpin=1; // stop bits
+		UART_nextBit.attach_us(&ISRdataBitTx , 2*UART_W1); //2 stop bits
+	}
+	UART_pin.write(txpin);
+}
+//----communication
+JetiC::JetiC() { //start the interface with the Jeti transmitter module
+	for(int i=0; i<32; i++) {
+		JETI_buffer[i]=0x20   ;
+	}
+	JETI_buffer[0] ='S';
+	JETI_buffer[1] ='E';
+	JETI_buffer[2] ='N';
+	JETI_buffer[3] ='S';
+	JETI_buffer[4] ='O';
+	JETI_buffer[5] ='R';
+
+	JETI_buffer[32]='\0';
+	
+	UART_ticker.attach_us(&UART_tickerAdd, 1000); 
+	UART_Tx_start =0; //this start the Tx
+}
+bool JetiC::isAnswer() {
+	if(!UART_isanswer)
+		return false;
+	//message received
+	UART_isanswer = false;
+	UART_Tx_start =25 ; //this start the Tx within 25 msec
+	return true; //return true only one time
+}
+//----//various utility functions to fill the buffer  without the big "printf", too big for the memeory-----------------------------
+void JetiC::clear() { //fill with spaces
+	pos=0;
+	for(int i=0; i<32; i++)
+		JETI_buffer[i]=' ';
+}
+void JetiC::setPos(int x) {
+	if((x>=0) && (x<32))
+		pos=x;
+}
+
+void JetiC::print(char c) {
+	JETI_buffer[pos] = c;
+	if(pos< 31)
+		pos++;
+}
+void JetiC::print(long n , uint8_t len) {
+	printNumber(n, 0,len);
+}
+void JetiC::printf(float value, uint8_t p  , uint8_t len) { //value ,decimal point , length
+	int valint= value * pow(10.0 , p) +0.5 ;//convert the float in fixed point
+	printNumber((int) valint, p, len); //print the numbers
+}
+
+void JetiC::printNumber(int valint, uint8_t decimal,uint8_t len) {  //decimal ==0 => no decimal point decimal ==2 => string as 123.45
+	int i=0;
+	int sign = 1;
+	if(valint<0) {
+		sign=0;
+		valint=-valint;
+	}
+	while(valint > 0 || (decimal>0 &&i<decimal+2) ||(decimal==0 && i<1)) {
+		if(i>0 && i==decimal) { //insert adecimal point
+			JETI_buffer[pos +len-i -1] = '.';
+		} else {
+			JETI_buffer[pos +len-i -1] = (char)(((int)'0')+(valint % 10));
+			valint /= 10;
+		}
+		i++;
+		if(i>len-2)
+			break;
+	}
+	if(sign==0)
+		JETI_buffer[pos +len-i -1] = '-';
+	else
+		JETI_buffer[pos +len-i -1] = '+';
+
+	pos+= len;
+}
+void  JetiC::print_p(const char *s) {
+	char c;
+	while((c = (*s)) !='\0') {
+		s++;
+		print(c);
+	}
+}
+//--------debug the jeti protocol
+void JetiC::debug_display() {
+    clear();
+	print_p("  JetiDebug"); //line1
+	setPos(16);
+	if(buttons== B_RIGHT)
+		print_p("  B_RIGHT");
+	if(buttons== B_DOWN)
+		print_p("  B_DOWN");
+	if(buttons== B_UP)
+		print_p("  B_UP");
+	if(buttons== B_LEFT)
+		print_p("  B_LEFT");
+	return;
+
+}
\ No newline at end of file