Radio control: use the Jeti protocol to communicate between a DIY sensor and a Jeti receiver (using 9 bits one wire serial)
Diff: JetiC.cpp
- 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