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

Dependencies:   mbed

Files at this revision

API Documentation at this revision

Comitter:
robertspil
Date:
Tue Oct 29 19:39:38 2013 +0000
Commit message:
Initial release -tested with 1768 and 11U34

Changed in this revision

JetiC.cpp Show annotated file Show diff for this revision Revisions of this file
core.h Show annotated file Show diff for this revision Revisions of this file
main.cpp Show annotated file Show diff for this revision Revisions of this file
mbed.lib Show annotated file Show diff for this revision Revisions of this file
--- /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
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/core.h	Tue Oct 29 19:39:38 2013 +0000
@@ -0,0 +1,52 @@
+#ifndef CORE_H
+#define CORE_H
+#include "mbed.h"
+#define B_RIGHT 0xE0
+#define B_LEFT   0x70
+#define B_UP      0xD0
+#define B_DOWN 0xB0
+#define B_ERASE 0x60
+int GetTicker();
+class JetiC { // free-wheeling communication with the JetiBox
+	/* use :
+	constructor initialize a first message
+	loop until isAnswer()==True
+		process the answer : select() + display()
+		getSensor()
+		
+	*/
+	public:
+	JetiC(); 
+	bool isAnswer(); //-> true after the Get from Rx ; reset  when the call isAnswer() returned true
+	int current_node;
+	int buttons; //answer from the jei box buttons
+	//void write_buffer();
+	void display(); //format the buffer for the current node and the current sensor data
+    void select( ); // process the answer to select a new current_node
+	void debug_display();
+	//-----various utility functions to fill the buffer-------------------------------
+	void clear();
+	void print(char);
+	void print(long value, uint8_t len); // len = total length
+	void printf(float value, uint8_t decimals, uint8_t len); // 2nd argument = number of decimals
+	void print_p(const char *); //const char * const mystrings[] = {"aaa","zzzz"};
+	void setPos(int);//set the position of the "cursor"
+	
+	private:
+	
+	//Timer loop;
+	void printNumber( int value, uint8_t pos, uint8_t len);
+	int pos;
+	int mode; //0 = normal message 1=special sequence to quit the sensor going left through the expander
+
+//this class is in the file JetiC.cpp, with the interrupt routines and their specific data
+};
+
+// common data
+struct instr_data{
+	JetiC*    jetiptr; //pointer to the JetiBox object..or NULL
+//	Sensor* sensorptr ; // pointer to the Sensor Object
+	
+};
+#endif
+
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Tue Oct 29 19:39:38 2013 +0000
@@ -0,0 +1,36 @@
+/* main program to communicate  between a sensor  and a Jeti Duplex receiver
+ Sensor assembly = pcb with processor and sensors 
+ processor MBED  lpc1768 or LPC11u34
+
+ Organization of the program files
+ main.cpp = main program - add here the s
+ core.h = main header file
+ JetiC.cpp  = serial communication with jeti
+ 
+ depending on the sensors
+ JetiMenu.cpp = Jeti Box menu for the sensor assembly
+ Sensor.h Sensor.cpp        = read the physical sensors and compute the measures
+ libraries , provided by external sources, the internet community..
+    one library for each sensor
+
+  */
+#include "core.h"
+#include <new>   //needed for the nothrow
+struct instr_data rc; //common sensor data  
+void init() {
+	rc.jetiptr = new(nothrow) JetiC(); // initialize and start the messages to the JetiBox
+	//rc.sensorptr = new(nothrow) Sensor();
+	
+}
+
+int main() {
+	init();
+	while(true) { //vey simple scheduler for the sensors
+		if (rc.jetiptr->isAnswer()){ //process the answer from the JetiBox
+			//add here the code to read the sensors
+			//rc.jetiptr->select(); // process the answer code and/or  choose a node
+			//rc.jetiptr->display(); //prepare the message for this node
+			rc.jetiptr->debug_display(); //replace the select / display above with a simple debug without any sensor
+		}
+	}
+}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/mbed.lib	Tue Oct 29 19:39:38 2013 +0000
@@ -0,0 +1,1 @@
+http://mbed.org/users/mbed_official/code/mbed/#f37f3b9c9f0b