Radio control: use the Jeti protocol to communicate between a DIY sensor and a Jeti receiver (using 9 bits one wire serial)
JetiC.cpp
- Committer:
- robertspil
- Date:
- 2013-10-29
- Revision:
- 0:32193823db59
File content as of revision 0:32193823db59:
/*======== 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; }