From d4b85e3b1c4caddb437c49cb58a7692174a8613a Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 9 Sep 2016 18:34:20 +0200 Subject: [PATCH] Hontai protocol & Bit bashing pause/resume --- Multiprotocol/Hontai_nrf24l01.ino | 258 ++++++++++++++++++++++++++++ Multiprotocol/MultiOrange.cpp.xmega | 25 +-- Multiprotocol/Multiprotocol.h | 19 +- Multiprotocol/Multiprotocol.ino | 37 +++- Multiprotocol/Telemetry.ino | 42 +++-- Multiprotocol/_Config.h | 5 + 6 files changed, 352 insertions(+), 34 deletions(-) create mode 100644 Multiprotocol/Hontai_nrf24l01.ino diff --git a/Multiprotocol/Hontai_nrf24l01.ino b/Multiprotocol/Hontai_nrf24l01.ino new file mode 100644 index 0000000..e25b019 --- /dev/null +++ b/Multiprotocol/Hontai_nrf24l01.ino @@ -0,0 +1,258 @@ +/* + This project 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 3 of the License, or + (at your option) any later version. + + Multiprotocol 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 Multiprotocol. If not, see . + */ + +#if defined(HONTAI_NRF24L01_INO) + +#include "iface_nrf24l01.h" + +#define HONTAI_BIND_COUNT 80 +#define HONTAI_PACKET_PERIOD 13500 + +#define HONTAI_INITIAL_WAIT 500 +#define HONTAI_BIND_HONTAI_PACKET_SIZE 10 +#define HONTAI_PACKET_SIZE 12 +#define HONTAI_RF_BIND_CHANNEL 0 + +// For code readability +enum { + CHANNEL1 = 0, // Aileron + CHANNEL2, // Elevator + CHANNEL3, // Throttle + CHANNEL4, // Rudder + CHANNEL5, // Leds + CHANNEL6, // Flip + CHANNEL7, // Still camera + CHANNEL8, // Video camera + CHANNEL9, // Headless + CHANNEL10, // Return To Home + CHANNEL11, // Calibrate +}; +#define CHANNEL_LED CHANNEL5 +#define CHANNEL_ARM CHANNEL5 // for JJRC X1 +#define CHANNEL_FLIP CHANNEL6 +#define CHANNEL_PICTURE CHANNEL7 +#define CHANNEL_VIDEO CHANNEL8 +#define CHANNEL_HEADLESS CHANNEL9 +#define CHANNEL_RTH CHANNEL10 +#define CHANNEL_CALIBRATE CHANNEL11 + +enum{ + HONTAI_FLAG_FLIP = 0x01, + HONTAI_FLAG_PICTURE = 0x02, + HONTAI_FLAG_VIDEO = 0x04, + HONTAI_FLAG_HEADLESS = 0x08, + HONTAI_FLAG_RTH = 0x10, + HONTAI_FLAG_CALIBRATE = 0x20, +}; + +// proudly swiped from http://www.drdobbs.com/implementing-the-ccitt-cyclical-redundan/199904926 +#define HONTAI_POLY 0x8408 +static void __attribute__((unused)) crc16(uint8_t *data_p, uint8_t length) +{ + uint16_t crc = 0xffff; + + length -= 2; + do + { + for (uint8_t i = 0, data = (uint8_t)*data_p++; + i < 8; + i++, data >>= 1) + { + if ((crc & 0x01) ^ (data & 0x01)) + crc = (crc >> 1) ^ HONTAI_POLY; + else + crc >>= 1; + } + } while (--length); + + crc = ~crc; + *data_p++ = crc & 0xff; + *data_p = crc >> 8; +} + +static void __attribute__((unused)) HONTAI_send_packet(uint8_t bind) +{ + uint8_t packet_size; + if (bind) + { + memcpy(packet, rx_tx_addr, 5); + memset(&packet[5], 0, 3); + packet_size=HONTAI_BIND_HONTAI_PACKET_SIZE; + } + else + { + if(sub_protocol == FORMAT_JJRCX1) + packet[0] = GET_FLAG(CHANNEL_ARM, 0x02); + else + packet[0] = 0x0b; + + packet[1] = 0x00; + packet[2] = 0x00; + packet[3] = (convert_channel_8b_scale(THROTTLE, 0, 127) << 1) // Throttle + | GET_FLAG(Servo_AUX3, 0x01); // Picture + packet[4] = convert_channel_8b_scale(CHANNEL1, 63, 0); // Aileron + if(sub_protocol == FORMAT_JJRCX1) + packet[4] |= 0x80; // not sure what this bit does + else + { + packet[4] |= GET_FLAG(Servo_AUX6, 0x80) // RTH + | GET_FLAG(Servo_AUX5, 0x40); // Headless + } + packet[5] = convert_channel_8b_scale(ELEVATOR, 0, 63) // Elevator + | GET_FLAG(Servo_AUX7, 0x80) // Calibrate + | GET_FLAG(Servo_AUX1, 0x40); // Flip + packet[6] = convert_channel_8b_scale(RUDDER, 0, 63) // Rudder + | GET_FLAG(Servo_AUX4, 0x80); // Video + packet[7] = convert_channel_8b_scale(AILERON, 0, 32)-16; // Aileron trim + if(sub_protocol == FORMAT_JJRCX1) + { + packet[8] = 0xc0 // Always in expert mode + | GET_FLAG(Servo_AUX6, 0x02) // RTH + | GET_FLAG(Servo_AUX5, 0x01); // Headless + } + else + packet[8] = convert_channel_8b_scale(RUDDER, 0, 32)-16; // Rudder trim + packet[9] = convert_channel_8b_scale(ELEVATOR, 0, 32)-16; // Elevator trim + packet_size=HONTAI_PACKET_SIZE; + } + crc16(packet, packet_size); + + // Power on, TX mode, 2byte CRC + if(sub_protocol == FORMAT_JJRCX1) + NRF24L01_SetTxRxMode(TX_EN); + else + XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP)); + + NRF24L01_WriteReg(NRF24L01_05_RF_CH, bind ? HONTAI_RF_BIND_CHANNEL : hopping_frequency[hopping_frequency_no++]); + hopping_frequency_no %= 3; + + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); + NRF24L01_FlushTx(); + + if(sub_protocol == FORMAT_JJRCX1) + NRF24L01_WritePayload(packet, packet_size); + else + XN297_WritePayload(packet, packet_size); + + NRF24L01_SetPower(); +} + +static void __attribute__((unused)) HONTAI_init() +{ + NRF24L01_Initialize(); + + NRF24L01_SetTxRxMode(TX_EN); + + if(sub_protocol == FORMAT_JJRCX1) + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\xd2\xb5\x99\xb3\x4a", 5); + else + XN297_SetTXAddr((const uint8_t*)"\xd2\xb5\x99\xb3\x4a", 5); + + NRF24L01_FlushTx(); + NRF24L01_FlushRx(); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit + NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowldgement on all data pipes + NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps + NRF24L01_SetPower(); + NRF24L01_Activate(0x73); // Activate feature register + if(sub_protocol == FORMAT_JJRCX1) + { + NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0xff); // JJRC uses dynamic payload length + NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3f); // match other stock settings even though AA disabled... + NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07); + } + else + { + NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits + NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes + NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x00); + } + NRF24L01_Activate(0x73); // Deactivate feature register +} + +const uint8_t PROGMEM hopping_frequency_nonels[][3] = { + {0x05, 0x19, 0x28}, // Hontai + {0x0a, 0x1e, 0x2d}}; // JJRC X1 + +const uint8_t PROGMEM addr_vals[4][16] = { + {0x24, 0x26, 0x2a, 0x2c, 0x32, 0x34, 0x36, 0x4a, 0x4c, 0x4e, 0x54, 0x56, 0x5a, 0x64, 0x66, 0x6a}, + {0x92, 0x94, 0x96, 0x9a, 0xa4, 0xa6, 0xac, 0xb2, 0xb4, 0xb6, 0xca, 0xcc, 0xd2, 0xd4, 0xd6, 0xda}, + {0x93, 0x95, 0x99, 0x9b, 0xa5, 0xa9, 0xab, 0xad, 0xb3, 0xb5, 0xc9, 0xcb, 0xcd, 0xd3, 0xd5, 0xd9}, + {0x25, 0x29, 0x2b, 0x2d, 0x33, 0x35, 0x49, 0x4b, 0x4d, 0x59, 0x5b, 0x65, 0x69, 0x6b, 0x6d, 0x6e}}; + +static void __attribute__((unused)) HONTAI_init2() +{ + uint8_t data_tx_addr[5]; + + //TX address + data_tx_addr[0] = pgm_read_byte_near( &addr_vals[0][ rx_tx_addr[3] & 0x0f]); + data_tx_addr[1] = pgm_read_byte_near( &addr_vals[1][(rx_tx_addr[3] >> 4) & 0x0f]); + data_tx_addr[2] = pgm_read_byte_near( &addr_vals[2][ rx_tx_addr[4] & 0x0f]); + data_tx_addr[3] = pgm_read_byte_near( &addr_vals[3][(rx_tx_addr[4] >> 4) & 0x0f]); + data_tx_addr[4] = 0x24; + if(sub_protocol == FORMAT_JJRCX1) + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, data_tx_addr, sizeof(data_tx_addr)); + else + XN297_SetTXAddr(data_tx_addr, sizeof(data_tx_addr)); + + //Hopping frequency table + for(uint8_t i=0;i<3;i++) + hopping_frequency[i]=pgm_read_byte_near( &hopping_frequency_nonels[sub_protocol == FORMAT_JJRCX1?1:0][i] ); + hopping_frequency_no=0; +} + +static void __attribute__((unused)) HONTAI_initialize_txid() +{ + rx_tx_addr[4] = rx_tx_addr[2]; + if(sub_protocol == FORMAT_HONTAI) + { + rx_tx_addr[0] = 0x4c; // first three bytes some kind of model id? - set same as stock tx + rx_tx_addr[1] = 0x4b; + rx_tx_addr[2] = 0x3a; + } + else + { + rx_tx_addr[0] = 0x4b; // JJRC X1 + rx_tx_addr[1] = 0x59; + rx_tx_addr[2] = 0x3a; + } +} + +uint16_t HONTAI_callback() +{ + if(bind_counter!=0) + { + HONTAI_send_packet(1); + bind_counter--; + if (bind_counter == 0) + { + HONTAI_init2(); + BIND_DONE; + } + } + else + HONTAI_send_packet(0); + + return HONTAI_PACKET_PERIOD; +} + +uint16_t initHONTAI() +{ + bind_counter = HONTAI_BIND_COUNT; + HONTAI_initialize_txid(); + HONTAI_init(); + return HONTAI_INITIAL_WAIT; +} +#endif diff --git a/Multiprotocol/MultiOrange.cpp.xmega b/Multiprotocol/MultiOrange.cpp.xmega index 85a7ca0..9c94c2d 100644 --- a/Multiprotocol/MultiOrange.cpp.xmega +++ b/Multiprotocol/MultiOrange.cpp.xmega @@ -9,11 +9,10 @@ static void protocol_init(void) ; static void update_aux_flags(void) ; -static void PPM_Telemetry_serial_init(void) ; +//static void PPM_Telemetry_serial_init(void) ; static uint32_t random_id(uint16_t adress, uint8_t create_new) ; static void update_serial_data(void) ; static void Mprotocol_serial_init(void) ; -static void module_reset(void) ; static void update_led_status(void) ; static void set_rx_tx_addr(uint32_t id) ; uint16_t limit_channel_100(uint8_t ch) ; @@ -26,9 +25,6 @@ extern void CC2500_Reset(void ) ; extern uint8_t CYRF_Reset(void ) ; extern void CYRF_SetTxRxMode(uint8_t mode) ; -extern void frskyUpdate(void) ; -extern uint16_t initDsm2(void) ; -extern uint16_t ReadDsm2(void) ; extern uint16_t DevoInit(void) ; extern uint16_t devo_callback(void) ; @@ -43,6 +39,15 @@ extern void init(void) ; extern int analogRead(uint8_t pin) ; +extern void modules_reset() ; +extern void Update_All() ; +extern void tx_pause() ; +extern void tx_resume() ; +extern void TelemetryUpdate() ; +extern uint16_t initDsm() ; +extern uint16_t ReadDsm() ; + + #define A6 20 #define A7 21 @@ -358,10 +363,10 @@ void init() #endif // PPM interrupt - PORTD.DIRCLR = 0x08 ; // D3 is input - PORTD.PIN3CTRL = 0x01 ; // Rising edge - PORTD.INT0MASK = 0x08 ; - PORTD.INTCTRL = 0x02 ; // Medium level interrupt +// PORTD.DIRCLR = 0x08 ; // D3 is input +// PORTD.PIN3CTRL = 0x01 ; // Rising edge +// PORTD.INT0MASK = 0x08 ; +// PORTD.INTCTRL = 0x02 ; // Medium level interrupt // Dip Switch inputs PORTA.DIRCLR = 0xFF ; @@ -462,7 +467,7 @@ void NRF24L01_Reset() #include "Multiprotocol.ino" #include "cyrf6936_SPI.ino" -#include "DSM2_cyrf6936.ino" +#include "DSM_cyrf6936.ino" #include "Devo_cyrf6936.ino" #include "Telemetry.ino" diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 2ac6e25..34d3af8 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -53,7 +53,8 @@ enum PROTOCOLS MODE_J6PRO = 22, // =>CYRF6936 MODE_FQ777 = 23, // =>NRF24L01 MODE_ASSAN = 24, // =>NRF24L01 - MODE_FRSKYV = 25 // =>CC2500 + MODE_FRSKYV = 25, // =>CC2500 + MODE_HONTAI = 26 // =>NRF24L01 }; enum Flysky @@ -123,12 +124,17 @@ enum MJXQ H26D = 3, E010 = 4 }; - enum FRSKYX { CH_16 = 0, CH_8 = 1, }; +enum HONTAI +{ + FORMAT_HONTAI = 0, + FORMAT_JJRCX1 = 1, + FORMAT_X5C1 = 2 +}; #define NONE 0 #define P_HIGH 1 @@ -154,10 +160,10 @@ struct PPM_Parameters #define OCF1A_bm TC1_CCAIF_bm #define OCR1A TCC1.CCA #define TCNT1 TCC1.CNT - #define USARTC0.DATA UDR0 + #define UDR0 USARTC0.DATA #define OCF1B_bm TC1_CCBIF_bm #define OCR1B TCC1.CCB - #define TCC1.INTCTRLB TIMSK1 + #define TIMSK1 TCC1.INTCTRLB #define SET_TIMSK1_OCIE1B TIMSK1 = (TIMSK1 & 0xF3) | 0x04 #define CLR_TIMSK1_OCIE1B TIMSK1 &= 0xF3 #else @@ -539,6 +545,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- FQ777 23 ASSAN 24 FrskyV 25 + HONTAI 26 BindBit=> 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No @@ -595,6 +602,10 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- sub_protocol==FRSKYX CH_16 0 CH_8 1 + sub_protocol==HONTAI + FORMAT_HONTAI 0 + FORMAT_JJRCX1 1 + FORMAT_X5C1 2 Power value => 0x80 0=High/1=Low Stream[3] = option_protocol; option_protocol value is -127..127 diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index e15a811..c46a5c9 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -30,7 +30,10 @@ #include "TX_Def.h" #ifdef XMEGA - #undef ENABLE_PPM // Disable PPM for orange module + #undef ENABLE_PPM // Disable PPM for orange module + #undef A7105_INSTALLED // Disable A7105 for orange module + #undef CC2500_INSTALLED // Disable CC2500 for orange module + #undef NFR24L01_INSTALLED // Disable NRF for orange module #endif //Global constants/variables @@ -285,30 +288,28 @@ void loop() while((TIFR1 & OCF1A_bm) == 0); // Wait before callback do { - TX_ON; TX_MAIN_PAUSE_on; tx_pause(); next_callback=remote_callback(); TX_MAIN_PAUSE_off; tx_resume(); - TX_OFF; while(next_callback>4000) { // start to wait here as much as we can... next_callback-=2000; // We will wait below for 2ms cli(); // Disable global int due to RW of 16 bits registers OCR1A += 2000*2 ; // set compare A for callback - TIFR1=OCF1A_bm; // clear compare A=callback flag + TIFR1=OCF1A_bm; // clear compare A=callback flag sei(); // enable global int Update_All(); if(IS_CHANGE_PROTOCOL_FLAG_on) break; // Protocol has been changed - while((TIFR1 & OCF1A_bm) == 0); // wait 2ms... + while((TIFR1 & OCF1A_bm) == 0); // wait 2ms... } // at this point we have a maximum of 4ms in next_callback next_callback *= 2 ; cli(); // Disable global int due to RW of 16 bits registers OCR1A+= next_callback ; // set compare A for callback - TIFR1=OCF1A_bm; // clear compare A=callback flag + TIFR1=OCF1A_bm; // clear compare A=callback flag diff=OCR1A-TCNT1; // compare timer and comparator sei(); // enable global int } @@ -413,6 +414,8 @@ inline void tx_resume() #else #ifndef BASH_SERIAL UCSR0B |= _BV(UDRIE0); // Resume telemetry by enabling transmitter interrupt + #else + resumeBashSerial() ; #endif #endif } @@ -631,6 +634,12 @@ static void protocol_init() remote_callback = ASSAN_callback; break; #endif + #if defined(HONTAI_NRF24L01_INO) + case MODE_HONTAI: + next_callback=initHONTAI(); + remote_callback = HONTAI_callback; + break; + #endif } if(next_callback>32000) @@ -875,21 +884,33 @@ static uint32_t random_id(uint16_t adress, uint8_t create_new) /********************/ /** SPI routines **/ /********************/ +#ifdef XMEGA + #define XNOP() NOP() +#else + #define XNOP() +#endif + void SPI_Write(uint8_t command) { uint8_t n=8; SCK_off;//SCK start low + XNOP(); SDI_off; + XNOP(); do { if(command&0x80) SDI_on; else SDI_off; + XNOP(); SCK_on; + XNOP(); + XNOP(); command = command << 1; SCK_off; + XNOP(); } while(--n) ; SDI_on; @@ -904,8 +925,12 @@ uint8_t SPI_Read(void) if(SDO_1) result |= 0x01; SCK_on; + XNOP(); + XNOP(); NOP(); SCK_off; + XNOP(); + XNOP(); } return result; } diff --git a/Multiprotocol/Telemetry.ino b/Multiprotocol/Telemetry.ino index 54a44cc..f728214 100644 --- a/Multiprotocol/Telemetry.ino +++ b/Multiprotocol/Telemetry.ino @@ -43,7 +43,7 @@ uint8_t frame[18]; #if defined DSM_TELEMETRY void DSM_frame() { - Serial_write(0xAA); // Start + Serial_write(0xAA); // Telemetry packet for (uint8_t i = 0; i < 17; i++) // RSSI value followed by 16 bytes of telemetry data Serial_write(pkt[i]); } @@ -625,6 +625,12 @@ void Serial_write( uint8_t byte ) SerialControl.data[SerialControl.head+1] = byteLo ; SerialControl.head = next ; } + if(!IS_TX_PAUSE_on) + tx_resume(); +} + +void resumeBashSerial() +{ cli() ; if ( SerialControl.busy == 0 ) { @@ -701,23 +707,31 @@ ISR(TIMER0_COMPB_vect) GPIOR2 = byte ; if ( --GPIOR1 == 0 ) { - // prepare next byte and allow for 2 stop bits - struct t_serial_bash *ptr = &SerialControl ; - if ( ptr->head != ptr->tail ) - { - GPIOR0 = ptr->data[ptr->tail] ; - GPIOR2 = ptr->data[ptr->tail+1] ; - ptr->tail = ( ptr->tail + 2 ) & 0x3F ; - GPIOR1 = 8 ; - OCR0A = OCR0B + 40 ; - OCR0B = OCR0A + 8 * 20 ; - TIMSK0 |= (1<head != ptr->tail ) + { + GPIOR0 = ptr->data[ptr->tail] ; + GPIOR2 = ptr->data[ptr->tail+1] ; + ptr->tail = ( ptr->tail + 2 ) & 0x3F ; + GPIOR1 = 8 ; + OCR0A = OCR0B + 40 ; + OCR0B = OCR0A + 8 * 20 ; + TIMSK0 |= (1<