From 151e82a2c38666e18ce817026ef73b8adc630e78 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 22 Jan 2016 16:23:39 +0100 Subject: [PATCH 001/293] _Config.h file and all protocol settings for PPM mode --- Multiprotocol/FrSky_cc2500.ino | 2 +- Multiprotocol/Hisky_nrf24l01.ino | 30 +++-- Multiprotocol/Hubsan_a7105.ino | 1 + Multiprotocol/Multiprotocol.ino | 213 +++++++----------------------- Multiprotocol/_Config.h | 220 +++++++++++++++++++++++++++++++ Multiprotocol/multiprotocol.h | 189 ++------------------------ README.md | 23 +++- 7 files changed, 320 insertions(+), 358 deletions(-) create mode 100644 Multiprotocol/_Config.h diff --git a/Multiprotocol/FrSky_cc2500.ino b/Multiprotocol/FrSky_cc2500.ino index 035383e..40b0f6c 100644 --- a/Multiprotocol/FrSky_cc2500.ino +++ b/Multiprotocol/FrSky_cc2500.ino @@ -151,7 +151,7 @@ static void frsky2way_init(uint8_t bind) cc2500_writeReg(CC2500_08_PKTCTRL0, 0x05); cc2500_writeReg(CC2500_3E_PATABLE, 0xff); cc2500_writeReg(CC2500_0B_FSCTRL1, 0x08); - cc2500_writeReg(CC2500_0C_FSCTRL0, fine); + cc2500_writeReg(CC2500_0C_FSCTRL0, option); //base freq FREQ = 0x5C7627 (F = 2404MHz) cc2500_writeReg(CC2500_0D_FREQ2, 0x5c); cc2500_writeReg(CC2500_0E_FREQ1, 0x76); diff --git a/Multiprotocol/Hisky_nrf24l01.ino b/Multiprotocol/Hisky_nrf24l01.ino index d7a3fde..4076f7a 100644 --- a/Multiprotocol/Hisky_nrf24l01.ino +++ b/Multiprotocol/Hisky_nrf24l01.ino @@ -18,21 +18,21 @@ #include "iface_nrf24l01.h" -#define BIND_COUNT 1000 -#define TXID_SIZE 5 -#define FREQUENCE_NUM 20 +#define HISKY_BIND_COUNT 1000 +#define HISKY_TXID_SIZE 5 +#define HISKY_FREQUENCE_NUM 20 // uint8_t bind_buf_arry[4][10]; // HiSky protocol uses TX id as an address for nRF24L01, and uses frequency hopping sequence // which does not depend on this id and is passed explicitly in binding sequence. So we are free // to generate this sequence as we wish. It should be in the range [02..77] -static void calc_fh_channels(uint32_t seed) +static void calc_fh_channels() { uint8_t idx = 0; - uint32_t rnd = seed; + uint32_t rnd = MProtocol_id; - while (idx < FREQUENCE_NUM) + while (idx < HISKY_FREQUENCE_NUM) { uint8_t i; uint8_t count_2_26 = 0, count_27_50 = 0, count_51_74 = 0; @@ -41,7 +41,7 @@ static void calc_fh_channels(uint32_t seed) // Use least-significant byte. 73 is prime, so channels 76..77 are unused uint8_t next_ch = ((rnd >> 8) % 73) + 2; // Keep the distance 2 between the channels - either odd or even - if (((next_ch ^ (uint8_t)seed) & 0x01 )== 0) + if (((next_ch ^ (uint8_t)rx_tx_addr[3]) & 0x01 )== 0) continue; // Check that it's not duplicated and spread uniformly for (i = 0; i < idx; i++) { @@ -195,7 +195,7 @@ uint16_t hisky_cb() NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5); NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]); hopping_frequency_no++; - if (hopping_frequency_no >= FREQUENCE_NUM) + if (hopping_frequency_no >= HISKY_FREQUENCE_NUM) hopping_frequency_no = 0; break; case 7: @@ -213,15 +213,19 @@ uint16_t hisky_cb() return 1000; // send 1 binding packet and 1 data packet per 9ms } -// Generate internal id from TX id and manufacturer id (STM32 unique id) static void initialize_tx_id() { //Generate frequency hopping table if(sub_protocol==HK310) - for(uint8_t i=0;i. */ +// compatible with Hubsan H102D, H107/L/C/D and H107P/C+/D+ // Last sync with hexfet new_protocols/hubsan_a7105.c dated 2015-12-11 #if defined(HUBSAN_A7105_INO) diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index c10128d..ea19440 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -4,7 +4,7 @@ http://www.rcgroups.com/forums/showthread.php?t=2165676 https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/edit/master/README.md - Thanks to PhracturedBlue + Thanks to PhracturedBlue, Hexfet, Goebish and all protocol developers Ported from deviation firmware This project is free software: you can redistribute it and/or modify @@ -23,71 +23,10 @@ #include #include #include +#include "Multiprotocol.h" -//****************************************************** -//****************************************************** -// Multiprotocol module configuration starts here - -//Uncomment the type of TX -#define TX_ER9X //ER9X AETR (988<->2012µs) -//#define TX_DEVO7 //DEVO7 EATR (1120<->1920µs) -//#define TX_SPEKTRUM //Spektrum TAER (1100<->1900µs) -//#define TX_HISKY //HISKY AETR (1100<->1900µs) - -#include "multiprotocol.h" - -//Uncomment to enable 8 channels serial protocol, 16 otherwise -//#define NUM_SERIAL_CH_8 - -//Uncomment to enable telemetry -#define TELEMETRY - -//Comment protocols to exclude from compilation -#define BAYANG_NRF24L01_INO -#define CG023_NRF24L01_INO -#define CX10_NRF24L01_INO -#define DEVO_CYRF6936_INO -#define DSM2_CYRF6936_INO -#define ESKY_NRF24L01_INO -#define FLYSKY_A7105_INO -#define FRSKY_CC2500_INO -#define HISKY_NRF24L01_INO -#define HUBSAN_A7105_INO -#define KN_NRF24L01_INO -#define SLT_NRF24L01_INO -#define SYMAX_NRF24L01_INO -#define V2X2_NRF24L01_INO -#define YD717_NRF24L01_INO -//#define FRSKYX_CC2500_INO - -//Update this table to set which protocol/sub_protocol is called for the corresponding dial number -static const uint8_t PPM_prot[15][2]= { {MODE_FLYSKY , Flysky }, //Dial=1 - {MODE_HUBSAN , 0 }, //Dial=2 - {MODE_FRSKY , 0 }, //Dial=3 - {MODE_HISKY , Hisky }, //Dial=4 - {MODE_V2X2 , 0 }, //Dial=5 - {MODE_DSM2 , DSM2 }, //Dial=6 - {MODE_DEVO , 0 }, //Dial=7 - {MODE_YD717 , YD717 }, //Dial=8 - {MODE_KN , WLTOYS }, //Dial=9 - {MODE_SYMAX , SYMAX }, //Dial=10 - {MODE_SLT , 0 }, //Dial=11 - {MODE_CX10 , CX10_BLUE }, //Dial=12 - {MODE_CG023 , CG023 }, //Dial=13 - {MODE_BAYANG , 0 }, //Dial=14 - {MODE_SYMAX , SYMAX5C } //Dial=15 - }; - -//CC2500 RF module frequency adjustment, use in case you cannot bind with Frsky RX -//Note: this is set via Option when serial protocol is used -//values from 0-127 offset increase frequency, values from 255 to 127 decrease base frequency -//uint8_t fine = 0x00; -uint8_t fine = 0xd7; //* 215=-41 * - -// Multiprotocol module configuration ends here -//****************************************************** -//****************************************************** - +//Multiprotocol module configuration file +#include "_Config.h" //Global constants/variables @@ -132,11 +71,7 @@ uint8_t mode_select; uint8_t protocol_flags=0,protocol_flags2=0; // Serial variables -#if defined(NUM_SERIAL_CH_8) //8 channels serial protocol -#define RXBUFFER_SIZE 14 -#else //16 channels serial protocol #define RXBUFFER_SIZE 25 -#endif #define TXBUFFER_SIZE 12 volatile uint8_t rx_buff[RXBUFFER_SIZE]; volatile uint8_t rx_ok_buff[RXBUFFER_SIZE]; @@ -213,18 +148,22 @@ void setup() LED_SET_OUTPUT; // Read or create protocol id - MProtocol_id=random_id(10,false); - MProtocol_id_master=MProtocol_id; + MProtocol_id_master=random_id(10,false); + - //Set power transmission flags - POWER_FLAG_on; //By default high power for everything - //Protocol and interrupts initialization if(mode_select != MODE_SERIAL) { // PPM - cur_protocol[0]= PPM_prot[mode_select-1][0]; - sub_protocol = PPM_prot[mode_select-1][1]; - protocol_init(cur_protocol[0]); + mode_select--; + cur_protocol[0] = PPM_prot[mode_select].protocol; + sub_protocol = PPM_prot[mode_select].sub_proto; + MProtocol_id = PPM_prot[mode_select].rx_num + MProtocol_id_master; + option = PPM_prot[mode_select].option; + if(PPM_prot[mode_select].power) POWER_FLAG_on; + if(PPM_prot[mode_select].autobind) AUTOBIND_FLAG_on; + mode_select++; + + protocol_init(); //Configure PPM interrupt EICRA |=(1<>2)+860; //range 860-2140; -#else //16 channels serial protocol + // decode channel values volatile uint8_t *p=rx_ok_buff+2; uint8_t dec=-3; for(uint8_t i=0;i>dec)&0x7FF)*5)/8+860; //value range 860<->2140 -125%<->+125% } -#endif RX_FLAG_off; //data has been processed } @@ -617,16 +543,6 @@ uint16_t limit_channel_100(uint8_t ch) return Servo_data[ch]; } -// Convert 32b id to rx_tx_addr -static void set_rx_tx_addr(uint32_t id) -{ // Used by almost all protocols - rx_tx_addr[0] = (id >> 24) & 0xFF; - rx_tx_addr[1] = (id >> 16) & 0xFF; - rx_tx_addr[2] = (id >> 8) & 0xFF; - rx_tx_addr[3] = (id >> 0) & 0xFF; - rx_tx_addr[4] = 0xC1; // for YD717: always uses first data port -} - #if defined(TELEMETRY) void Serial_write(uint8_t data) { @@ -641,21 +557,12 @@ void Serial_write(uint8_t data) static void Mprotocol_serial_init() { -#if defined(NUM_SERIAL_CH_8) //8 channels serial protocol - #define BAUD 125000 - #include - UBRR0H = UBRRH_VALUE; - UBRR0L = UBRRL_VALUE; - //Set frame format to 8 data bits, no parity, 1 stop bit - UCSR0C |= (1< UBRR0H = UBRRH_VALUE; UBRR0L = UBRRL_VALUE; //Set frame format to 8 data bits, even parity, 2 stop bits UCSR0C |= (1<> 24) & 0xFF; + rx_tx_addr[1] = (id >> 16) & 0xFF; + rx_tx_addr[2] = (id >> 8) & 0xFF; + rx_tx_addr[3] = (id >> 0) & 0xFF; + rx_tx_addr[4] = 0xC1; // for YD717: always uses first data port +} + static uint32_t random_id(uint16_t adress, uint8_t create_new) { uint32_t id; @@ -694,6 +611,7 @@ static uint32_t random_id(uint16_t adress, uint8_t create_new) /**************************/ /**************************/ +//PPM ISR(INT1_vect) { // Interrupt on PPM pin static int8_t chan=-1; @@ -722,53 +640,7 @@ ISR(INT1_vect) Prev_TCNT1+=Cur_TCNT1; } -#if defined(TELEMETRY) -ISR(USART_UDRE_vect) -{ // Transmit interrupt - uint8_t t = tx_tail; - if(tx_head!=t) - { - if(++t>=TXBUFFER_SIZE)//head - t=0; - UDR0=tx_buff[t]; - tx_tail=t; - } - if (t == tx_head) - UCSR0B &= ~(1<>8) ^ rx_buff[idx++]) & 0xFF]); - } - else - { // A frame has been received and needs to be checked before giving it to main - TIMSK1 &=~(1<=TXBUFFER_SIZE)//head + t=0; + UDR0=tx_buff[t]; + tx_tail=t; + } + if (t == tx_head) + UCSR0B &= ~(1<. + */ + +/** Multiprotocol module configuration file ***/ + +//Uncomment your TX type +#define TX_ER9X //ER9X AETR (988<->2012µs) +//#define TX_DEVO7 //DEVO7 EATR (1120<->1920µs) +//#define TX_SPEKTRUM //Spektrum TAER (1100<->1900µs) +//#define TX_HISKY //HISKY AETR (1100<->1900µs) + +//Uncomment to enable telemetry +#define TELEMETRY + +//Comment a protocol to exclude it from compilation +#define BAYANG_NRF24L01_INO +#define CG023_NRF24L01_INO +#define CX10_NRF24L01_INO +#define DEVO_CYRF6936_INO +#define DSM2_CYRF6936_INO +#define ESKY_NRF24L01_INO +#define FLYSKY_A7105_INO +#define FRSKY_CC2500_INO +#define HISKY_NRF24L01_INO +#define HUBSAN_A7105_INO +#define KN_NRF24L01_INO +#define SLT_NRF24L01_INO +#define SYMAX_NRF24L01_INO +#define V2X2_NRF24L01_INO +#define YD717_NRF24L01_INO +//#define FRSKYX_CC2500_INO + +//Update this table to set which protocol and all associated settings are called for the corresponding dial number +static const PPM_Parameters PPM_prot[15]= +{ +// Protocol Sub protocol RX_Num Power Auto Bind Option + {MODE_FLYSKY, Flysky , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=1 + {MODE_HUBSAN, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=2 + {MODE_FRSKY , 0 , 0 , P_HIGH , NO_AUTOBIND , 0xD7 }, //Dial=3 + {MODE_HISKY , Hisky , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=4 + {MODE_V2X2 , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=5 + {MODE_DSM2 , DSM2 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=6 + {MODE_DEVO , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=7 + {MODE_YD717 , YD717 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=8 + {MODE_KN , WLTOYS , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=9 + {MODE_SYMAX , SYMAX , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=10 + {MODE_SLT , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=11 + {MODE_CX10 , CX10_BLUE , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=12 + {MODE_CG023 , CG023 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=13 + {MODE_BAYANG, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=14 + {MODE_SYMAX , SYMAX5C , 0 , P_HIGH , NO_AUTOBIND , 0 } //Dial=15 +}; +/* Available protocols and associated sub protocols: + MODE_FLYSKY + Flysky + V9X9 + V6X6 + V912 + MODE_HUBSAN + NONE + MODE_FRSKY + NONE + MODE_HISKY + Hisky + HK310 + MODE_V2X2 + NONE + MODE_DSM2 + DSM2 + DSMX + MODE_DEVO + NONE + MODE_YD717 + YD717 + SKYWLKR + SYMAX4 + XINXUN + NIHUI + MODE_KN + WLTOYS + FEILUN + MODE_SYMAX + SYMAX + SYMAX5C + MODE_SLT + NONE + MODE_CX10 + CX10_GREEN + CX10_BLUE + DM007 + Q282 + JC3015_1 + JC3015_2 + MK33041 + MODE_CG023 + CG023 + YD829 + H8_3D + MODE_BAYANG + NONE + MODE_FRSKYX + NONE + MODE_ESKY + NONE + +RX_Num value between 0 and 15 + +Power P_HIGH or P_LOW + +Auto Bind AUTOBIND or NO_AUTOBIND + +Option value between 0 and 255. 0xD7 or 0x00 for Frsky fine tuning. +*/ + +//****************** +//TX definitions with timing endpoints and channels order + +// Turnigy PPM and channels +#if defined(TX_ER9X) +#define PPM_MAX 2140 +#define PPM_MIN 860 +#define PPM_MAX_100 2012 +#define PPM_MIN_100 988 +enum chan_order{ + AILERON =0, + ELEVATOR, + THROTTLE, + RUDDER, + AUX1, + AUX2, + AUX3, + AUX4, + AUX5, + AUX6, + AUX7, + AUX8 +}; +#endif + +// Devo PPM and channels +#if defined(TX_DEVO7) +#define PPM_MAX 2100 +#define PPM_MIN 900 +#define PPM_MAX_100 1920 +#define PPM_MIN_100 1120 +enum chan_order{ + ELEVATOR=0, + AILERON, + THROTTLE, + RUDDER, + AUX1, + AUX2, + AUX3, + AUX4, + AUX5, + AUX6, + AUX7, + AUX8 +}; +#endif + +// SPEKTRUM PPM and channels +#if defined(TX_SPEKTRUM) +#define PPM_MAX 2000 +#define PPM_MIN 1000 +#define PPM_MAX_100 1900 +#define PPM_MIN_100 1100 +enum chan_order{ + THROTTLE=0, + AILERON, + ELEVATOR, + RUDDER, + AUX1, + AUX2, + AUX3, + AUX4, + AUX5, + AUX6, + AUX7, + AUX8 +}; +#endif + +// HISKY +#if defined(TX_HISKY) +#define PPM_MAX 2000 +#define PPM_MIN 1000 +#define PPM_MAX_100 1900 +#define PPM_MIN_100 1100 +enum chan_order{ + AILERON =0, + ELEVATOR, + THROTTLE, + RUDDER, + AUX1, + AUX2, + AUX3, + AUX4, + AUX5, + AUX6, + AUX7, + AUX8 +}; +#endif + +#define PPM_MIN_COMMAND 1250 +#define PPM_SWITCH 1550 +#define PPM_MAX_COMMAND 1750 diff --git a/Multiprotocol/multiprotocol.h b/Multiprotocol/multiprotocol.h index 3fab255..389a862 100644 --- a/Multiprotocol/multiprotocol.h +++ b/Multiprotocol/multiprotocol.h @@ -87,101 +87,21 @@ enum CG023 H8_3D = 2 }; -//****************** -//TX definitions with timing endpoints and channels order -//****************** +#define NONE 0 +#define P_HIGH 1 +#define P_LOW 0 +#define AUTOBIND 1 +#define NO_AUTOBIND 0 -// Turnigy PPM and channels -#if defined(TX_ER9X) -#define PPM_MAX 2140 -#define PPM_MIN 860 -#define PPM_MAX_100 2012 -#define PPM_MIN_100 988 -enum chan_order{ - AILERON =0, - ELEVATOR, - THROTTLE, - RUDDER, - AUX1, - AUX2, - AUX3, - AUX4, - AUX5, - AUX6, - AUX7, - AUX8 +struct PPM_Parameters +{ + uint8_t protocol : 5; + uint8_t sub_proto : 3; + uint8_t rx_num : 4; + uint8_t power : 1; + uint8_t autobind : 1; + uint8_t option; }; -#endif - -// Devo PPM and channels -#if defined(TX_DEVO7) -#define PPM_MAX 2100 -#define PPM_MIN 900 -#define PPM_MAX_100 1920 -#define PPM_MIN_100 1120 -enum chan_order{ - ELEVATOR=0, - AILERON, - THROTTLE, - RUDDER, - AUX1, - AUX2, - AUX3, - AUX4, - AUX5, - AUX6, - AUX7, - AUX8 -}; -#endif - -// SPEKTRUM PPM and channels -#if defined(TX_SPEKTRUM) -#define PPM_MAX 2000 -#define PPM_MIN 1000 -#define PPM_MAX_100 1900 -#define PPM_MIN_100 1100 -enum chan_order{ - THROTTLE=0, - AILERON, - ELEVATOR, - RUDDER, - AUX1, - AUX2, - AUX3, - AUX4, - AUX5, - AUX6, - AUX7, - AUX8 -}; -#endif - -// HISKY -#if defined(TX_HISKY) -#define PPM_MAX 2000 -#define PPM_MIN 1000 -#define PPM_MAX_100 1900 -#define PPM_MIN_100 1100 -enum chan_order{ - AILERON =0, - ELEVATOR, - THROTTLE, - RUDDER, - AUX1, - AUX2, - AUX3, - AUX4, - AUX5, - AUX6, - AUX7, - AUX8 -}; -#endif - -#define PPM_MIN_COMMAND 1250 -#define PPM_SWITCH 1550 -#define PPM_MAX_COMMAND 1750 //******************* //*** Pinouts *** @@ -523,86 +443,5 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- 1843 +100% 2047 +125% Channels bits are concatenated to fit in 22 bytes like in SBUS protocol - - -************************** -8 channels serial protocol -************************** -Serial: 125000 Baud 8n1 _ xxxx xxxx - --- - Channels: - Nbr=8 - 10bits=0..1023 - 0 -125% - 96 -100% - 512 0% - 928 +100% - 1023 +125% - Stream[0] = sub_protocol|BindBit|RangeCheckBit|AutoBindBit; - sub_protocol is 0..31 (bits 0..4) - => Reserved 0 - Flysky 1 - Hubsan 2 - Frsky 3 - Hisky 4 - V2x2 5 - DSM2 6 - Devo 7 - YD717 8 - KN 9 - SymaX 10 - SLT 11 - CX10 12 - CG023 13 - Bayang 14 - FrskyX 15 - ESky 16 - BindBit=> 0x80 1=Bind/0=No - AutoBindBit=> 0x40 1=Yes /0=No - RangeCheck=> 0x20 1=Yes /0=No - Stream[1] = RxNum | Power | Type; - RxNum value is 0..15 (bits 0..3) - Type is 0..7 <<4 (bit 4..6) - sub_protocol==Flysky - Flysky 0 - V9x9 1 - V6x6 2 - V912 3 - sub_protocol==Hisky - Hisky 0 - HK310 1 - sub_protocol==DSM2 - DSM2 0 - DSMX 1 - sub_protocol==YD717 - YD717 0 - SKYWLKR 1 - SYMAX4 2 - XINXUN 3 - NIHUI 4 - sub_protocol==KN - WLTOYS 0 - FEILUN 1 - sub_protocol==SYMAX - SYMAX 0 - SYMAX5C 1 - sub_protocol==CX10 - CX10_GREEN 0 - CX10_BLUE 1 // also compatible with CX10-A, CX12 - DM007 2 - Q282 3 - JC3015_1 4 - JC3015_2 5 - MK33041 6 - sub_protocol==CG023 - CG023 0 - YD829 1 - H8_3D 2 - Power value => 0x80 0=High/1=Low - Stream[2] = option_protocol; - option_protocol value is -127..127 - Stream[i+3] = lowByte(channel[i]) // with i[0..7] - Stream[11] = highByte(channel[0])<<6 | highByte(channel[1])<<4 | highByte(channel[2])<<2 | highByte(channel[3]) - Stream[12] = highByte(channel[4])<<6 | highByte(channel[5])<<4 | highByte(channel[6])<<2 | highByte(channel[7]) - Stream[13] = lowByte(CRC16(Stream[0..12]) */ - + \ No newline at end of file diff --git a/README.md b/README.md index f3eba31..e890937 100644 --- a/README.md +++ b/README.md @@ -26,12 +26,21 @@ The source code is partly based on the Deviation TX project, thanks to all the d ###Using standard PPM output (trainer port) The multiprotocol TX module can be used on any TX with a trainer port. -Channels order is AETR by default but can be changed in the source code. +Channels order is AETR by default but can be changed in the _Config.h. -The protocol selection is done via a dip switch or a rotary dip switch for access to up to 15 different protocols. +The protocol selection is done via a dip switch or a rotary dip switch. ![Screenshot](http://media.digikey.com/photos/Grayhill%20Photos/94HBB16T_sml.jpg) +You can access to up to 15 different protocols and associated settings. + +Settings per selection are located in _Config.h: + - Protocol and type: many main protocols have variants + - RX Num: number your different RXs and make sure only one model will react to the commands + - Power: High or low, enables to lower the power setting of your TX (indoor for example). + - Option: -127..+127 allowing to set specific protocol options. Like for Hubsan to set the video frequency. + - Autobind: Yes or No. At the model selection (or power applied to the TX) a bind sequence will be initiated + ###Using a serial output The multiprotocol TX module takes full advantage of being used on a Turnigy 9X, 9XR, 9XR Pro, Taranis, 9Xtreme, AR9X, ... running [er9x or ersky9X](https://github.com/MikeBland/mbtx/tree/next). (A version for OpenTX is being looked at) @@ -50,8 +59,8 @@ Options are: Notes: - Using this solution does not need any modification of the TX since it uses the TX module slot PPM pin for serial transfer. - - There are 2 versions of serial protocol either 8 or 16 channels. 16 channels is the latest version. Make sure to use the right version based on your version of er9x/ersky9x. - - Channels order is AETR by default but can be changed in the source code. + - There are 2 versions of serial protocol either 8 or 16 channels. 16 channels is the latest and only available version going forward. Make sure to use the right version based on your version of er9x/ersky9x. + - Channels order is AETR by default but can be changed in _Config.h. ###Telemetry Telemetry is available for er9x and ersky9x TXs. @@ -85,7 +94,7 @@ Notes: ###Protocol selection ####Using the dial for PPM input -PPM is only allowing access to a subset of existing protocols & sub_protocols. +PPM is only allowing access to a subset of existing protocols. The default association dial position / protocol is listed below. Dial|Protocol|Sub_protocol|RF Module @@ -109,7 +118,7 @@ Dial|Protocol|Sub_protocol|RF Module Notes: - The dial selection must be done before the power is applied. -- The protocols and subprotocols accessible by the dial can be personalized by modifying the source code. +- The protocols, subprotocols and all other settings can be personalized by modifying the _Config.h file. ####Using serial input with er9x/ersky9x Serial is allowing access to all existing protocols & sub_protocols listed below. @@ -455,7 +464,7 @@ Arduino 1.6.5 Compilation of the code posted here works. So if it doesn't for you this is a problem with your setup, please double check everything before asking. -Multiprotocol.ino header can be modified to compile with/without some protocols, change protocols/sub_protocols associated with dial for PPM input, different channel orders, different channels timing, 8 or 16 channels serial protocol, Telemetry or not, ... +_Config.h file can be modified to compile with/without some protocols, change protocols/sub_protocols/settings associated with dial for PPM input, different channel orders, different channels timing, Telemetry or not, ... ###Upload the code using ISP (In System Programming) It is recommended to use an external programmer like [USBASP](http://www.banggood.com/USBASP-USBISP-3_3-5V-AVR-Downloader-Programmer-With-ATMEGA8-ATMEGA128-p-934425.html) to upload the code in the Atmega328. The programmer should be set to 3.3V or nothing to not supply any over voltage to the multimodule and avoid any damages. From 76ad1d5ef7c23fc5c81792d02fd6a7ec39541906 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 22 Jan 2016 16:30:59 +0100 Subject: [PATCH 002/293] Default PPM protocols and settings --- README.md | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index e890937..0bd3703 100644 --- a/README.md +++ b/README.md @@ -97,24 +97,24 @@ Notes: PPM is only allowing access to a subset of existing protocols. The default association dial position / protocol is listed below. -Dial|Protocol|Sub_protocol|RF Module -----|--------|------------|--------- -0|Select serial|| -1|FLYSKY|Flysky|A7105 -2|HUBSAN|-|A7105 -3|FRSKY|-|CC2500 -4|HISKY|Hisky|NRF24L01 -5|V2X2|-|NRF24L01 -6|DSM2|DSM2|CYRF6936 -7|DEVO|-|CYRF6936 -8|YD717|YD717|NRF24L01 -9|KN|WLTOYS|NRF24L01 -10|SYMAX|SYMAX|NRF24L01 -11|SLT|-|NRF24L01 -12|CX10|CX10_BLUE|NRF24L01 -13|CG023|CG023|NRF24L01 -14|BAYANG|-|NRF24L01 -15|SYMAX|SYMAX5C|NRF24L01 +Dial|Protocol|Sub_protocol|RX Num|Power|Auto Bind|Option|RF Module +----|--------|------------|------|-----|---------|------|--------- +0|Select serial|||||| +1|FLYSKY|Flysky|0|High|No|0|A7105 +2|HUBSAN|-|0|High|No|0|A7105 +3|FRSKY|-|0|High|No|-41|CC2500 +4|HISKY|Hisky|0|High|No|0|NRF24L01 +5|V2X2|-|0|High|No|0|NRF24L01 +6|DSM2|DSM2|0|High|No|0|CYRF6936 +7|DEVO|-|0|High|No|0|CYRF6936 +8|YD717|YD717|0|High|No|0|NRF24L01 +9|KN|WLTOYS|0|High|No|0|NRF24L01 +10|SYMAX|SYMAX|0|High|No|0|NRF24L01 +11|SLT|-|0|High|No|0|NRF24L01 +12|CX10|CX10_BLUE|0|High|No|0|NRF24L01 +13|CG023|CG023|0|High|No|0|NRF24L01 +14|BAYANG|-|0|High|No|0|NRF24L01 +15|SYMAX|SYMAX5C|0|High|No|0|NRF24L01 Notes: - The dial selection must be done before the power is applied. From 95c339ef7427dd5c1a7f252e2f3165c55d4119b4 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 22 Jan 2016 16:33:46 +0100 Subject: [PATCH 003/293] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 0bd3703..2e75263 100644 --- a/README.md +++ b/README.md @@ -428,6 +428,7 @@ An [Arduino pro mini](http://www.banggood.com/Wholesale-New-Ver-Pro-Mini-ATMEGA3 Using stripboard: ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t8214655-87-thumb-uploadfromtaptalk1405598143749.jpg?d=1441459923) +![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t8214656-102-thumb-uploadfromtaptalk1405598152484.jpg?d=1441459924) Using a [home made PCB](http://www.rcgroups.com/forums/showpost.php?p=32645328&postcount=1621): From 2bd8d7ee328377be8ffd2c8b89e08d475845e888 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 22 Jan 2016 16:34:34 +0100 Subject: [PATCH 004/293] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2e75263..44d2c76 100644 --- a/README.md +++ b/README.md @@ -432,8 +432,8 @@ Using stripboard: Using a [home made PCB](http://www.rcgroups.com/forums/showpost.php?p=32645328&postcount=1621): -![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8226719-72-thumb-IMG_20150715_230024065.jpg?d=1441816456) ![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8226720-197-thumb-IMG_20150715_230603155.jpg?d=1441816457) +![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8226719-72-thumb-IMG_20150715_230024065.jpg?d=1441816456) or build your own board using [SMD components](http://www.rcgroups.com/forums/showpost.php?p=31064232&postcount=1020) and an [associated PCB](https://oshpark.com/shared_projects/MaGYDg0y): From 93300c68215541f424a87acef41b1500289919c6 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sat, 23 Jan 2016 09:03:00 +0100 Subject: [PATCH 005/293] Fix: removed reset of nrf24l01 if not previously used... --- Multiprotocol/Multiprotocol.ino | 46 +++++++++++++++++---------------- 1 file changed, 24 insertions(+), 22 deletions(-) diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index ea19440..564a171 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -149,8 +149,7 @@ void setup() // Read or create protocol id MProtocol_id_master=random_id(10,false); - - + //Protocol and interrupts initialization if(mode_select != MODE_SERIAL) { // PPM @@ -469,26 +468,29 @@ static void update_serial_data() static void module_reset() { - remote_callback = 0; - switch(prev_protocol) - { - case MODE_FLYSKY: - case MODE_HUBSAN: - A7105_Reset(); - break; - case MODE_FRSKY: - case MODE_FRSKYX: - CC2500_Reset(); - break; - break; - case MODE_DSM2: - case MODE_DEVO: - CYRF_Reset(); - break; - default: - // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY - NRF24L01_Reset(); - break; + if(remote_callback) + { // a protocol was loaded, reset the module used + remote_callback = 0; + switch(prev_protocol) + { + case MODE_FLYSKY: + case MODE_HUBSAN: + A7105_Reset(); + break; + case MODE_FRSKY: + case MODE_FRSKYX: + CC2500_Reset(); + break; + break; + case MODE_DSM2: + case MODE_DEVO: + CYRF_Reset(); + break; + default: + // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY + NRF24L01_Reset(); + break; + } } } From b3ca0beead91bcc778683d83798c15566eb2524f Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sat, 23 Jan 2016 12:59:28 +0100 Subject: [PATCH 006/293] Fix typo in ESky --- Multiprotocol/ESky_nrf24l01.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Multiprotocol/ESky_nrf24l01.ino b/Multiprotocol/ESky_nrf24l01.ino index 77452a3..f83128f 100644 --- a/Multiprotocol/ESky_nrf24l01.ino +++ b/Multiprotocol/ESky_nrf24l01.ino @@ -41,8 +41,8 @@ static void ESKY_init(uint8_t bind) if (bind) { NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // 3-byte RX/TX address for bind packets - NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"x00x00x00", 3); - NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"x00x00x00", 3); + NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t*)"\x00\x00\x00", 3); + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"\x00\x00\x00", 3); } else ESKY_set_data_address(); From 644c10e99454723bf51b6383665bb3c7754dedd2 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 25 Jan 2016 17:07:37 +0100 Subject: [PATCH 007/293] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 44d2c76..bf8d4d5 100644 --- a/README.md +++ b/README.md @@ -28,9 +28,11 @@ The multiprotocol TX module can be used on any TX with a trainer port. Channels order is AETR by default but can be changed in the _Config.h. -The protocol selection is done via a dip switch or a rotary dip switch. +The protocol selection is done via a dip switch, rotary dip switch or scsi ID selector. +![Screenshot](http://media.digikey.com/photos/CTS%20Photos/206-4,%20206-4ST_sml.jpg) ![Screenshot](http://media.digikey.com/photos/Grayhill%20Photos/94HBB16T_sml.jpg) +![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8637216-7-thumb-SCSI%20ID%20selector.jpg?d=1453737244) You can access to up to 15 different protocols and associated settings. From 5d26357025786347171d1d9188181939b081628c Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sun, 24 Jan 2016 17:15:02 +0100 Subject: [PATCH 008/293] Couple of edits... --- Multiprotocol/CG023_nrf24l01.ino | 8 ++++---- Multiprotocol/CX10_nrf24l01.ino | 2 +- Multiprotocol/Multiprotocol.ino | 5 ++--- Multiprotocol/NRF24l01_SPI.ino | 2 +- Multiprotocol/multiprotocol.h | 2 +- 5 files changed, 9 insertions(+), 10 deletions(-) diff --git a/Multiprotocol/CG023_nrf24l01.ino b/Multiprotocol/CG023_nrf24l01.ino index 7236dd0..adb6539 100644 --- a/Multiprotocol/CG023_nrf24l01.ino +++ b/Multiprotocol/CG023_nrf24l01.ino @@ -255,10 +255,10 @@ static void CG023_initialize_txid() rx_tx_addr[2] = rx_tx_addr[2] % 0x20; rx_tx_addr[3] = rx_tx_addr[3] % 0x11; - hopping_frequency[0] = 0x06 + (rx_tx_addr[0]&0x0f); - hopping_frequency[1] = 0x15 + (rx_tx_addr[1]&0x0f); - hopping_frequency[2] = 0x24 + (rx_tx_addr[2]&0x0f); - hopping_frequency[3] = 0x33 + (rx_tx_addr[3]&0x0f); + hopping_frequency[0] = 0x06 + ((rx_tx_addr[0]&0x0f) % 0x0f); + hopping_frequency[1] = 0x15 + ((rx_tx_addr[1]&0x0f) % 0x0f); + hopping_frequency[2] = 0x24 + ((rx_tx_addr[2]&0x0f) % 0x0f); + hopping_frequency[3] = 0x33 + ((rx_tx_addr[3]&0x0f) % 0x0f); } else { // CG023 and YD829 diff --git a/Multiprotocol/CX10_nrf24l01.ino b/Multiprotocol/CX10_nrf24l01.ino index 10b9437..6f6c816 100644 --- a/Multiprotocol/CX10_nrf24l01.ino +++ b/Multiprotocol/CX10_nrf24l01.ino @@ -199,7 +199,7 @@ uint16_t CX10_callback() { NRF24L01_SetTxRxMode(TXRX_OFF); NRF24L01_SetTxRxMode(TX_EN); CX10_Write_Packet(1); - delay(1); // used to be 300µs in deviation but not working so 1ms now + delayMicroseconds(400); // 300µs in deviation but not working so using 400µs instead // switch to RX mode NRF24L01_SetTxRxMode(TXRX_OFF); NRF24L01_FlushRx(); diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 564a171..543a12c 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -469,7 +469,7 @@ static void update_serial_data() static void module_reset() { if(remote_callback) - { // a protocol was loaded, reset the module used + { // previous protocol loaded remote_callback = 0; switch(prev_protocol) { @@ -486,8 +486,7 @@ static void module_reset() case MODE_DEVO: CYRF_Reset(); break; - default: - // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY + default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY NRF24L01_Reset(); break; } diff --git a/Multiprotocol/NRF24l01_SPI.ino b/Multiprotocol/NRF24l01_SPI.ino index 200365e..c14f5d5 100644 --- a/Multiprotocol/NRF24l01_SPI.ino +++ b/Multiprotocol/NRF24l01_SPI.ino @@ -271,7 +271,7 @@ static const uint8_t xn297_scramble[] = { static const uint16_t xn297_crc_xorout[] = { 0x0000, 0x3448, 0x9BA7, 0x8BBB, 0x85E1, 0x3E8C, // 1st entry is missing, probably never needed - 0x451E, 0x18E6, 0x6B24, 0xE7AB, 0x3828, 0x8148, // it's used for 3-byte address w/ 0 byte payload only + 0x451E, 0x18E6, 0x6B24, 0xE7AB, 0x3828, 0x814B, // it's used for 3-byte address w/ 0 byte payload only 0xD461, 0xF494, 0x2503, 0x691D, 0xFE8B, 0x9BA7, 0x8B17, 0x2920, 0x8B5F, 0x61B1, 0xD391, 0x7401, 0x2138, 0x129F, 0xB3A0, 0x2988}; diff --git a/Multiprotocol/multiprotocol.h b/Multiprotocol/multiprotocol.h index 389a862..addda61 100644 --- a/Multiprotocol/multiprotocol.h +++ b/Multiprotocol/multiprotocol.h @@ -28,7 +28,7 @@ enum PROTOCOLS MODE_DEVO =7, // =>CYRF6936 / DEVO protocol MODE_YD717 = 8, // =>NRF24L01 / YD717 protocol (CX10 red pcb) MODE_KN = 9, // =>NRF24L01 / KN protocol - MODE_SYMAX = 10, // =>NRF24L01 / SYMAX protocol (SYMAX4 working) + MODE_SYMAX = 10, // =>NRF24L01 / SYMAX protocol MODE_SLT = 11, // =>NRF24L01 / SLT protocol MODE_CX10 = 12, // =>NRF24L01 / CX-10 protocol MODE_CG023 = 13, // =>NRF24L01 / CG023 protocol From a41bfabede975b9a31e8296a7063dd5ab11c3ed5 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 25 Jan 2016 17:22:47 +0100 Subject: [PATCH 009/293] HK310: 2 packets per 5ms + Core: reset CC2500 at boot --- Multiprotocol/Hisky_nrf24l01.ino | 6 +++++- Multiprotocol/Multiprotocol.ino | 4 +++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/Multiprotocol/Hisky_nrf24l01.ino b/Multiprotocol/Hisky_nrf24l01.ino index 4076f7a..d413cbe 100644 --- a/Multiprotocol/Hisky_nrf24l01.ino +++ b/Multiprotocol/Hisky_nrf24l01.ino @@ -144,10 +144,14 @@ uint16_t hisky_cb() NRF24L01_SetPower(); phase=2; break; + case 3: + if (! bind_counter) + NRF24L01_WritePayload(packet,10); // 2 packets per 5ms + break; case 4: phase=6; break; - case 7: // build packet and send failsafe every 100ms + case 7: // build packet with failsafe every 100ms convert_channel_HK310(hopping_frequency_no!=0?RUDDER:AUX2,&packet[0],&packet[1]); convert_channel_HK310(hopping_frequency_no!=0?THROTTLE:AUX3,&packet[2],&packet[3]); convert_channel_HK310(hopping_frequency_no!=0?AUX1:AUX4,&packet[4],&packet[5]); diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 543a12c..89084f1 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -150,6 +150,9 @@ void setup() // Read or create protocol id MProtocol_id_master=random_id(10,false); + //Init RF modules + CC2500_Reset(); + //Protocol and interrupts initialization if(mode_select != MODE_SERIAL) { // PPM @@ -481,7 +484,6 @@ static void module_reset() case MODE_FRSKYX: CC2500_Reset(); break; - break; case MODE_DSM2: case MODE_DEVO: CYRF_Reset(); From 9140c426c4b1e7addba65cf1af2b6ecceec4da77 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 25 Jan 2016 18:14:56 +0100 Subject: [PATCH 010/293] New protocol CX-10/Q242 --- Multiprotocol/CX10_nrf24l01.ino | 54 ++++++++++++++++++++++----------- Multiprotocol/_Config.h | 1 + Multiprotocol/multiprotocol.h | 4 ++- README.md | 2 ++ 4 files changed, 43 insertions(+), 18 deletions(-) diff --git a/Multiprotocol/CX10_nrf24l01.ino b/Multiprotocol/CX10_nrf24l01.ino index 6f6c816..ff7073b 100644 --- a/Multiprotocol/CX10_nrf24l01.ino +++ b/Multiprotocol/CX10_nrf24l01.ino @@ -90,24 +90,36 @@ static void CX10_Write_Packet(uint8_t bind) if(Servo_AUX4) flags |= 0x08; // Channel 8 - video break; case Q282: + case Q242: + memcpy(&packet[15], "\x10\x10\xaa\xaa\x00\x00", 6); //FLIP|LED|PICTURE|VIDEO|HEADLESS|RTH|XCAL|YCAL if(Servo_AUX1) flags2 =0x80; // Channel 5 - FLIP if(Servo_AUX2) flags2|=0x40; // Channel 6 - LED - if(Servo_AUX3) flags2|=0x10; // Channel 7 - picture - if(Servo_AUX4) // Channel 8 - video - { - if (!(video_state & 0x20)) video_state ^= 0x21; - } - else - if (video_state & 0x20) video_state &= 0x01; - flags2 |= video_state; if(Servo_AUX5) flags2|=0x08; // Channel 9 - HEADLESS - flags=3; + if(sub_protocol==Q282) + { + if(Servo_AUX3) flags2|=0x10; // Channel 7 - picture + if(Servo_AUX4) // Channel 8 - video + { + if (!(video_state & 0x20)) video_state ^= 0x21; + } + else + if (video_state & 0x20) video_state &= 0x01; + flags2 |= video_state; + flags=3; + } + else + { + if(Servo_AUX3) flags2|=0x01; // Channel 7 - picture + if(Servo_AUX4) flags2|=0x10; // Channel 8 - video + flags=2; + packet[17]=0x00; + packet[18]=0x00; + } if(Servo_AUX6) flags |=0x80; // Channel 10 - RTH if(Servo_AUX7) flags2|=0x04; // Channel 11 - XCAL if(Servo_AUX8) flags2|=0x02; // Channel 12 - YCAL - memcpy(&packet[15], "\x10\x10\xaa\xaa\x00\x00", 6); break; case DM007: //FLIP|MODE|PICTURE|VIDEO|HEADLESS @@ -225,12 +237,20 @@ static void initialize_txid() hopping_frequency[3] = 0x4c; } else - { - hopping_frequency[0] = 0x03 + (rx_tx_addr[0] & 0x0F); - hopping_frequency[1] = 0x16 + (rx_tx_addr[0] >> 4); - hopping_frequency[2] = 0x2D + (rx_tx_addr[1] & 0x0F); - hopping_frequency[3] = 0x40 + (rx_tx_addr[1] >> 4); - } + if(sub_protocol==Q242) + { + hopping_frequency[0] = 0x48; + hopping_frequency[1] = 0x4a; + hopping_frequency[2] = 0x4c; + hopping_frequency[3] = 0x4e; + } + else + { + hopping_frequency[0] = 0x03 + (rx_tx_addr[0] & 0x0F); + hopping_frequency[1] = 0x16 + (rx_tx_addr[0] >> 4); + hopping_frequency[2] = 0x2D + (rx_tx_addr[1] & 0x0F); + hopping_frequency[3] = 0x40 + (rx_tx_addr[1] >> 4); + } } uint16_t initCX10(void) @@ -247,7 +267,7 @@ uint16_t initCX10(void) } else { - if(sub_protocol==Q282) + if(sub_protocol==Q282||sub_protocol==Q242) packet_length = Q282_PACKET_SIZE; else packet_length = CX10_PACKET_SIZE; diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 4e6797f..7eaf8d4 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -104,6 +104,7 @@ static const PPM_Parameters PPM_prot[15]= JC3015_1 JC3015_2 MK33041 + Q242 MODE_CG023 CG023 YD829 diff --git a/Multiprotocol/multiprotocol.h b/Multiprotocol/multiprotocol.h index addda61..2eec052 100644 --- a/Multiprotocol/multiprotocol.h +++ b/Multiprotocol/multiprotocol.h @@ -78,7 +78,8 @@ enum CX10 Q282=3, JC3015_1=4, JC3015_2=5, - MK33041=6 + MK33041=6, + Q242=7 }; enum CG023 { @@ -428,6 +429,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- JC3015_1 4 JC3015_2 5 MK33041 6 + Q242 7 sub_protocol==CG023 CG023 0 YD829 1 diff --git a/README.md b/README.md index bf8d4d5..7ad86b4 100644 --- a/README.md +++ b/README.md @@ -163,6 +163,7 @@ CX10||NRF24L01 |JC3015_1 |JC3015_2 |MK33041 + |Q242 CG023||NRF24L01 |CG023 |YD829 @@ -251,6 +252,7 @@ CH5|CH6|CH7|CH8|CH9 FLIP|MODE|PICTURE|VIDEO|HEADLESS #####Sub_protocol CX10_Q282 +#####Sub_protocol CX10_Q242 CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 ---|---|---|---|---|---|---|--- From ee6eed5ac5d0c99b352ec6f4a1d18e74e36e6232 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 25 Jan 2016 18:16:20 +0100 Subject: [PATCH 011/293] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 7ad86b4..cbcb98b 100644 --- a/README.md +++ b/README.md @@ -251,8 +251,7 @@ CH5|CH6|CH7|CH8|CH9 ---|---|---|---|--- FLIP|MODE|PICTURE|VIDEO|HEADLESS -#####Sub_protocol CX10_Q282 -#####Sub_protocol CX10_Q242 +#####Sub_protocol CX10_Q282 and CX10_Q242 CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 ---|---|---|---|---|---|---|--- From ae0478a7e9e9067bf63b3559426c02e2b2b0321e Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 26 Jan 2016 13:46:22 +0100 Subject: [PATCH 012/293] Frsky telemetry update --- Multiprotocol/DSM2_cyrf6936.ino | 9 +++------ Multiprotocol/FrSky_cc2500.ino | 14 ++++++++++---- Multiprotocol/Multiprotocol.ino | 12 +++++++++--- Multiprotocol/iface_cc2500.h | 10 ++++++++++ 4 files changed, 32 insertions(+), 13 deletions(-) diff --git a/Multiprotocol/DSM2_cyrf6936.ino b/Multiprotocol/DSM2_cyrf6936.ino index 66b582a..ab1e781 100644 --- a/Multiprotocol/DSM2_cyrf6936.ino +++ b/Multiprotocol/DSM2_cyrf6936.ino @@ -110,7 +110,6 @@ uint16_t cyrf_state; uint8_t crcidx; uint8_t binding; uint16_t crc; -uint8_t model; /* #ifdef USE_FIXED_MFGID @@ -128,7 +127,7 @@ static void build_bind_packet() packet[0] = crc >> 8; packet[1] = crc & 0xff; packet[2] = 0xff ^ cyrfmfg_id[2]; - packet[3] = (0xff ^ cyrfmfg_id[3]) + model; + packet[3] = (0xff ^ cyrfmfg_id[3]) + RX_num; packet[4] = packet[0]; packet[5] = packet[1]; packet[6] = packet[2]; @@ -187,13 +186,13 @@ static void build_data_packet(uint8_t upper)// if (sub_protocol==DSMX) { packet[0] = cyrfmfg_id[2]; - packet[1] = cyrfmfg_id[3] + model; + packet[1] = cyrfmfg_id[3] + RX_num; bits=11; } else { packet[0] = (0xff ^ cyrfmfg_id[2]); - packet[1] = (0xff ^ cyrfmfg_id[3]) + model; + packet[1] = (0xff ^ cyrfmfg_id[3]) + RX_num; bits=10; } // @@ -513,8 +512,6 @@ uint16_t initDsm2() sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;//Ok data_col = 7 - sop_col;//ok - model=MProtocol_id-MProtocol_id_master; // RxNum for serial or 0 for ppm - CYRF_SetTxRxMode(TX_EN); // if(IS_AUTOBIND_FLAG_on) diff --git a/Multiprotocol/FrSky_cc2500.ino b/Multiprotocol/FrSky_cc2500.ino index 40b0f6c..ac61452 100644 --- a/Multiprotocol/FrSky_cc2500.ino +++ b/Multiprotocol/FrSky_cc2500.ino @@ -18,9 +18,11 @@ #include "iface_cc2500.h" //##########Variables######## -uint32_t state; -uint8_t len; +//uint32_t state; +//uint8_t len; +uint8_t telemetry_counter=0; +/* enum { FRSKY_BIND = 0, FRSKY_BIND_DONE = 1000, @@ -30,6 +32,7 @@ enum { FRSKY_DATA4, FRSKY_DATA5 }; +*/ uint16_t initFrSky_2way() { @@ -124,6 +127,8 @@ static void check_telemetry(uint8_t *pkt,uint8_t len) for (uint8_t i=3;i0) + telemetry_counter=(telemetry_counter+1)%32; } } @@ -231,7 +236,7 @@ static void frsky2way_build_bind_packet() packet[17] = 0x01; } -uint8_t telemetry_counter=0; + static void frsky2way_data_frame() {//pachet[4] is telemetry user frame counter(hub) @@ -241,7 +246,8 @@ static void frsky2way_data_frame() packet[1] = rx_tx_addr[3]; packet[2] = rx_tx_addr[2]; packet[3] = counter;// - packet[4] = pkt[6]?(telemetry_counter++)%32:0; + packet[4]=telemetry_counter; + packet[5] = 0x01; // packet[10] = 0; diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 89084f1..5299ef4 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -65,6 +65,10 @@ uint8_t hopping_frequency_no=0; uint8_t rf_ch_num; uint8_t throttle, rudder, elevator, aileron; uint8_t flags; +// +uint32_t state; +uint8_t len; +uint8_t RX_num; // Mode_select variables uint8_t mode_select; @@ -159,7 +163,8 @@ void setup() mode_select--; cur_protocol[0] = PPM_prot[mode_select].protocol; sub_protocol = PPM_prot[mode_select].sub_proto; - MProtocol_id = PPM_prot[mode_select].rx_num + MProtocol_id_master; + RX_num = PPM_prot[mode_select].rx_num; + MProtocol_id = RX_num + MProtocol_id_master; option = PPM_prot[mode_select].option; if(PPM_prot[mode_select].power) POWER_FLAG_on; if(PPM_prot[mode_select].autobind) AUTOBIND_FLAG_on; @@ -208,7 +213,7 @@ void loop() } update_led_status(); #if defined(TELEMETRY) - if(((cur_protocol[0]&0x1F)==MODE_FRSKY)||((cur_protocol[0]&0x1F)==MODE_HUBSAN)) + if( ((cur_protocol[0]&0x1F)==MODE_FRSKY) || ((cur_protocol[0]&0x1F)==MODE_HUBSAN) || ((cur_protocol[0]&0x1F)==MODE_FRSKYX) ) frskyUpdate(); #endif if (remote_callback != 0) @@ -445,7 +450,8 @@ static void update_serial_data() cur_protocol[1] = rx_ok_buff[1]&0x7F; //store current protocol CHANGE_PROTOCOL_FLAG_on; //change protocol sub_protocol=(rx_ok_buff[1]>>4)& 0x07; //subprotocol no (0-7) bits 4-6 - MProtocol_id=MProtocol_id_master+(rx_ok_buff[1]& 0x0F); //personalized RX bind + rx num // rx_num bits 0---3 + RX_num=rx_ok_buff[1]& 0x0F; + MProtocol_id=MProtocol_id_master+RX_num; //personalized RX bind + rx num // rx_num bits 0---3 } else if( ((rx_ok_buff[0]&0x80)!=0) && ((cur_protocol[0]&0x80)==0) ) // Bind flag has been set diff --git a/Multiprotocol/iface_cc2500.h b/Multiprotocol/iface_cc2500.h index 8bcd506..cb7b623 100644 --- a/Multiprotocol/iface_cc2500.h +++ b/Multiprotocol/iface_cc2500.h @@ -16,6 +16,16 @@ #ifndef _IFACE_CC2500_H_ #define _IFACE_CC2500_H_ +enum { + FRSKY_BIND = 0, + FRSKY_BIND_DONE = 1000, + FRSKY_DATA1, + FRSKY_DATA2, + FRSKY_DATA3, + FRSKY_DATA4, + FRSKY_DATA5 +}; + enum { CC2500_00_IOCFG2 = 0x00, // GDO2 output pin configuration CC2500_01_IOCFG1 = 0x01, // GDO1 output pin configuration From a689ce4de94c7f84a5c524e78b03335ca31cc10e Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 26 Jan 2016 22:33:17 +0100 Subject: [PATCH 013/293] Fix: Update_aux_flags missplaced for PPM input --- Multiprotocol/FrSky_cc2500.ino | 6 +++--- Multiprotocol/Multiprotocol.ino | 7 ++++--- 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/Multiprotocol/FrSky_cc2500.ino b/Multiprotocol/FrSky_cc2500.ino index ac61452..5f90a46 100644 --- a/Multiprotocol/FrSky_cc2500.ino +++ b/Multiprotocol/FrSky_cc2500.ino @@ -91,7 +91,7 @@ uint16_t ReadFrSky_2way() if (state == FRSKY_DATA1) { len = cc2500_readReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F; - if (len)//20 bytes + if (len<=MAX_PKT)//27 bytes { cc2500_readFifo(pkt, len); //received telemetry packets #if defined(TELEMETRY) @@ -125,10 +125,10 @@ static void check_telemetry(uint8_t *pkt,uint8_t len) else { for (uint8_t i=3;i0) - telemetry_counter=(telemetry_counter+1)%32; + telemetry_counter=(telemetry_counter+1)%32; } } diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 5299ef4..d299734 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -90,8 +90,9 @@ uint8_t prev_protocol=0; // Telemetry #if defined(TELEMETRY) -uint8_t pkt[27];//telemetry receiving packets -uint8_t pktt[27];//telemetry receiving packets +#define MAX_PKT 27 +uint8_t pkt[MAX_PKT];//telemetry receiving packets +uint8_t pktt[MAX_PKT];//telemetry receiving packets volatile uint8_t tx_head; volatile uint8_t tx_tail; uint8_t v_lipo; @@ -207,8 +208,8 @@ void loop() cli(); // disable global int Servo_data[i]=PPM_data[i]; sei(); // enable global int - update_aux_flags(); } + update_aux_flags(); PPM_FLAG_off; // wait for next frame before update } update_led_status(); From b50bedef398535c09262d186226a27fb2bd60eba Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 27 Jan 2016 17:57:33 +0100 Subject: [PATCH 014/293] Hub telemetry and fix compilation warnings/errors if protocols are commented --- Multiprotocol/Bayang_nrf24l01.ino | 6 +- Multiprotocol/CG023_nrf24l01.ino | 6 +- Multiprotocol/CX10_nrf24l01.ino | 6 +- Multiprotocol/DSM2_cyrf6936.ino | 48 ++-- Multiprotocol/Devo_cyrf6936.ino | 22 +- Multiprotocol/ESky_nrf24l01.ino | 8 +- Multiprotocol/FlySky_a7105.ino | 4 +- Multiprotocol/FrSky_cc2500.ino | 308 +++++++++++------------ Multiprotocol/Hisky_nrf24l01.ino | 10 +- Multiprotocol/Hubsan_a7105.ino | 16 +- Multiprotocol/KN_nrf24l01.ino | 397 +++++++++++++++--------------- Multiprotocol/Multiprotocol.ino | 15 +- Multiprotocol/SLT_nrf24l01.ino | 14 +- Multiprotocol/Symax_nrf24l01.ino | 18 +- Multiprotocol/V2X2_nrf24l01.ino | 10 +- Multiprotocol/YD717_nrf24l01.ino | 8 +- Multiprotocol/_Config.h | 1 + Multiprotocol/telemetry.h | 164 +++++++++--- 18 files changed, 578 insertions(+), 483 deletions(-) diff --git a/Multiprotocol/Bayang_nrf24l01.ino b/Multiprotocol/Bayang_nrf24l01.ino index 782d3ad..84907b4 100644 --- a/Multiprotocol/Bayang_nrf24l01.ino +++ b/Multiprotocol/Bayang_nrf24l01.ino @@ -38,7 +38,7 @@ enum BAYANG_FLAGS { BAYANG_FLAG_INVERTED = 0x80 // inverted flight on Floureon H101 }; -static void BAYANG_send_packet(uint8_t bind) +static void __attribute__((unused)) BAYANG_send_packet(uint8_t bind) { uint8_t i; if (bind) @@ -112,7 +112,7 @@ static void BAYANG_send_packet(uint8_t bind) NRF24L01_SetPower(); // Set tx_power } -static void BAYANG_init() +static void __attribute__((unused)) BAYANG_init() { NRF24L01_Initialize(); NRF24L01_SetTxRxMode(TX_EN); @@ -148,7 +148,7 @@ uint16_t BAYANG_callback() return BAYANG_PACKET_PERIOD; } -static void BAYANG_initialize_txid() +static void __attribute__((unused)) BAYANG_initialize_txid() { //Could be using txid[0..2] but using rx_tx_addr everywhere instead... hopping_frequency[0]=0; diff --git a/Multiprotocol/CG023_nrf24l01.ino b/Multiprotocol/CG023_nrf24l01.ino index adb6539..6810652 100644 --- a/Multiprotocol/CG023_nrf24l01.ino +++ b/Multiprotocol/CG023_nrf24l01.ino @@ -70,7 +70,7 @@ enum H8_3D_FLAGS_2 { H8_3D_FLAG_CALIBRATE = 0x20, // accelerometer calibration }; -static void CG023_send_packet(uint8_t bind) +static void __attribute__((unused)) CG023_send_packet(uint8_t bind) { // throttle : 0x00 - 0xFF throttle=convert_channel_8b(THROTTLE); @@ -205,7 +205,7 @@ static void CG023_send_packet(uint8_t bind) NRF24L01_SetPower(); // Set tx_power } -static void CG023_init() +static void __attribute__((unused)) CG023_init() { NRF24L01_Initialize(); NRF24L01_SetTxRxMode(TX_EN); @@ -246,7 +246,7 @@ uint16_t CG023_callback() return H8_3D_PACKET_PERIOD; } -static void CG023_initialize_txid() +static void __attribute__((unused)) CG023_initialize_txid() { if(sub_protocol==H8_3D) { diff --git a/Multiprotocol/CX10_nrf24l01.ino b/Multiprotocol/CX10_nrf24l01.ino index ff7073b..044c20c 100644 --- a/Multiprotocol/CX10_nrf24l01.ino +++ b/Multiprotocol/CX10_nrf24l01.ino @@ -46,7 +46,7 @@ enum { CX10_DATA }; -static void CX10_Write_Packet(uint8_t bind) +static void __attribute__((unused)) CX10_Write_Packet(uint8_t bind) { uint8_t offset = 0; if(sub_protocol == CX10_BLUE) @@ -166,7 +166,7 @@ static void CX10_Write_Packet(uint8_t bind) NRF24L01_SetPower(); } -static void CX10_init() +static void __attribute__((unused)) CX10_init() { NRF24L01_Initialize(); NRF24L01_SetTxRxMode(TX_EN); @@ -226,7 +226,7 @@ uint16_t CX10_callback() { return packet_period; } -static void initialize_txid() +static void __attribute__((unused)) initialize_txid() { rx_tx_addr[1]%= 0x30; if(sub_protocol==Q282) diff --git a/Multiprotocol/DSM2_cyrf6936.ino b/Multiprotocol/DSM2_cyrf6936.ino index ab1e781..e6769a6 100644 --- a/Multiprotocol/DSM2_cyrf6936.ino +++ b/Multiprotocol/DSM2_cyrf6936.ino @@ -120,7 +120,7 @@ const uint8_t cyrfmfg_id[6] = {0xd4, 0x62, 0xd6, 0xad, 0xd3, 0xff}; //dx6i #endif */ -static void build_bind_packet() +static void __attribute__((unused)) build_bind_packet() { uint8_t i; uint16_t sum = 384 - 0x10;// @@ -153,7 +153,23 @@ static void build_bind_packet() packet[15] = sum & 0xff; } -static void build_data_packet(uint8_t upper)// +static uint8_t __attribute__((unused)) PROTOCOL_SticksMoved(uint8_t init) +{ +#define STICK_MOVEMENT 15*(PPM_MAX-PPM_MIN)/100 // defines when the bind dialog should be interrupted (stick movement STICK_MOVEMENT %) + static uint16_t ele_start, ail_start; + uint16_t ele = Servo_data[ELEVATOR];//CHAN_ReadInput(MIXER_MapChannel(INP_ELEVATOR)); + uint16_t ail = Servo_data[AILERON];//CHAN_ReadInput(MIXER_MapChannel(INP_AILERON)); + if(init) { + ele_start = ele; + ail_start = ail; + return 0; + } + uint16_t ele_diff = ele_start - ele;//abs(ele_start - ele); + uint16_t ail_diff = ail_start - ail;//abs(ail_start - ail); + return ((ele_diff + ail_diff) > STICK_MOVEMENT);// +} + +static void __attribute__((unused)) build_data_packet(uint8_t upper)// { #if DSM2_NUM_CHANNELS==4 const uint8_t ch_map[] = {0, 1, 2, 3, 0xff, 0xff, 0xff}; //Guess @@ -251,23 +267,7 @@ static void build_data_packet(uint8_t upper)// } } -static uint8_t PROTOCOL_SticksMoved(uint8_t init) -{ -#define STICK_MOVEMENT 15*(PPM_MAX-PPM_MIN)/100 // defines when the bind dialog should be interrupted (stick movement STICK_MOVEMENT %) - static uint16_t ele_start, ail_start; - uint16_t ele = Servo_data[ELEVATOR];//CHAN_ReadInput(MIXER_MapChannel(INP_ELEVATOR)); - uint16_t ail = Servo_data[AILERON];//CHAN_ReadInput(MIXER_MapChannel(INP_AILERON)); - if(init) { - ele_start = ele; - ail_start = ail; - return 0; - } - uint16_t ele_diff = ele_start - ele;//abs(ele_start - ele); - uint16_t ail_diff = ail_start - ail;//abs(ail_start - ail); - return ((ele_diff + ail_diff) > STICK_MOVEMENT);// -} - -static uint8_t get_pn_row(uint8_t channel) +static uint8_t __attribute__((unused)) get_pn_row(uint8_t channel) { return (sub_protocol == DSMX ? (channel - 2) % 5 : channel % 5); } @@ -299,7 +299,7 @@ const uint8_t init_vals[][2] = { {CYRF_01_TX_LENGTH, 0x10}, //16byte packet }; -static void cyrf_config() +static void __attribute__((unused)) cyrf_config() { for(uint8_t i = 0; i < sizeof(init_vals) / 2; i++) CYRF_WriteRegister(init_vals[i][0], init_vals[i][1]); @@ -307,7 +307,7 @@ static void cyrf_config() CYRF_ConfigRFChannel(0x61); } -static void initialize_bind_state() +static void __attribute__((unused)) initialize_bind_state() { const uint8_t pn_bind[] = { 0xc6,0x94,0x22,0xfe,0x48,0xe6,0x57,0x4e }; uint8_t data_code[32]; @@ -341,13 +341,13 @@ const uint8_t data_vals[][2] = { {CYRF_10_FRAMING_CFG, 0xea}, }; -static void cyrf_configdata() +static void __attribute__((unused)) cyrf_configdata() { for(uint8_t i = 0; i < sizeof(data_vals) / 2; i++) CYRF_WriteRegister(data_vals[i][0], data_vals[i][1]); } -static void set_sop_data_crc() +static void __attribute__((unused)) set_sop_data_crc() { uint8_t pn_row = get_pn_row(hopping_frequency[chidx]); //printf("Ch: %d Row: %d SOP: %d Data: %d\n", ch[chidx], pn_row, sop_col, data_col); @@ -362,7 +362,7 @@ static void set_sop_data_crc() crcidx = !crcidx; } -static void calc_dsmx_channel() +static void __attribute__((unused)) calc_dsmx_channel() { uint8_t idx = 0; uint32_t id = ~(((uint32_t)cyrfmfg_id[0] << 24) | ((uint32_t)cyrfmfg_id[1] << 16) | ((uint32_t)cyrfmfg_id[2] << 8) | (cyrfmfg_id[3] << 0)); diff --git a/Multiprotocol/Devo_cyrf6936.ino b/Multiprotocol/Devo_cyrf6936.ino index 3e8ec7a..e569cb9 100644 --- a/Multiprotocol/Devo_cyrf6936.ino +++ b/Multiprotocol/Devo_cyrf6936.ino @@ -66,7 +66,7 @@ uint8_t ch_idx; uint8_t use_fixed_id; uint8_t failsafe_pkt; -static void scramble_pkt() +static void __attribute__((unused)) scramble_pkt() { #ifdef NO_SCRAMBLE return; @@ -77,7 +77,7 @@ static void scramble_pkt() #endif } -static void add_pkt_suffix() +static void __attribute__((unused)) add_pkt_suffix() { uint8_t bind_state; if (use_fixed_id) @@ -97,7 +97,7 @@ static void add_pkt_suffix() packet[15] = (fixed_id >> 16) & 0xff; } -static void build_beacon_pkt(uint8_t upper) +static void __attribute__((unused)) build_beacon_pkt(uint8_t upper) { packet[0] = ((DEVO_NUM_CHANNELS << 4) | 0x07); // uint8_t enable = 0; @@ -116,7 +116,7 @@ static void build_beacon_pkt(uint8_t upper) add_pkt_suffix(); } -static void build_bind_pkt() +static void __attribute__((unused)) build_bind_pkt() { packet[0] = (DEVO_NUM_CHANNELS << 4) | 0x0a; packet[1] = bind_counter & 0xff; @@ -136,7 +136,7 @@ static void build_bind_pkt() packet[15] ^= cyrfmfg_id[2]; } -static void build_data_pkt() +static void __attribute__((unused)) build_data_pkt() { uint8_t i; packet[0] = (DEVO_NUM_CHANNELS << 4) | (0x0b + ch_idx); @@ -161,7 +161,7 @@ static void build_data_pkt() add_pkt_suffix(); } -static void cyrf_set_bound_sop_code() +static void __attribute__((unused)) cyrf_set_bound_sop_code() { /* crc == 0 isn't allowed, so use 1 if the math results in 0 */ uint8_t crc = (cyrfmfg_id[0] + (cyrfmfg_id[1] >> 6) + cyrfmfg_id[2]); @@ -174,7 +174,7 @@ static void cyrf_set_bound_sop_code() CYRF_SetPower(0x08); } -static void cyrf_init() +static void __attribute__((unused)) cyrf_init() { /* Initialise CYRF chip */ CYRF_WriteRegister(CYRF_1D_MODE_OVERRIDE, 0x39); @@ -201,7 +201,7 @@ static void cyrf_init() CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x28); } -static void set_radio_channels() +static void __attribute__((unused)) set_radio_channels() { //int i; CYRF_FindBestChannels(hopping_frequency, 3, 4, 4, 80); @@ -217,7 +217,7 @@ static void set_radio_channels() hopping_frequency[4] = hopping_frequency[1]; } -static void DEVO_BuildPacket() +static void __attribute__((unused)) DEVO_BuildPacket() { switch(phase) { @@ -302,7 +302,7 @@ uint16_t devo_callback() return 1200; } -/*static void devo_bind() +/*static void __attribute__((unused)) devo_bind() { fixed_id = Model_fixed_id; bind_counter = DEVO_BIND_COUNT; @@ -311,7 +311,7 @@ uint16_t devo_callback() } -static void generate_fixed_id_bind(){ +static void __attribute__((unused)) generate_fixed_id_bind(){ if(BIND_0){ //randomSeed((uint32_t)analogRead(A6)<<10|analogRead(A7));//seed uint8_t txid[4]; diff --git a/Multiprotocol/ESky_nrf24l01.ino b/Multiprotocol/ESky_nrf24l01.ino index f83128f..1ed7d3d 100644 --- a/Multiprotocol/ESky_nrf24l01.ino +++ b/Multiprotocol/ESky_nrf24l01.ino @@ -23,14 +23,14 @@ #define ESKY_PAYLOAD_SIZE 13 #define ESKY_PACKET_CHKTIME 100 // Time to wait for packet to be sent (no ACK, so very short) -static void ESKY_set_data_address() +static void __attribute__((unused)) ESKY_set_data_address() { NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x02); // 4-byte RX/TX address for regular packets NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 4); NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 4); } -static void ESKY_init(uint8_t bind) +static void __attribute__((unused)) ESKY_init(uint8_t bind) { NRF24L01_Initialize(); @@ -60,7 +60,7 @@ static void ESKY_init(uint8_t bind) NRF24L01_WriteReg(NRF24L01_17_FIFO_STATUS, 0x00); // Just in case, no real bits to write here } -static void ESKY_init2() +static void __attribute__((unused)) ESKY_init2() { NRF24L01_FlushTx(); packet_sent = 0; @@ -90,7 +90,7 @@ static void ESKY_init2() NRF24L01_SetTxRxMode(TX_EN); } -static void ESKY_send_packet(uint8_t bind) +static void __attribute__((unused)) ESKY_send_packet(uint8_t bind) { uint8_t rf_ch = 50; // bind channel if (bind) diff --git a/Multiprotocol/FlySky_a7105.ino b/Multiprotocol/FlySky_a7105.ino index 452b5ff..8c5f956 100644 --- a/Multiprotocol/FlySky_a7105.ino +++ b/Multiprotocol/FlySky_a7105.ino @@ -73,7 +73,7 @@ uint8_t chanrow; uint8_t chancol; uint8_t chanoffset; -static void flysky_apply_extension_flags() +static void __attribute__((unused)) flysky_apply_extension_flags() { const uint8_t V912_X17_SEQ[10] = { 0x14, 0x31, 0x40, 0x49, 0x49, // sometime first byte is 0x15 ? 0x49, 0x49, 0x49, 0x49, 0x49, }; @@ -148,7 +148,7 @@ static void flysky_apply_extension_flags() } } -static void flysky_build_packet(uint8_t init) +static void __attribute__((unused)) flysky_build_packet(uint8_t init) { uint8_t i; //servodata timing range for flysky. diff --git a/Multiprotocol/FrSky_cc2500.ino b/Multiprotocol/FrSky_cc2500.ino index 5f90a46..449f954 100644 --- a/Multiprotocol/FrSky_cc2500.ino +++ b/Multiprotocol/FrSky_cc2500.ino @@ -34,6 +34,135 @@ enum { }; */ +static void __attribute__((unused)) frsky2way_init(uint8_t bind) +{ + // Configure cc2500 for tx mode + CC2500_Reset(); + // + cc2500_writeReg(CC2500_02_IOCFG0, 0x06); + cc2500_writeReg(CC2500_00_IOCFG2, 0x06); + cc2500_writeReg(CC2500_17_MCSM1, 0x0c); + cc2500_writeReg(CC2500_18_MCSM0, 0x18); + cc2500_writeReg(CC2500_06_PKTLEN, 0x19); + cc2500_writeReg(CC2500_07_PKTCTRL1, 0x04); + cc2500_writeReg(CC2500_08_PKTCTRL0, 0x05); + cc2500_writeReg(CC2500_3E_PATABLE, 0xff); + cc2500_writeReg(CC2500_0B_FSCTRL1, 0x08); + cc2500_writeReg(CC2500_0C_FSCTRL0, option); + //base freq FREQ = 0x5C7627 (F = 2404MHz) + cc2500_writeReg(CC2500_0D_FREQ2, 0x5c); + cc2500_writeReg(CC2500_0E_FREQ1, 0x76); + cc2500_writeReg(CC2500_0F_FREQ0, 0x27); + // + cc2500_writeReg(CC2500_10_MDMCFG4, 0xAA); + cc2500_writeReg(CC2500_11_MDMCFG3, 0x39); + cc2500_writeReg(CC2500_12_MDMCFG2, 0x11); + cc2500_writeReg(CC2500_13_MDMCFG1, 0x23); + cc2500_writeReg(CC2500_14_MDMCFG0, 0x7a); + cc2500_writeReg(CC2500_15_DEVIATN, 0x42); + cc2500_writeReg(CC2500_19_FOCCFG, 0x16); + cc2500_writeReg(CC2500_1A_BSCFG, 0x6c); + cc2500_writeReg(CC2500_1B_AGCCTRL2, bind ? 0x43 : 0x03); + cc2500_writeReg(CC2500_1C_AGCCTRL1,0x40); + cc2500_writeReg(CC2500_1D_AGCCTRL0,0x91); + cc2500_writeReg(CC2500_21_FREND1, 0x56); + cc2500_writeReg(CC2500_22_FREND0, 0x10); + cc2500_writeReg(CC2500_23_FSCAL3, 0xa9); + cc2500_writeReg(CC2500_24_FSCAL2, 0x0A); + cc2500_writeReg(CC2500_25_FSCAL1, 0x00); + cc2500_writeReg(CC2500_26_FSCAL0, 0x11); + cc2500_writeReg(CC2500_29_FSTEST, 0x59); + cc2500_writeReg(CC2500_2C_TEST2, 0x88); + cc2500_writeReg(CC2500_2D_TEST1, 0x31); + cc2500_writeReg(CC2500_2E_TEST0, 0x0B); + cc2500_writeReg(CC2500_03_FIFOTHR, 0x07); + cc2500_writeReg(CC2500_09_ADDR, 0x00); + // + CC2500_SetTxRxMode(TX_EN); + CC2500_SetPower(); + + cc2500_strobe(CC2500_SIDLE); + + cc2500_writeReg(CC2500_09_ADDR, bind ? 0x03 : rx_tx_addr[3]); + cc2500_writeReg(CC2500_07_PKTCTRL1, 0x05); + cc2500_strobe(CC2500_SIDLE); // Go to idle... + // + cc2500_writeReg(CC2500_0A_CHANNR, 0x00); + cc2500_writeReg(CC2500_23_FSCAL3, 0x89); + cc2500_strobe(CC2500_SFRX); + //#######END INIT######## +} + +static uint8_t __attribute__((unused)) get_chan_num(uint16_t idx) +{ + uint8_t ret = (idx * 0x1e) % 0xeb; + if(idx == 3 || idx == 23 || idx == 47) + ret++; + if(idx > 47) + return 0; + return ret; +} + +static void __attribute__((unused)) frsky2way_build_bind_packet() +{ + //11 03 01 d7 2d 00 00 1e 3c 5b 78 00 00 00 00 00 00 01 + //11 03 01 19 3e 00 02 8e 2f bb 5c 00 00 00 00 00 00 01 + packet[0] = 0x11; + packet[1] = 0x03; + packet[2] = 0x01; + packet[3] = rx_tx_addr[3]; + packet[4] = rx_tx_addr[2]; + uint16_t idx = ((state -FRSKY_BIND) % 10) * 5; + packet[5] = idx; + packet[6] = get_chan_num(idx++); + packet[7] = get_chan_num(idx++); + packet[8] = get_chan_num(idx++); + packet[9] = get_chan_num(idx++); + packet[10] = get_chan_num(idx++); + packet[11] = 0x00; + packet[12] = 0x00; + packet[13] = 0x00; + packet[14] = 0x00; + packet[15] = 0x00; + packet[16] = 0x00; + packet[17] = 0x01; +} + + + +static void __attribute__((unused)) frsky2way_data_frame() +{//pachet[4] is telemetry user frame counter(hub) + //11 d7 2d 22 00 01 c9 c9 ca ca 88 88 ca ca c9 ca 88 88 + //11 57 12 00 00 01 f2 f2 f2 f2 06 06 ca ca ca ca 18 18 + packet[0] = 0x11; //Length + packet[1] = rx_tx_addr[3]; + packet[2] = rx_tx_addr[2]; + packet[3] = counter;// + packet[4]=telemetry_counter; + + packet[5] = 0x01; + // + packet[10] = 0; + packet[11] = 0; + packet[16] = 0; + packet[17] = 0; + for(uint8_t i = 0; i < 8; i++) + { + uint16_t value; + value = convert_channel_frsky(i); + if(i < 4) + { + packet[6+i] = value & 0xff; + packet[10+(i>>1)] |= ((value >> 8) & 0x0f) << (4 *(i & 0x01)); + } + else + { + packet[8+i] = value & 0xff; + packet[16+((i-4)>>1)] |= ((value >> 8) & 0x0f) << (4 * ((i-4) & 0x01)); + } + } +} + uint16_t initFrSky_2way() { if(IS_AUTOBIND_FLAG_on) @@ -49,6 +178,26 @@ uint16_t initFrSky_2way() return 10000; } +#if defined(TELEMETRY) +static void __attribute__((unused)) check_telemetry(uint8_t *pkt,uint8_t len) +{ + if(pkt[1] != rx_tx_addr[3] || pkt[2] != rx_tx_addr[2] || len != pkt[0] + 3) + {//only packets with the required id and packet length + for(uint8_t i=3;i<6;i++) + pktt[i]=0; + return; + } + else + { + for (uint8_t i=3;i0) + telemetry_counter=(telemetry_counter+1)%32; + } +} +#endif + uint16_t ReadFrSky_2way() { if (state < FRSKY_BIND_DONE) @@ -112,163 +261,4 @@ uint16_t ReadFrSky_2way() } return state == FRSKY_DATA4 ? 7500 : 9000; } - -#if defined(TELEMETRY) -static void check_telemetry(uint8_t *pkt,uint8_t len) -{ - if(pkt[1] != rx_tx_addr[3] || pkt[2] != rx_tx_addr[2] || len != pkt[0] + 3) - {//only packets with the required id and packet length - for(uint8_t i=3;i<6;i++) - pktt[i]=0; - return; - } - else - { - for (uint8_t i=3;i0) - telemetry_counter=(telemetry_counter+1)%32; - } -} - -void compute_RSSIdbm(){ - RSSI_dBm = (((uint16_t)(pktt[len-2])*18)>>5); - if(pktt[len-2] >=128) - RSSI_dBm -= 82; - else - RSSI_dBm += 65; -} - -#endif - -static void frsky2way_init(uint8_t bind) -{ - // Configure cc2500 for tx mode - CC2500_Reset(); - // - cc2500_writeReg(CC2500_02_IOCFG0, 0x06); - cc2500_writeReg(CC2500_00_IOCFG2, 0x06); - cc2500_writeReg(CC2500_17_MCSM1, 0x0c); - cc2500_writeReg(CC2500_18_MCSM0, 0x18); - cc2500_writeReg(CC2500_06_PKTLEN, 0x19); - cc2500_writeReg(CC2500_07_PKTCTRL1, 0x04); - cc2500_writeReg(CC2500_08_PKTCTRL0, 0x05); - cc2500_writeReg(CC2500_3E_PATABLE, 0xff); - cc2500_writeReg(CC2500_0B_FSCTRL1, 0x08); - cc2500_writeReg(CC2500_0C_FSCTRL0, option); - //base freq FREQ = 0x5C7627 (F = 2404MHz) - cc2500_writeReg(CC2500_0D_FREQ2, 0x5c); - cc2500_writeReg(CC2500_0E_FREQ1, 0x76); - cc2500_writeReg(CC2500_0F_FREQ0, 0x27); - // - cc2500_writeReg(CC2500_10_MDMCFG4, 0xAA); - cc2500_writeReg(CC2500_11_MDMCFG3, 0x39); - cc2500_writeReg(CC2500_12_MDMCFG2, 0x11); - cc2500_writeReg(CC2500_13_MDMCFG1, 0x23); - cc2500_writeReg(CC2500_14_MDMCFG0, 0x7a); - cc2500_writeReg(CC2500_15_DEVIATN, 0x42); - cc2500_writeReg(CC2500_19_FOCCFG, 0x16); - cc2500_writeReg(CC2500_1A_BSCFG, 0x6c); - cc2500_writeReg(CC2500_1B_AGCCTRL2, bind ? 0x43 : 0x03); - cc2500_writeReg(CC2500_1C_AGCCTRL1,0x40); - cc2500_writeReg(CC2500_1D_AGCCTRL0,0x91); - cc2500_writeReg(CC2500_21_FREND1, 0x56); - cc2500_writeReg(CC2500_22_FREND0, 0x10); - cc2500_writeReg(CC2500_23_FSCAL3, 0xa9); - cc2500_writeReg(CC2500_24_FSCAL2, 0x0A); - cc2500_writeReg(CC2500_25_FSCAL1, 0x00); - cc2500_writeReg(CC2500_26_FSCAL0, 0x11); - cc2500_writeReg(CC2500_29_FSTEST, 0x59); - cc2500_writeReg(CC2500_2C_TEST2, 0x88); - cc2500_writeReg(CC2500_2D_TEST1, 0x31); - cc2500_writeReg(CC2500_2E_TEST0, 0x0B); - cc2500_writeReg(CC2500_03_FIFOTHR, 0x07); - cc2500_writeReg(CC2500_09_ADDR, 0x00); - // - CC2500_SetTxRxMode(TX_EN); - CC2500_SetPower(); - - cc2500_strobe(CC2500_SIDLE); - - cc2500_writeReg(CC2500_09_ADDR, bind ? 0x03 : rx_tx_addr[3]); - cc2500_writeReg(CC2500_07_PKTCTRL1, 0x05); - cc2500_strobe(CC2500_SIDLE); // Go to idle... - // - cc2500_writeReg(CC2500_0A_CHANNR, 0x00); - cc2500_writeReg(CC2500_23_FSCAL3, 0x89); - cc2500_strobe(CC2500_SFRX); - //#######END INIT######## -} - -static uint8_t get_chan_num(uint16_t idx) -{ - uint8_t ret = (idx * 0x1e) % 0xeb; - if(idx == 3 || idx == 23 || idx == 47) - ret++; - if(idx > 47) - return 0; - return ret; -} - -static void frsky2way_build_bind_packet() -{ - //11 03 01 d7 2d 00 00 1e 3c 5b 78 00 00 00 00 00 00 01 - //11 03 01 19 3e 00 02 8e 2f bb 5c 00 00 00 00 00 00 01 - packet[0] = 0x11; - packet[1] = 0x03; - packet[2] = 0x01; - packet[3] = rx_tx_addr[3]; - packet[4] = rx_tx_addr[2]; - uint16_t idx = ((state -FRSKY_BIND) % 10) * 5; - packet[5] = idx; - packet[6] = get_chan_num(idx++); - packet[7] = get_chan_num(idx++); - packet[8] = get_chan_num(idx++); - packet[9] = get_chan_num(idx++); - packet[10] = get_chan_num(idx++); - packet[11] = 0x00; - packet[12] = 0x00; - packet[13] = 0x00; - packet[14] = 0x00; - packet[15] = 0x00; - packet[16] = 0x00; - packet[17] = 0x01; -} - - - -static void frsky2way_data_frame() -{//pachet[4] is telemetry user frame counter(hub) - //11 d7 2d 22 00 01 c9 c9 ca ca 88 88 ca ca c9 ca 88 88 - //11 57 12 00 00 01 f2 f2 f2 f2 06 06 ca ca ca ca 18 18 - packet[0] = 0x11; //Length - packet[1] = rx_tx_addr[3]; - packet[2] = rx_tx_addr[2]; - packet[3] = counter;// - packet[4]=telemetry_counter; - - packet[5] = 0x01; - // - packet[10] = 0; - packet[11] = 0; - packet[16] = 0; - packet[17] = 0; - for(uint8_t i = 0; i < 8; i++) - { - uint16_t value; - value = convert_channel_frsky(i); - if(i < 4) - { - packet[6+i] = value & 0xff; - packet[10+(i>>1)] |= ((value >> 8) & 0x0f) << (4 *(i & 0x01)); - } - else - { - packet[8+i] = value & 0xff; - packet[16+((i-4)>>1)] |= ((value >> 8) & 0x0f) << (4 * ((i-4) & 0x01)); - } - } -} - #endif diff --git a/Multiprotocol/Hisky_nrf24l01.ino b/Multiprotocol/Hisky_nrf24l01.ino index d413cbe..c6edabe 100644 --- a/Multiprotocol/Hisky_nrf24l01.ino +++ b/Multiprotocol/Hisky_nrf24l01.ino @@ -27,7 +27,7 @@ uint8_t bind_buf_arry[4][10]; // HiSky protocol uses TX id as an address for nRF24L01, and uses frequency hopping sequence // which does not depend on this id and is passed explicitly in binding sequence. So we are free // to generate this sequence as we wish. It should be in the range [02..77] -static void calc_fh_channels() +static void __attribute__((unused)) calc_fh_channels() { uint8_t idx = 0; uint32_t rnd = MProtocol_id; @@ -61,7 +61,7 @@ static void calc_fh_channels() } } -static void build_binding_packet(void) +static void __attribute__((unused)) build_binding_packet(void) { uint8_t i; uint16_t sum=0; @@ -95,7 +95,7 @@ static void build_binding_packet(void) } } -static void hisky_init() +static void __attribute__((unused)) hisky_init() { NRF24L01_Initialize(); @@ -116,7 +116,7 @@ static void hisky_init() // HiSky channel sequence: AILE ELEV THRO RUDD GEAR PITCH, channel data value is from 0 to 1000 // Channel 7 - Gyro mode, 0 - 6 axis, 3 - 3 axis -static void build_ch_data() +static void __attribute__((unused)) build_ch_data() { uint16_t temp; uint8_t i,j; @@ -217,7 +217,7 @@ uint16_t hisky_cb() return 1000; // send 1 binding packet and 1 data packet per 9ms } -static void initialize_tx_id() +static void __attribute__((unused)) initialize_tx_id() { //Generate frequency hopping table if(sub_protocol==HK310) diff --git a/Multiprotocol/Hubsan_a7105.ino b/Multiprotocol/Hubsan_a7105.ino index 6cd5c03..d13bdb7 100644 --- a/Multiprotocol/Hubsan_a7105.ino +++ b/Multiprotocol/Hubsan_a7105.ino @@ -56,7 +56,7 @@ enum { }; #define WAIT_WRITE 0x80 -static void update_crc() +static void __attribute__((unused)) hubsan_update_crc() { uint8_t sum = 0; for(uint8_t i = 0; i < 15; i++) @@ -64,7 +64,7 @@ static void update_crc() packet[15] = (256 - (sum % 256)) & 0xFF; } -static void hubsan_build_bind_packet(uint8_t bind_state) +static void __attribute__((unused)) hubsan_build_bind_packet(uint8_t bind_state) { static uint8_t handshake_counter; if(phase < BIND_7) @@ -99,14 +99,14 @@ static void hubsan_build_bind_packet(uint8_t bind_state) if(phase == BIND_7) packet[2] = handshake_counter++; } - update_crc(); + hubsan_update_crc(); } //cc : throttle observed range: 0x00 - 0xFF (smaller is down) //ee : rudder observed range: 0x34 - 0xcc (smaller is right)52-204-60% //gg : elevator observed range: 0x3e - 0xbc (smaller is up)62-188 -50% //ii : aileron observed range: 0x45 - 0xc3 (smaller is right)69-195-50% -static void hubsan_build_packet() +static void __attribute__((unused)) hubsan_build_packet() { static uint8_t vtx_freq = 0; memset(packet, 0, 16); @@ -177,7 +177,7 @@ static void hubsan_build_packet() packet_count++; } } - update_crc(); + hubsan_update_crc(); } #if defined(TELEMETRY) @@ -193,8 +193,10 @@ static void hubsan_build_packet() uint16_t ReadHubsan() { - static uint8_t txState=0; +#if defined(TELEMETRY) static uint8_t rfMode=0; +#endif + static uint8_t txState=0; static uint8_t bind_count=0; uint16_t delay; uint8_t i; @@ -277,7 +279,9 @@ uint16_t ReadHubsan() case DATA_4: case DATA_5: if( txState == 0) { // send packet +#if defined(TELEMETRY) rfMode = A7105_TX; +#endif if( phase == DATA_1) A7105_SetPower(); //Keep transmit power in sync hubsan_build_packet(); diff --git a/Multiprotocol/KN_nrf24l01.ino b/Multiprotocol/KN_nrf24l01.ino index 6c89ff1..53e902d 100644 --- a/Multiprotocol/KN_nrf24l01.ino +++ b/Multiprotocol/KN_nrf24l01.ino @@ -70,6 +70,205 @@ enum { KN_FLAG_GYROR = 0x80 // Always 0 so far }; +//------------------------------------------------------------------------------------------------- +// This function init 24L01 regs and packet data for binding +// Send tx address, hopping table (for Wl Toys), and data rate to the KN receiver during binding. +// It seems that KN can remember these parameters, no binding needed after power up. +// Bind uses fixed TX address "KNDZK", 1 Mbps data rate and channel 83 +//------------------------------------------------------------------------------------------------- +static void __attribute__((unused)) kn_bind_init() +{ + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"KNDZK", 5); + packet[0] = 'K'; + packet[1] = 'N'; + packet[2] = 'D'; + packet[3] = 'Z'; + //Use first four bytes of tx_addr + packet[4] = rx_tx_addr[0]; + packet[5] = rx_tx_addr[1]; + packet[6] = rx_tx_addr[2]; + packet[7] = rx_tx_addr[3]; + + if(sub_protocol==WLTOYS) + { + packet[8] = hopping_frequency[0]; + packet[9] = hopping_frequency[1]; + packet[10] = hopping_frequency[2]; + packet[11] = hopping_frequency[3]; + } + else + { + packet[8] = 0x00; + packet[9] = 0x00; + packet[10] = 0x00; + packet[11] = 0x00; + } + packet[12] = 0x00; + packet[13] = 0x00; + packet[14] = 0x00; + packet[15] = 0x01; //(USE1MBPS_YES) ? 0x01 : 0x00; + + //Set RF channel + NRF24L01_WriteReg(NRF24L01_05_RF_CH, 83); +} + +//------------------------------------------------------------------------------------------------- +// Update control data to be sent +// Do it once per frequency, so the same values will be sent 4 times +// KN uses 4 10-bit data channels plus a 8-bit switch channel +// +// The packet[0] is used for pitch/throttle, the relation is hard coded, not changeable. +// We can change the throttle/pitch range though. +// +// How to use trim? V977 stock controller can trim 6-axis mode to eliminate the drift. +//------------------------------------------------------------------------------------------------- +static void __attribute__((unused)) kn_update_packet_control_data() +{ + uint16_t value; + value = convert_channel_10b(THROTTLE); + packet[0] = (value >> 8) & 0xFF; + packet[1] = value & 0xFF; + value = convert_channel_10b(AILERON); + packet[2] = (value >> 8) & 0xFF; + packet[3] = value & 0xFF; + value = convert_channel_10b(ELEVATOR); + packet[4] = (value >> 8) & 0xFF; + packet[5] = value & 0xFF; + value = convert_channel_10b(RUDDER); + packet[6] = (value >> 8) & 0xFF; + packet[7] = value & 0xFF; + // Trims, middle is 0x64 (100) range 0-200 + packet[8] = convert_channel_8b_scale(AUX5,0,200); // 0x64; // T + packet[9] = convert_channel_8b_scale(AUX6,0,200); // 0x64; // A + packet[10] = convert_channel_8b_scale(AUX7,0,200); // 0x64; // E + packet[11] = 0x64; // R + + flags=0; + if (Servo_data[AUX1] > PPM_SWITCH) + flags = KN_FLAG_DR; + if (Servo_data[AUX2] > PPM_SWITCH) + flags |= KN_FLAG_TH; + if (Servo_data[AUX3] > PPM_SWITCH) + flags |= KN_FLAG_IDLEUP; + if (Servo_data[AUX4] > PPM_SWITCH) + flags |= KN_FLAG_GYRO3; + + packet[12] = flags; + + packet[13] = 0x00; + if(sub_protocol==WLTOYS) + packet[13] = (packet_sent << 5) | (hopping_frequency_no << 2); + + packet[14] = 0x00; + packet[15] = 0x00; + + NRF24L01_SetPower(); +} + + +//------------------------------------------------------------------------------------------------- +// This function generate RF TX packet address +// V977 can remember the binding parameters; we do not need rebind when power up. +// This requires the address must be repeatable for a specific RF ID at power up. +//------------------------------------------------------------------------------------------------- +static void __attribute__((unused)) kn_calculate_tx_addr() +{ + if(sub_protocol==FEILUN) + { + uint8_t addr2; + // Generate TXID with sum of minimum 256 and maximum 256+MAX_RF_CHANNEL-32 + rx_tx_addr[1] = 1 + rx_tx_addr[0] % (KN_MAX_RF_CHANNEL-33); + addr2 = 1 + rx_tx_addr[2] % (KN_MAX_RF_CHANNEL-33); + if ((uint16_t)(rx_tx_addr[0] + rx_tx_addr[1]) < 256) + rx_tx_addr[2] = addr2; + else + rx_tx_addr[2] = 0x00; + rx_tx_addr[3] = 0x00; + while((uint16_t)(rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2] + rx_tx_addr[3]) < 257) + rx_tx_addr[3] += addr2; + } + //The 5th byte is a constant, must be 'K' + rx_tx_addr[4] = 'K'; +} + +//------------------------------------------------------------------------------------------------- +// This function generates "random" RF hopping frequency channel numbers. +// These numbers must be repeatable for a specific seed +// The generated number range is from 0 to MAX_RF_CHANNEL. No repeat or adjacent numbers +// +// For Feilun variant, the channels are calculated from TXID, and since only 2 channels are used +// we copy them to fill up to MAX_RF_CHANNEL +//------------------------------------------------------------------------------------------------- +static void __attribute__((unused)) kn_calculate_freqency_hopping_channels() +{ + if(sub_protocol==WLTOYS) + { + uint8_t idx = 0; + uint32_t rnd = MProtocol_id; + while (idx < KN_RF_CH_COUNT) + { + uint8_t i; + rnd = rnd * 0x0019660D + 0x3C6EF35F; // Randomization + + // Use least-significant byte. 73 is prime, so channels 76..77 are unused + uint8_t next_ch = ((rnd >> 8) % KN_MAX_RF_CHANNEL) + 2; + // Keep the distance 2 between the channels - either odd or even + if (((next_ch ^ MProtocol_id) & 0x01 )== 0) + continue; + // Check that it's not duplicate and spread uniformly + for (i = 0; i < idx; i++) + if(hopping_frequency[i] == next_ch) + break; + if (i != idx) + continue; + hopping_frequency[idx++] = next_ch; + } + } + else + {//FEILUN + hopping_frequency[0] = rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2] + rx_tx_addr[3]; // - 256; ??? + hopping_frequency[1] = hopping_frequency[0] + 32; + hopping_frequency[2] = hopping_frequency[0]; + hopping_frequency[3] = hopping_frequency[1]; + } +} + +//------------------------------------------------------------------------------------------------- +// This function setup 24L01 +// V977 uses one way communication, receiving only. 24L01 RX is never enabled. +// V977 needs payload length in the packet. We should configure 24L01 to enable Packet Control Field(PCF) +// Some RX reg settings are actually for enable PCF +//------------------------------------------------------------------------------------------------- +static void __attribute__((unused)) kn_init() +{ + kn_calculate_tx_addr(); + kn_calculate_freqency_hopping_channels(); + + NRF24L01_Initialize(); + + NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO)); + NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknoledgement + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address + NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0); // Disable retransmit + NRF24L01_SetPower(); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit + NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 0x20); // bytes of data payload for pipe 0 + + + NRF24L01_Activate(0x73); + NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 1); // Dynamic payload for data pipe 0 + // Enable: Dynamic Payload Length to enable PCF + NRF24L01_WriteReg(NRF24L01_1D_FEATURE, BV(NRF2401_1D_EN_DPL)); + + NRF24L01_SetPower(); + + NRF24L01_FlushTx(); + // Turn radio power on + NRF24L01_SetTxRxMode(TX_EN); + NRF24L01_SetBitrate(NRF24L01_BR_1M); //USE1MBPS_YES ? NRF24L01_BR_1M : NRF24L01_BR_250K; +} + //================================================================================================ // Private Functions //================================================================================================ @@ -145,202 +344,4 @@ uint16_t kn_callback() return packet_period; } -//------------------------------------------------------------------------------------------------- -// This function init 24L01 regs and packet data for binding -// Send tx address, hopping table (for Wl Toys), and data rate to the KN receiver during binding. -// It seems that KN can remember these parameters, no binding needed after power up. -// Bind uses fixed TX address "KNDZK", 1 Mbps data rate and channel 83 -//------------------------------------------------------------------------------------------------- -static void kn_bind_init() -{ - NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t*)"KNDZK", 5); - packet[0] = 'K'; - packet[1] = 'N'; - packet[2] = 'D'; - packet[3] = 'Z'; - //Use first four bytes of tx_addr - packet[4] = rx_tx_addr[0]; - packet[5] = rx_tx_addr[1]; - packet[6] = rx_tx_addr[2]; - packet[7] = rx_tx_addr[3]; - - if(sub_protocol==WLTOYS) - { - packet[8] = hopping_frequency[0]; - packet[9] = hopping_frequency[1]; - packet[10] = hopping_frequency[2]; - packet[11] = hopping_frequency[3]; - } - else - { - packet[8] = 0x00; - packet[9] = 0x00; - packet[10] = 0x00; - packet[11] = 0x00; - } - packet[12] = 0x00; - packet[13] = 0x00; - packet[14] = 0x00; - packet[15] = 0x01; //(USE1MBPS_YES) ? 0x01 : 0x00; - - //Set RF channel - NRF24L01_WriteReg(NRF24L01_05_RF_CH, 83); -} - -//------------------------------------------------------------------------------------------------- -// Update control data to be sent -// Do it once per frequency, so the same values will be sent 4 times -// KN uses 4 10-bit data channels plus a 8-bit switch channel -// -// The packet[0] is used for pitch/throttle, the relation is hard coded, not changeable. -// We can change the throttle/pitch range though. -// -// How to use trim? V977 stock controller can trim 6-axis mode to eliminate the drift. -//------------------------------------------------------------------------------------------------- -static void kn_update_packet_control_data() -{ - uint16_t value; - value = convert_channel_10b(THROTTLE); - packet[0] = (value >> 8) & 0xFF; - packet[1] = value & 0xFF; - value = convert_channel_10b(AILERON); - packet[2] = (value >> 8) & 0xFF; - packet[3] = value & 0xFF; - value = convert_channel_10b(ELEVATOR); - packet[4] = (value >> 8) & 0xFF; - packet[5] = value & 0xFF; - value = convert_channel_10b(RUDDER); - packet[6] = (value >> 8) & 0xFF; - packet[7] = value & 0xFF; - // Trims, middle is 0x64 (100) range 0-200 - packet[8] = convert_channel_8b_scale(AUX5,0,200); // 0x64; // T - packet[9] = convert_channel_8b_scale(AUX6,0,200); // 0x64; // A - packet[10] = convert_channel_8b_scale(AUX7,0,200); // 0x64; // E - packet[11] = 0x64; // R - - flags=0; - if (Servo_data[AUX1] > PPM_SWITCH) - flags = KN_FLAG_DR; - if (Servo_data[AUX2] > PPM_SWITCH) - flags |= KN_FLAG_TH; - if (Servo_data[AUX3] > PPM_SWITCH) - flags |= KN_FLAG_IDLEUP; - if (Servo_data[AUX4] > PPM_SWITCH) - flags |= KN_FLAG_GYRO3; - - packet[12] = flags; - - packet[13] = 0x00; - if(sub_protocol==WLTOYS) - packet[13] = (packet_sent << 5) | (hopping_frequency_no << 2); - - packet[14] = 0x00; - packet[15] = 0x00; - - NRF24L01_SetPower(); -} - -//------------------------------------------------------------------------------------------------- -// This function setup 24L01 -// V977 uses one way communication, receiving only. 24L01 RX is never enabled. -// V977 needs payload length in the packet. We should configure 24L01 to enable Packet Control Field(PCF) -// Some RX reg settings are actually for enable PCF -//------------------------------------------------------------------------------------------------- -static void kn_init() -{ - kn_calculate_tx_addr(); - kn_calculate_freqency_hopping_channels(); - - NRF24L01_Initialize(); - - NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO)); - NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknoledgement - NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 - NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address - NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0); // Disable retransmit - NRF24L01_SetPower(); - NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit - NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 0x20); // bytes of data payload for pipe 0 - - - NRF24L01_Activate(0x73); - NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 1); // Dynamic payload for data pipe 0 - // Enable: Dynamic Payload Length to enable PCF - NRF24L01_WriteReg(NRF24L01_1D_FEATURE, BV(NRF2401_1D_EN_DPL)); - - NRF24L01_SetPower(); - - NRF24L01_FlushTx(); - // Turn radio power on - NRF24L01_SetTxRxMode(TX_EN); - NRF24L01_SetBitrate(NRF24L01_BR_1M); //USE1MBPS_YES ? NRF24L01_BR_1M : NRF24L01_BR_250K; -} - -//------------------------------------------------------------------------------------------------- -// This function generate RF TX packet address -// V977 can remember the binding parameters; we do not need rebind when power up. -// This requires the address must be repeatable for a specific RF ID at power up. -//------------------------------------------------------------------------------------------------- -static void kn_calculate_tx_addr() -{ - if(sub_protocol==FEILUN) - { - uint8_t addr2; - // Generate TXID with sum of minimum 256 and maximum 256+MAX_RF_CHANNEL-32 - rx_tx_addr[1] = 1 + rx_tx_addr[0] % (KN_MAX_RF_CHANNEL-33); - addr2 = 1 + rx_tx_addr[2] % (KN_MAX_RF_CHANNEL-33); - if ((uint16_t)(rx_tx_addr[0] + rx_tx_addr[1]) < 256) - rx_tx_addr[2] = addr2; - else - rx_tx_addr[2] = 0x00; - rx_tx_addr[3] = 0x00; - while((uint16_t)(rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2] + rx_tx_addr[3]) < 257) - rx_tx_addr[3] += addr2; - } - //The 5th byte is a constant, must be 'K' - rx_tx_addr[4] = 'K'; -} - -//------------------------------------------------------------------------------------------------- -// This function generates "random" RF hopping frequency channel numbers. -// These numbers must be repeatable for a specific seed -// The generated number range is from 0 to MAX_RF_CHANNEL. No repeat or adjacent numbers -// -// For Feilun variant, the channels are calculated from TXID, and since only 2 channels are used -// we copy them to fill up to MAX_RF_CHANNEL -//------------------------------------------------------------------------------------------------- -static void kn_calculate_freqency_hopping_channels() -{ - if(sub_protocol==WLTOYS) - { - uint8_t idx = 0; - uint32_t rnd = MProtocol_id; - while (idx < KN_RF_CH_COUNT) - { - uint8_t i; - rnd = rnd * 0x0019660D + 0x3C6EF35F; // Randomization - - // Use least-significant byte. 73 is prime, so channels 76..77 are unused - uint8_t next_ch = ((rnd >> 8) % KN_MAX_RF_CHANNEL) + 2; - // Keep the distance 2 between the channels - either odd or even - if (((next_ch ^ MProtocol_id) & 0x01 )== 0) - continue; - // Check that it's not duplicate and spread uniformly - for (i = 0; i < idx; i++) - if(hopping_frequency[i] == next_ch) - break; - if (i != idx) - continue; - hopping_frequency[idx++] = next_ch; - } - } - else - {//FEILUN - hopping_frequency[0] = rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2] + rx_tx_addr[3]; // - 256; ??? - hopping_frequency[1] = hopping_frequency[0] + 32; - hopping_frequency[2] = hopping_frequency[0]; - hopping_frequency[3] = hopping_frequency[1]; - } -} - #endif diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index d299734..0e32599 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -89,9 +89,9 @@ uint8_t cur_protocol[2]; uint8_t prev_protocol=0; // Telemetry -#if defined(TELEMETRY) #define MAX_PKT 27 uint8_t pkt[MAX_PKT];//telemetry receiving packets +#if defined(TELEMETRY) uint8_t pktt[MAX_PKT];//telemetry receiving packets volatile uint8_t tx_head; volatile uint8_t tx_tail; @@ -176,6 +176,9 @@ void setup() //Configure PPM interrupt EICRA |=(1<> 2) + 0x20) -static void SYMAX_build_packet_x5c(uint8_t bind) +static void __attribute__((unused)) SYMAX_build_packet_x5c(uint8_t bind) { if (bind) { @@ -116,7 +116,7 @@ static void SYMAX_build_packet_x5c(uint8_t bind) } } -static void SYMAX_build_packet(uint8_t bind) +static void __attribute__((unused)) SYMAX_build_packet(uint8_t bind) { if (bind) { @@ -146,7 +146,7 @@ static void SYMAX_build_packet(uint8_t bind) packet[9] = SYMAX_checksum(packet); } -static void SYMAX_send_packet(uint8_t bind) +static void __attribute__((unused)) SYMAX_send_packet(uint8_t bind) { if (sub_protocol==SYMAX5C) SYMAX_build_packet_x5c(bind); @@ -167,7 +167,7 @@ static void SYMAX_send_packet(uint8_t bind) NRF24L01_SetPower(); // Set tx_power } -static void symax_init() +static void __attribute__((unused)) symax_init() { NRF24L01_Initialize(); // @@ -219,7 +219,7 @@ static void symax_init() NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0e); // power on } -static void symax_init1() +static void __attribute__((unused)) symax_init1() { // duplicate stock tx sending strange packet (effect unknown) uint8_t first_packet[] = {0xf9, 0x96, 0x82, 0x1b, 0x20, 0x08, 0x08, 0xf2, 0x7d, 0xef, 0xff, 0x00, 0x00, 0x00, 0x00}; @@ -247,7 +247,7 @@ static void symax_init1() } // channels determined by last byte of tx address -static void symax_set_channels(uint8_t address) +static void __attribute__((unused)) symax_set_channels(uint8_t address) { static const uint8_t start_chans_1[] = {0x0a, 0x1a, 0x2a, 0x3a}; static const uint8_t start_chans_2[] = {0x2a, 0x0a, 0x42, 0x22}; @@ -290,7 +290,7 @@ static void symax_set_channels(uint8_t address) *pchans = 0x39194121; } -static void symax_init2() +static void __attribute__((unused)) symax_init2() { uint8_t chans_data_x5c[] = {0x1d, 0x2f, 0x26, 0x3d, 0x15, 0x2b, 0x25, 0x24, 0x27, 0x2c, 0x1c, 0x3e, 0x39, 0x2d, 0x22}; diff --git a/Multiprotocol/V2X2_nrf24l01.ino b/Multiprotocol/V2X2_nrf24l01.ino index 35796b1..d761c57 100644 --- a/Multiprotocol/V2X2_nrf24l01.ino +++ b/Multiprotocol/V2X2_nrf24l01.ino @@ -75,7 +75,7 @@ static const uint8_t freq_hopping[][16] = { 0x18, 0x2A, 0x21, 0x38, 0x10, 0x26, 0x20, 0x1F } // 03 }; -static void v202_init() +static void __attribute__((unused)) v202_init() { NRF24L01_Initialize(); @@ -108,7 +108,7 @@ static void v202_init() NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x66\x88\x68\x68\x68", 5); } -static void V202_init2() +static void __attribute__((unused)) V202_init2() { NRF24L01_FlushTx(); packet_sent = 0; @@ -119,7 +119,7 @@ static void V202_init2() //Done by TX_EN??? => NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP)); } -static void V2X2_set_tx_id(void) +static void __attribute__((unused)) V2X2_set_tx_id(void) { uint8_t sum; sum = rx_tx_addr[1] + rx_tx_addr[2] + rx_tx_addr[3]; @@ -134,7 +134,7 @@ static void V2X2_set_tx_id(void) } } -static void V2X2_add_pkt_checksum() +static void __attribute__((unused)) V2X2_add_pkt_checksum() { uint8_t sum = 0; for (uint8_t i = 0; i < 15; ++i) @@ -142,7 +142,7 @@ static void V2X2_add_pkt_checksum() packet[15] = sum; } -static void V2X2_send_packet(uint8_t bind) +static void __attribute__((unused)) V2X2_send_packet(uint8_t bind) { uint8_t flags2=0; if (bind) diff --git a/Multiprotocol/YD717_nrf24l01.ino b/Multiprotocol/YD717_nrf24l01.ino index d2a3f1a..1d9ffbe 100644 --- a/Multiprotocol/YD717_nrf24l01.ino +++ b/Multiprotocol/YD717_nrf24l01.ino @@ -41,7 +41,7 @@ enum { YD717_DATA }; -static void yd717_send_packet(uint8_t bind) +static void __attribute__((unused)) yd717_send_packet(uint8_t bind) { uint8_t rudder_trim, elevator_trim, aileron_trim; if (bind) @@ -125,7 +125,7 @@ static void yd717_send_packet(uint8_t bind) NRF24L01_SetPower(); // Set tx_power } -static void yd717_init() +static void __attribute__((unused)) yd717_init() { NRF24L01_Initialize(); @@ -162,7 +162,7 @@ static void yd717_init() NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5); } -static void YD717_init1() +static void __attribute__((unused)) YD717_init1() { // for bind packets set address to prearranged value known to receiver uint8_t bind_rx_tx_addr[] = {0x65, 0x65, 0x65, 0x65, 0x65}; @@ -179,7 +179,7 @@ static void YD717_init1() NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, bind_rx_tx_addr, 5); } -static void YD717_init2() +static void __attribute__((unused)) YD717_init2() { // set rx/tx address for data phase NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5); diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 7eaf8d4..9a8a8d2 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -23,6 +23,7 @@ //Uncomment to enable telemetry #define TELEMETRY +#define HUB_TELEMETRY //Comment a protocol to exclude it from compilation #define BAYANG_NRF24L01_INO diff --git a/Multiprotocol/telemetry.h b/Multiprotocol/telemetry.h index b305cd7..4af2b7c 100644 --- a/Multiprotocol/telemetry.h +++ b/Multiprotocol/telemetry.h @@ -1,63 +1,149 @@ -/* - 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. +//************************************* +// FrSky Telemetry serial code * +// By Midelic on RCG * +//************************************* - 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. +#if defined TELEMETRY - You should have received a copy of the GNU General Public License - along with Multiprotocol. If not, see . - */ +#define USER_MAX_BYTES 6 +#define MAX_PKTX 10 +uint8_t frame[18]; +uint8_t pass = 0; +uint8_t index; +uint8_t prev_index; +uint8_t pktx[MAX_PKTX]; - -static void frskySendStuffed(uint8_t frame[]) +void frskySendStuffed() { Serial_write(0x7E); - for (uint8_t i = 0; i < 9; i++) { - if ((frame[i] == 0x7e) || (frame[i] == 0x7d)) { + for (uint8_t i = 0; i < 9; i++) + { + + if ((frame[i] == 0x7e) || (frame[i] == 0x7d)) + { Serial_write(0x7D); - frame[i] ^= 0x20; + frame[i] ^= 0x20; } Serial_write(frame[i]); } Serial_write(0x7E); } -static void frskySendFrame() -{ - uint8_t frame[9]; +void compute_RSSIdbm(){ + RSSI_dBm = (((uint16_t)(pktt[len-2])*18)>>5); + if(pktt[len-2] >=128) + RSSI_dBm -= 82; + else + RSSI_dBm += 65; +} - frame[0] = 0xfe; - if ((cur_protocol[0]&0x1F)==MODE_FRSKY) - { - compute_RSSIdbm(); - frame[1] = pktt[3]; - frame[2] = pktt[4]; - frame[3] = (uint8_t)RSSI_dBm; - frame[4] = pktt[5]*2;//txrssi +void frsky_link_frame() +{ + frame[0] = 0xFE; + if ((cur_protocol[0]&0x1F)==MODE_FRSKY) + { + compute_RSSIdbm(); + frame[1] = pktt[3]; + frame[2] = pktt[4]; + frame[3] = (uint8_t)RSSI_dBm; + frame[4] = pktt[5]*2; + frame[5] = frame[6] = frame[7] = frame[8] = 0; + } + else + if ((cur_protocol[0]&0x1F)==MODE_HUBSAN) + { + frame[1] = v_lipo*2; //v_lipo; common 0x2A=42/10=4.2V + frame[2] = frame[1]; + frame[3] =0X6e; + frame[4] =2*0x6e; frame[5] = frame[6] = frame[7] = frame[8] = 0; } - else - if ((cur_protocol[0]&0x1F)==MODE_HUBSAN) - { - frame[1] = v_lipo*2; - frame[2] = 0; - frame[3] = 0x5A;//dummy value - frame[4] = 2 * 0x5A;//dummy value - frame[5] = frame[6] = frame[7] = frame[8] = 0; - } - frskySendStuffed(frame); + frskySendStuffed(); } +#if defined HUB_TELEMETRY +void frsky_user_frame() +{ + uint8_t indexx = 0, c=0, j=8, n=0, i; + + if(pktt[6]>0 && pktt[6]<=MAX_PKTX) + {//only valid hub frames + frame[0] = 0xFD; + frame[1] = 0; + frame[2] = pktt[7]; + + switch(pass) + { + case 0: + indexx=pktt[6]; + for(i=0;i Date: Wed, 27 Jan 2016 18:09:20 +0100 Subject: [PATCH 015/293] Telemetry additions --- README.md | 23 ++++++++++++++++++----- 1 file changed, 18 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index cbcb98b..001ac7a 100644 --- a/README.md +++ b/README.md @@ -65,14 +65,27 @@ Notes: - Channels order is AETR by default but can be changed in _Config.h. ###Telemetry -Telemetry is available for er9x and ersky9x TXs. + There are only 2 protocols so far supporting telemetry: Hubsan and Frsky. -To enable telemetry on Turnigy 9X or 9XR you need to modify your TX following one of the Frsky mod like this [one](http://blog.oscarliang.net/turnigy-9x-advance-mod/). +Hubsan displays the battery voltage. -Enabling telemetry on 9XR PRO and may be other TXs does not require any hardware modifications. The additional required serial pin is already available on the TX back module pins. +FRSky displays full telemetry (A0, A1, RSSI, TSSI and Hub). -Once the TX is telemetry enabled, it just needs to be configured on the model as usual. +### If used in PPM mode + +Telemetry is available as a serial 9600 8 n 1 output on the TX pin of the Atmega328p using the FRSky hub format. + +You can connect it to your TX if it is telemetry enabled or use a bluetooth adapter along with an app on your phone to display telemetry information and setup alerts. + +### If used in Serial mode + Telemetry is built in for er9x and ersky9x TXs. + +To enable telemetry on a Turnigy 9X or 9XR you need to modify your TX following one of the Frsky mod like this [one](http://blog.oscarliang.net/turnigy-9x-advance-mod/). + +Enabling telemetry on a 9XR PRO and may be other TXs does not require any hardware modifications. The additional required serial pin is already available on the TX back module pins. + +Once the TX is telemetry enabled, it just needs to be configured on the model (see er9x/ersky9x documentation). ##Protocols @@ -320,7 +333,7 @@ BTMBTN|TOPBTN ####FRSKY Extended limits supported -Telemetry enabled for A0, A1, RSSI +Telemetry enabled for A0, A1, RSSI, TSSI and Hub Option=fine frequency tuning, usually 0 or -41 based on the manufacturer boards From 141d7cc268ffe69875a8072afb58895fb4034144 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 28 Jan 2016 09:45:00 +0100 Subject: [PATCH 016/293] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 001ac7a..72413d7 100644 --- a/README.md +++ b/README.md @@ -477,7 +477,7 @@ You can 3D print your box (details [here](http://www.rcgroups.com/forums/showpos ##Compilation and programmation ###Toolchain -Arduino 1.6.5 +Arduino 1.6.5. Make sure to select "Arduino Pro or Pro Mini, ATmega328 (5V,16MHz)". Compilation of the code posted here works. So if it doesn't for you this is a problem with your setup, please double check everything before asking. From 4b82ead18b57f0fd77c9faf172eb5e6cd8cdf147 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 28 Jan 2016 09:48:19 +0100 Subject: [PATCH 017/293] Improved Toolchain section --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 72413d7..a968c41 100644 --- a/README.md +++ b/README.md @@ -477,7 +477,7 @@ You can 3D print your box (details [here](http://www.rcgroups.com/forums/showpos ##Compilation and programmation ###Toolchain -Arduino 1.6.5. Make sure to select "Arduino Pro or Pro Mini, ATmega328 (5V,16MHz)". +Supported Arduino version is [1.6.5](http://arduino.cc/download.php?f=/arduino-1.6.5-r5-windows.exe). Make sure to select "Arduino Pro or Pro Mini, ATmega328 (5V,16MHz)" before compiling. Compilation of the code posted here works. So if it doesn't for you this is a problem with your setup, please double check everything before asking. From 365169a9fb9c9e14a933a406bf050a0538926bf6 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 28 Jan 2016 09:52:44 +0100 Subject: [PATCH 018/293] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index a968c41..5cf6f52 100644 --- a/README.md +++ b/README.md @@ -76,7 +76,7 @@ FRSky displays full telemetry (A0, A1, RSSI, TSSI and Hub). Telemetry is available as a serial 9600 8 n 1 output on the TX pin of the Atmega328p using the FRSky hub format. -You can connect it to your TX if it is telemetry enabled or use a bluetooth adapter along with an app on your phone to display telemetry information and setup alerts. +You can connect it to your TX if it is telemetry enabled or use a bluetooth adapter (HC05/HC06) along with an app on your phone/tablet ([app example](https://play.google.com/store/apps/details?id=biz.onomato.frskydash&hl=fr)) to display telemetry information and setup alerts. ### If used in Serial mode Telemetry is built in for er9x and ersky9x TXs. From 304fc2536b824daf1842573e7cca8f8d988a8615 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 28 Jan 2016 10:50:52 +0100 Subject: [PATCH 019/293] Fix: Arduino 1.6.7 compilation issues --- Multiprotocol/Multiprotocol.ino | 3 ++- Multiprotocol/{telemetry.h => Telemetry.ino} | 0 2 files changed, 2 insertions(+), 1 deletion(-) rename Multiprotocol/{telemetry.h => Telemetry.ino} (100%) diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 0e32599..c3abbda 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -99,7 +99,6 @@ uint8_t v_lipo; int16_t RSSI_dBm; //const uint8_t RSSI_offset=72;//69 71.72 values db uint8_t telemetry_link=0; -#include "telemetry.h" #endif // Callback @@ -583,6 +582,7 @@ static void Mprotocol_serial_init() UCSR0B |= (1< Date: Thu, 28 Jan 2016 10:53:14 +0100 Subject: [PATCH 020/293] Arduino 1.6.7 support --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5cf6f52..6e7e878 100644 --- a/README.md +++ b/README.md @@ -477,7 +477,7 @@ You can 3D print your box (details [here](http://www.rcgroups.com/forums/showpos ##Compilation and programmation ###Toolchain -Supported Arduino version is [1.6.5](http://arduino.cc/download.php?f=/arduino-1.6.5-r5-windows.exe). Make sure to select "Arduino Pro or Pro Mini, ATmega328 (5V,16MHz)" before compiling. +Supported Arduino version is [1.6.7](https://www.arduino.cc/download_handler.php?f=/arduino-1.6.7-windows.exe). Make sure to select "Arduino Pro or Pro Mini, ATmega328 (5V,16MHz)" before compiling. Compilation of the code posted here works. So if it doesn't for you this is a problem with your setup, please double check everything before asking. From 017a21c17fe7b61e2f314e0397fe8b1dcdcafbb8 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 28 Jan 2016 11:26:31 +0100 Subject: [PATCH 021/293] Added: Display error messages if wrong board type is selected at compilation time --- Multiprotocol/multiprotocol.h | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/Multiprotocol/multiprotocol.h b/Multiprotocol/multiprotocol.h index 2eec052..717ada0 100644 --- a/Multiprotocol/multiprotocol.h +++ b/Multiprotocol/multiprotocol.h @@ -13,6 +13,14 @@ along with Multiprotocol. If not, see . */ +// Check selected board type +#ifndef ARDUINO_AVR_PRO + #error You must select the board type "Arduino Pro or Pro Mini" +#endif +#if F_CPU != 16000000L || not defined(__AVR_ATmega328P__) + #error You must select the processor type "ATmega328(5V, 16MHz)" +#endif + //****************** // Protocols //****************** From c74de12ceb7673694b02019d2488e87b66d405ef Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 28 Jan 2016 11:42:56 +0100 Subject: [PATCH 022/293] Fix: small bug in telemetry for Hubsan --- Multiprotocol/Telemetry.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Multiprotocol/Telemetry.ino b/Multiprotocol/Telemetry.ino index 4af2b7c..9d4ffbf 100644 --- a/Multiprotocol/Telemetry.ino +++ b/Multiprotocol/Telemetry.ino @@ -141,7 +141,7 @@ void frskyUpdate() return; } #if defined HUB_TELEMETRY - if(!telemetry_link) + if(!telemetry_link && (cur_protocol[0]&0x1F) != MODE_HUBSAN ) frsky_user_frame(); #endif } From 85548d6e8e134246e2c542ae26518965134459f4 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 28 Jan 2016 17:25:15 +0100 Subject: [PATCH 023/293] Add: Telemetry display for Hubsan TX RSSI --- Multiprotocol/Hubsan_a7105.ino | 32 +++++++++++++++++++++----------- Multiprotocol/Multiprotocol.ino | 11 +++++------ Multiprotocol/Telemetry.ino | 7 +++---- 3 files changed, 29 insertions(+), 21 deletions(-) diff --git a/Multiprotocol/Hubsan_a7105.ino b/Multiprotocol/Hubsan_a7105.ino index d13bdb7..f126b34 100644 --- a/Multiprotocol/Hubsan_a7105.ino +++ b/Multiprotocol/Hubsan_a7105.ino @@ -181,14 +181,16 @@ static void __attribute__((unused)) hubsan_build_packet() } #if defined(TELEMETRY) -/*static uint8_t hubsan_check_integrity() +static __attribute__((unused)) uint8_t hubsan_check_integrity() { - int sum = 0; + if( (packet[0]&0xFE) != 0xE0 ) + return 0; + return 1; + uint8_t sum = 0; for(uint8_t i = 0; i < 15; i++) sum += packet[i]; - return packet[15] == ((256 - (sum % 256)) & 0xFF); + return ( packet[15] == (uint8_t)(-sum) ); } -*/ #endif uint16_t ReadHubsan() @@ -295,7 +297,8 @@ uint16_t ReadHubsan() } else { #if defined(TELEMETRY) - if( rfMode == A7105_TX) {// switch to rx mode 3ms after packet sent + if( rfMode == A7105_TX) + {// switch to rx mode 3ms after packet sent for( i=0; i<10; i++) { if( !(A7105_ReadReg(A7105_00_MODE) & 0x01)) {// wait for tx completion @@ -306,15 +309,23 @@ uint16_t ReadHubsan() } } } - if( rfMode == A7105_RX) { // check for telemetry frame - for( i=0; i<10; i++) { - if( !(A7105_ReadReg(A7105_00_MODE) & 0x01)) { // data received + if( rfMode == A7105_RX) + { // check for telemetry frame + for( i=0; i<10; i++) + { + if( !(A7105_ReadReg(A7105_00_MODE) & 0x01)) + { // data received A7105_ReadData(); - if( !(A7105_ReadReg(A7105_00_MODE) & 0x01)){ // data received - v_lipo=packet[13];// hubsan lipo voltage 8bits the real value is h_lipo/10(0x2A=42-4.2V) + if( hubsan_check_integrity() ) + { + v_lipo=packet[13];// hubsan lipo voltage 8bits the real value is h_lipo/10(0x2A=42 -> 4.2V) telemetry_link=1; } A7105_Strobe(A7105_RX); + // Read TX RSSI + RSSI_dBm=256-(A7105_ReadReg(A7105_1D_RSSI_THOLD)*8)/5; // value from A7105 is between 8 for maximum signal strength to 160 or less + if(RSSI_dBm<0) RSSI_dBm=0; + else if(RSSI_dBm>255) RSSI_dBm=255; break; } } @@ -344,7 +355,6 @@ uint16_t initHubsan() { packet_count=0; id_data=ID_NORMAL; #if defined(TELEMETRY) - v_lipo=0; telemetry_link=0; #endif return 10000; diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index c3abbda..5b927bf 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -29,7 +29,6 @@ #include "_Config.h" //Global constants/variables - uint32_t MProtocol_id;//tx id, uint32_t MProtocol_id_master; uint32_t Model_fixed_id=0; @@ -558,11 +557,11 @@ uint16_t limit_channel_100(uint8_t ch) #if defined(TELEMETRY) void Serial_write(uint8_t data) { - uint8_t t=tx_head; - if(++t>=TXBUFFER_SIZE) - t=0; - tx_buff[t]=data; - tx_head=t; + cli(); // disable global int + if(++tx_head>=TXBUFFER_SIZE) + tx_head=0; + tx_buff[tx_head]=data; + sei(); // enable global int UCSR0B |= (1< Date: Thu, 28 Jan 2016 17:27:58 +0100 Subject: [PATCH 024/293] Telemetry display for Hubsan TX RSSI --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6e7e878..355d2eb 100644 --- a/README.md +++ b/README.md @@ -68,9 +68,9 @@ Notes: There are only 2 protocols so far supporting telemetry: Hubsan and Frsky. -Hubsan displays the battery voltage. +Hubsan displays the battery voltage and TX RSSI. -FRSky displays full telemetry (A0, A1, RSSI, TSSI and Hub). +FRSky displays full telemetry (A0, A1, RX RSSI, TX RSSI and Hub). ### If used in PPM mode @@ -360,7 +360,7 @@ Models: Hubsan H102D, H107/L/C/D and Hubsan H107P/C+/D+ Autobind protocol -Telemetry enabled for battery voltage only +Telemetry enabled for battery voltage and TX RSSI Option=vTX frequency (H107D) 5645 - 5900 MHz From ac78ddcc8240970b153ad0fddad54e8800187656 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 28 Jan 2016 18:43:46 +0100 Subject: [PATCH 025/293] Fix: Hubsan telemetry packet check function & Change: Telemetry variables to static --- Multiprotocol/Hubsan_a7105.ino | 3 +-- Multiprotocol/Telemetry.ino | 12 ++++-------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/Multiprotocol/Hubsan_a7105.ino b/Multiprotocol/Hubsan_a7105.ino index f126b34..760cb4e 100644 --- a/Multiprotocol/Hubsan_a7105.ino +++ b/Multiprotocol/Hubsan_a7105.ino @@ -181,11 +181,10 @@ static void __attribute__((unused)) hubsan_build_packet() } #if defined(TELEMETRY) -static __attribute__((unused)) uint8_t hubsan_check_integrity() +static uint8_t __attribute__((unused)) hubsan_check_integrity() { if( (packet[0]&0xFE) != 0xE0 ) return 0; - return 1; uint8_t sum = 0; for(uint8_t i = 0; i < 15; i++) sum += packet[i]; diff --git a/Multiprotocol/Telemetry.ino b/Multiprotocol/Telemetry.ino index 48f8f2c..e7ff62f 100644 --- a/Multiprotocol/Telemetry.ino +++ b/Multiprotocol/Telemetry.ino @@ -8,10 +8,6 @@ #define USER_MAX_BYTES 6 #define MAX_PKTX 10 uint8_t frame[18]; -uint8_t pass = 0; -uint8_t index; -uint8_t prev_index; -uint8_t pktx[MAX_PKTX]; void frskySendStuffed() { @@ -63,7 +59,8 @@ void frsky_link_frame() #if defined HUB_TELEMETRY void frsky_user_frame() { - uint8_t indexx = 0, c=0, j=8, n=0, i; + static uint8_t indexx = 0, pass=0, index, pktx[MAX_PKTX]; + uint8_t c=0, j=8, n=0, i; if(pktt[6]>0 && pktt[6]<=MAX_PKTX) {//only valid hub frames @@ -93,7 +90,6 @@ void frsky_user_frame() case 1: index=indexx; - prev_index = indexx; if(index Date: Thu, 28 Jan 2016 19:27:56 +0100 Subject: [PATCH 026/293] Revert "Fix: Hubsan telemetry packet check function & Change: Telemetry variables to static" This reverts commit ac78ddcc8240970b153ad0fddad54e8800187656. --- Multiprotocol/Hubsan_a7105.ino | 3 ++- Multiprotocol/Telemetry.ino | 12 ++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/Multiprotocol/Hubsan_a7105.ino b/Multiprotocol/Hubsan_a7105.ino index 760cb4e..f126b34 100644 --- a/Multiprotocol/Hubsan_a7105.ino +++ b/Multiprotocol/Hubsan_a7105.ino @@ -181,10 +181,11 @@ static void __attribute__((unused)) hubsan_build_packet() } #if defined(TELEMETRY) -static uint8_t __attribute__((unused)) hubsan_check_integrity() +static __attribute__((unused)) uint8_t hubsan_check_integrity() { if( (packet[0]&0xFE) != 0xE0 ) return 0; + return 1; uint8_t sum = 0; for(uint8_t i = 0; i < 15; i++) sum += packet[i]; diff --git a/Multiprotocol/Telemetry.ino b/Multiprotocol/Telemetry.ino index e7ff62f..48f8f2c 100644 --- a/Multiprotocol/Telemetry.ino +++ b/Multiprotocol/Telemetry.ino @@ -8,6 +8,10 @@ #define USER_MAX_BYTES 6 #define MAX_PKTX 10 uint8_t frame[18]; +uint8_t pass = 0; +uint8_t index; +uint8_t prev_index; +uint8_t pktx[MAX_PKTX]; void frskySendStuffed() { @@ -59,8 +63,7 @@ void frsky_link_frame() #if defined HUB_TELEMETRY void frsky_user_frame() { - static uint8_t indexx = 0, pass=0, index, pktx[MAX_PKTX]; - uint8_t c=0, j=8, n=0, i; + uint8_t indexx = 0, c=0, j=8, n=0, i; if(pktt[6]>0 && pktt[6]<=MAX_PKTX) {//only valid hub frames @@ -90,6 +93,7 @@ void frsky_user_frame() case 1: index=indexx; + prev_index = indexx; if(index Date: Thu, 28 Jan 2016 19:31:03 +0100 Subject: [PATCH 027/293] Fix: Hubsan telemetry packet check function --- Multiprotocol/Hubsan_a7105.ino | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Multiprotocol/Hubsan_a7105.ino b/Multiprotocol/Hubsan_a7105.ino index f126b34..760cb4e 100644 --- a/Multiprotocol/Hubsan_a7105.ino +++ b/Multiprotocol/Hubsan_a7105.ino @@ -181,11 +181,10 @@ static void __attribute__((unused)) hubsan_build_packet() } #if defined(TELEMETRY) -static __attribute__((unused)) uint8_t hubsan_check_integrity() +static uint8_t __attribute__((unused)) hubsan_check_integrity() { if( (packet[0]&0xFE) != 0xE0 ) return 0; - return 1; uint8_t sum = 0; for(uint8_t i = 0; i < 15; i++) sum += packet[i]; From 2f983f42fe19bb237b050b9462905a902db7e437 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sun, 31 Jan 2016 22:03:43 +0100 Subject: [PATCH 028/293] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 355d2eb..3310c0f 100644 --- a/README.md +++ b/README.md @@ -437,8 +437,8 @@ RF modules can be installed for protocols need only. Example: if you only need t You also need some [antennas](http://www.banggood.com/2_4GHz-3dBi-RP-SMA-Connector-Booster-Wireless-Antenna-Modem-Router-p-979407.html) and [cables](http://www.banggood.com/10cm-PCI-UFL-IPX-to-RPSMA-Female-Jack-Pigtail-Cable-p-924933.html). -###Microcontroller -The main program is running on an ATMEGA328 running @16MHz and 3.3V. +###Board +The main program is running on an ATMEGA328p running @16MHz and 3.3V. An [Arduino pro mini](http://www.banggood.com/Wholesale-New-Ver-Pro-Mini-ATMEGA328-328p-5V-16MHz-Arduino-Compatible-Nano-Size-p-68534.html) can be used to build your own Multimodule. Using stripboard: From 38c6330a2ac9555623586319b15fc88e3d7d9a17 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 1 Feb 2016 11:39:24 +0100 Subject: [PATCH 029/293] CX-10A bind improvement --- Multiprotocol/CX10_nrf24l01.ino | 26 +++++++++++++++++++------- 1 file changed, 19 insertions(+), 7 deletions(-) diff --git a/Multiprotocol/CX10_nrf24l01.ino b/Multiprotocol/CX10_nrf24l01.ino index 044c20c..bf62c44 100644 --- a/Multiprotocol/CX10_nrf24l01.ino +++ b/Multiprotocol/CX10_nrf24l01.ino @@ -19,12 +19,13 @@ #include "iface_nrf24l01.h" -#define CX10_BIND_COUNT 4360 // 6 seconds -#define CX10_PACKET_SIZE 15 -#define CX10A_PACKET_SIZE 19 // CX10 blue board packets have 19-byte payload -#define Q282_PACKET_SIZE 21 -#define CX10_PACKET_PERIOD 1316 // Timeout for callback in uSec -#define CX10A_PACKET_PERIOD 6000 +#define CX10_BIND_COUNT 4360 // 6 seconds +#define CX10_PACKET_SIZE 15 +#define CX10A_PACKET_SIZE 19 // CX10 blue board packets have 19-byte payload +#define Q282_PACKET_SIZE 21 +#define CX10_PACKET_PERIOD 1316 // Timeout for callback in uSec +#define CX10A_PACKET_PERIOD 6000 +#define CX10A_BIND_COUNT 400 // 2 seconds #define INITIAL_WAIT 500 @@ -198,13 +199,22 @@ uint16_t CX10_callback() { } break; case CX10_BIND2: + bind_counter--; + if(bind_counter==0) + { // Needed for some CX-10A to properly finish the bind + CX10_init(); + bind_counter=CX10A_BIND_COUNT; + } if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR)) { // RX fifo data ready XN297_ReadPayload(packet, packet_length); NRF24L01_SetTxRxMode(TXRX_OFF); NRF24L01_SetTxRxMode(TX_EN); if(packet[9] == 1) + { phase = CX10_BIND1; + bind_counter=0; + } } else { @@ -259,8 +269,10 @@ uint16_t initCX10(void) { packet_length = CX10A_PACKET_SIZE; packet_period = CX10A_PACKET_PERIOD; + phase = CX10_BIND2; - bind_counter=0; + bind_counter=CX10A_BIND_COUNT; + for(uint8_t i=0; i<4; i++) packet[5+i] = 0xff; // clear aircraft id packet[9] = 0; From 08dc0db2e217d03aacff9518cffb1c2d461baf76 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 1 Feb 2016 11:41:36 +0100 Subject: [PATCH 030/293] Preparation for new protocol MT99XX (includes H7) --- Multiprotocol/Multiprotocol.ino | 44 ++++++++++++++++++-------------- Multiprotocol/_Config.h | 5 ++++ Multiprotocol/multiprotocol.h | 45 +++++++++++++++++++++------------ 3 files changed, 59 insertions(+), 35 deletions(-) diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 5b927bf..44a4bcf 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -33,12 +33,12 @@ uint32_t MProtocol_id;//tx id, uint32_t MProtocol_id_master; uint32_t Model_fixed_id=0; uint32_t fixed_id; -uint8_t cyrfmfg_id[6];//for dsm2 and devo +uint8_t cyrfmfg_id[6];//for dsm2 and devo uint32_t blink=0; // uint16_t counter; -uint8_t channel; -uint8_t packet[40]; +uint8_t channel; +uint8_t packet[40]; #define NUM_CHN 16 // Servo data @@ -48,26 +48,26 @@ uint8_t Servo_AUX; volatile uint16_t PPM_data[NUM_CHN]; // NRF variables -uint8_t rx_tx_addr[5]; -uint8_t phase; +uint8_t rx_tx_addr[5]; +uint8_t phase; uint16_t bind_counter; -uint8_t bind_phase; -uint8_t binding_idx; +uint8_t bind_phase; +uint8_t binding_idx; uint32_t packet_counter; uint16_t packet_period; -uint8_t packet_count; -uint8_t packet_sent; -uint8_t packet_length; -uint8_t hopping_frequency[23]; -uint8_t *hopping_frequency_ptr; -uint8_t hopping_frequency_no=0; -uint8_t rf_ch_num; -uint8_t throttle, rudder, elevator, aileron; -uint8_t flags; +uint8_t packet_count; +uint8_t packet_sent; +uint8_t packet_length; +uint8_t hopping_frequency[23]; +uint8_t *hopping_frequency_ptr; +uint8_t hopping_frequency_no=0; +uint8_t rf_ch_num; +uint8_t throttle, rudder, elevator, aileron; +uint8_t flags; // uint32_t state; -uint8_t len; -uint8_t RX_num; +uint8_t len; +uint8_t RX_num; // Mode_select variables uint8_t mode_select; @@ -414,6 +414,12 @@ static void protocol_init() next_callback=initESKY(); remote_callback = ESKY_callback; break; +#endif +#if defined(MT99XX_NRF24L01_INO) + case MODE_MT99XX: + next_callback=initMT99XX(); + remote_callback = MT99XX_callback; + break; #endif } @@ -496,7 +502,7 @@ static void module_reset() case MODE_DEVO: CYRF_Reset(); break; - default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY + default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY, MODE_MT99XX NRF24L01_Reset(); break; } diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 9a8a8d2..44d44d6 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -42,6 +42,7 @@ #define V2X2_NRF24L01_INO #define YD717_NRF24L01_INO //#define FRSKYX_CC2500_INO +//#define MT99XX_NRF24L01_INO //Update this table to set which protocol and all associated settings are called for the corresponding dial number static const PPM_Parameters PPM_prot[15]= @@ -116,6 +117,10 @@ static const PPM_Parameters PPM_prot[15]= NONE MODE_ESKY NONE + MODE_MT99XX + MT99 + H7 + YZ RX_Num value between 0 and 15 diff --git a/Multiprotocol/multiprotocol.h b/Multiprotocol/multiprotocol.h index 717ada0..f3fa019 100644 --- a/Multiprotocol/multiprotocol.h +++ b/Multiprotocol/multiprotocol.h @@ -27,23 +27,25 @@ enum PROTOCOLS { MODE_SERIAL = 0, // Serial commands - MODE_FLYSKY = 1, // =>A7105 / FLYSKY protocol - MODE_HUBSAN = 2, // =>A7105 / HUBSAN protocol - MODE_FRSKY = 3, // =>CC2500 / FRSKY protocol - MODE_HISKY = 4, // =>NRF24L01 / HISKY protocol - MODE_V2X2 = 5, // =>NRF24L01 / V2x2 protocol - MODE_DSM2 = 6, // =>CYRF6936 / DSM2 protocol - MODE_DEVO =7, // =>CYRF6936 / DEVO protocol - MODE_YD717 = 8, // =>NRF24L01 / YD717 protocol (CX10 red pcb) - MODE_KN = 9, // =>NRF24L01 / KN protocol - MODE_SYMAX = 10, // =>NRF24L01 / SYMAX protocol - MODE_SLT = 11, // =>NRF24L01 / SLT protocol - MODE_CX10 = 12, // =>NRF24L01 / CX-10 protocol - MODE_CG023 = 13, // =>NRF24L01 / CG023 protocol - MODE_BAYANG = 14, // =>NRF24L01 / BAYANG protocol - MODE_FRSKYX = 15, // =>CC2500 / FRSKYX protocol - MODE_ESKY = 16, // =>NRF24L01 / ESKY protocol + MODE_FLYSKY = 1, // =>A7105 + MODE_HUBSAN = 2, // =>A7105 + MODE_FRSKY = 3, // =>CC2500 + MODE_HISKY = 4, // =>NRF24L01 + MODE_V2X2 = 5, // =>NRF24L01 + MODE_DSM2 = 6, // =>CYRF6936 + MODE_DEVO =7, // =>CYRF6936 + MODE_YD717 = 8, // =>NRF24L01 + MODE_KN = 9, // =>NRF24L01 + MODE_SYMAX = 10, // =>NRF24L01 + MODE_SLT = 11, // =>NRF24L01 + MODE_CX10 = 12, // =>NRF24L01 + MODE_CG023 = 13, // =>NRF24L01 + MODE_BAYANG = 14, // =>NRF24L01 + MODE_FRSKYX = 15, // =>CC2500 + MODE_ESKY = 16, // =>NRF24L01 + MODE_MT99XX=17, // =>NRF24L01 }; + enum Flysky { Flysky=0, @@ -95,6 +97,12 @@ enum CG023 YD829 = 1, H8_3D = 2 }; +enum MT99XX +{ + MT99 = 0, + H7 = 1, + YZ = 2 +}; #define NONE 0 #define P_HIGH 1 @@ -400,6 +408,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- Bayang 14 FrskyX 15 ESky 16 + MT99XX 17 BindBit=> 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No @@ -442,6 +451,10 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- CG023 0 YD829 1 H8_3D 2 + sub_protocol==MT99XX + MT99 0 + H7 1 + YZ 2 Power value => 0x80 0=High/1=Low Stream[3] = option_protocol; option_protocol value is -127..127 From 54accbf21fd577f5b4bcb8a4a103e4bee5f0ac78 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 1 Feb 2016 11:49:10 +0100 Subject: [PATCH 031/293] CG023 small change --- Multiprotocol/CG023_nrf24l01.ino | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/Multiprotocol/CG023_nrf24l01.ino b/Multiprotocol/CG023_nrf24l01.ino index 6810652..de31672 100644 --- a/Multiprotocol/CG023_nrf24l01.ino +++ b/Multiprotocol/CG023_nrf24l01.ino @@ -237,13 +237,7 @@ uint16_t CG023_callback() bind_counter--; } } - - if(sub_protocol==CG023) - return CG023_PACKET_PERIOD; - else - if(sub_protocol==YD829) - return YD829_PACKET_PERIOD; - return H8_3D_PACKET_PERIOD; + return packet_period; } static void __attribute__((unused)) CG023_initialize_txid() @@ -276,11 +270,13 @@ uint16_t initCG023(void) CG023_initialize_txid(); CG023_init(); if(sub_protocol==CG023) - return CG023_INITIAL_WAIT+CG023_PACKET_PERIOD; + packet_period=CG023_PACKET_PERIOD; else if(sub_protocol==YD829) - return CG023_INITIAL_WAIT+YD829_PACKET_PERIOD; - return CG023_INITIAL_WAIT+H8_3D_PACKET_PERIOD; + packet_period=YD829_PACKET_PERIOD; + else + packet_period=H8_3D_PACKET_PERIOD; + return CG023_INITIAL_WAIT+YD829_PACKET_PERIOD; } #endif From 4c8a0b9a63b18a06b4f17f8fa18edfa995a87175 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 1 Feb 2016 12:18:09 +0100 Subject: [PATCH 032/293] MT99XX protocol --- README.md | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/README.md b/README.md index 3310c0f..8730e8c 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,10 @@ CG023||NRF24L01 Bayang||NRF24L01 FrskyX||CC2500 ESky||NRF24L01 +MT99XX||NRF24L01 + |MT + |H7 + |YZ Note: - The dial should be set to 0 for serial. Which means all protocol selection pins should be left unconnected. @@ -379,6 +383,20 @@ Dual Rate: +100%=full range, Throttle Hold: +100%=hold, Idle Up: +100%=3D, GYRO: #####Sub_protocol FEILUN Same channels assignement as above. +####MT99XX +Autobind protocol + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10 +---|---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP||PICTURE|VIDEO|PITCH_Trim|ROLL_Trim + +#####Sub_protocol MT +Models: MT99xx +#####Sub_protocol H7 +Models: Eachine H7 +#####Sub_protocol YZ +Models: YIZHAN YZ i6S + ####SLT Autobind protocol From 11283a2199c541e1bcd5d4c954b5fc579d6224fa Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 1 Feb 2016 13:23:28 +0100 Subject: [PATCH 033/293] MT99xx protocol for MT99xx, Eachine H7, Yi Zhan i6S --- Multiprotocol/FrSky_cc2500.ino | 22 +-- Multiprotocol/MT99xx_nrf24l01.ino | 221 ++++++++++++++++++++++++++++++ Multiprotocol/Telemetry.ino | 18 +++ Multiprotocol/_Config.h | 2 +- Multiprotocol/multiprotocol.h | 2 + 5 files changed, 243 insertions(+), 22 deletions(-) create mode 100644 Multiprotocol/MT99xx_nrf24l01.ino diff --git a/Multiprotocol/FrSky_cc2500.ino b/Multiprotocol/FrSky_cc2500.ino index 449f954..dae03c7 100644 --- a/Multiprotocol/FrSky_cc2500.ino +++ b/Multiprotocol/FrSky_cc2500.ino @@ -178,26 +178,6 @@ uint16_t initFrSky_2way() return 10000; } -#if defined(TELEMETRY) -static void __attribute__((unused)) check_telemetry(uint8_t *pkt,uint8_t len) -{ - if(pkt[1] != rx_tx_addr[3] || pkt[2] != rx_tx_addr[2] || len != pkt[0] + 3) - {//only packets with the required id and packet length - for(uint8_t i=3;i<6;i++) - pktt[i]=0; - return; - } - else - { - for (uint8_t i=3;i0) - telemetry_counter=(telemetry_counter+1)%32; - } -} -#endif - uint16_t ReadFrSky_2way() { if (state < FRSKY_BIND_DONE) @@ -245,7 +225,7 @@ uint16_t ReadFrSky_2way() cc2500_readFifo(pkt, len); //received telemetry packets #if defined(TELEMETRY) //parse telemetry packet here - check_telemetry(pkt,len); //check if valid telemetry packets and buffer them. + frsky_check_telemetry(pkt,len); //check if valid telemetry packets and buffer them. #endif } CC2500_SetTxRxMode(TX_EN); diff --git a/Multiprotocol/MT99xx_nrf24l01.ino b/Multiprotocol/MT99xx_nrf24l01.ino new file mode 100644 index 0000000..b9909a9 --- /dev/null +++ b/Multiprotocol/MT99xx_nrf24l01.ino @@ -0,0 +1,221 @@ +/* + 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 . + */ +// compatible with MT99xx, Eachine H7, Yi Zhan i6S +// Last sync with Goebish mt99xx_nrf24l01.c dated 2016-01-29 + +#if defined(MT99XX_NRF24L01_INO) + +#include "iface_nrf24l01.h" + +#define MT99XX_BIND_COUNT 928 +#define MT99XX_PACKET_PERIOD_MT 2625 +#define MT99XX_PACKET_PERIOD_YZ 3125 +#define MT99XX_INITIAL_WAIT 500 +#define MT99XX_PACKET_SIZE 9 + +#define checksum_offset rf_ch_num +#define channel_offset phase + +enum{ + // flags going to packet[6] (MT99xx, H7) + FLAG_MT_RATE1 = 0x01, // (H7 high rate) + FLAG_MT_RATE2 = 0x02, // (MT9916 only) + FLAG_MT_VIDEO = 0x10, + FLAG_MT_SNAPSHOT= 0x20, + FLAG_MT_FLIP = 0x80, +}; + +enum{ + // flags going to ?????? (Yi Zhan i6S)ROLL + BLABLA, +}; + +enum { + MT99XX_INIT = 0, + MT99XX_BIND, + MT99XX_DATA +}; + +static uint8_t __attribute__((unused)) MT99XX_calcChecksum() +{ + uint8_t result=checksum_offset; + for(uint8_t i=0; i<8; i++) + result += packet[i]; + return result; +} + +static void __attribute__((unused)) MT99XX_send_packet() +{ + static const uint8_t yz_p4_seq[] = {0xa0, 0x20, 0x60}; + static const uint8_t mys_byte[] = { + 0x01, 0x11, 0x02, 0x12, 0x03, 0x13, 0x04, 0x14, + 0x05, 0x15, 0x06, 0x16, 0x07, 0x17, 0x00, 0x10 + }; + static uint8_t yz_seq_num=0; + + if(sub_protocol != YZ) + { // MT99XX & H7 + packet[0] = convert_channel_8b_scale(THROTTLE,0x00,0xE1); // throttle + packet[1] = convert_channel_8b_scale(RUDDER ,0x00,0xE1); // rudder + packet[2] = convert_channel_8b_scale(AILERON ,0x00,0xE1); // aileron + packet[3] = convert_channel_8b_scale(ELEVATOR,0x00,0xE1); // elevator + packet[4] = convert_channel_8b_scale(AUX5,0x00,0x3F); // pitch trim (0x3f-0x20-0x00) + packet[5] = convert_channel_8b_scale(AUX6,0x00,0x3F); // roll trim (0x00-0x20-0x3f) + packet[6] = GET_FLAG( Servo_AUX1, FLAG_MT_FLIP ) + | GET_FLAG( Servo_AUX3, FLAG_MT_SNAPSHOT ) + | GET_FLAG( Servo_AUX4, FLAG_MT_VIDEO ); + if(sub_protocol==MT99) + packet[6] |= 0x40 | FLAG_MT_RATE2; + else + packet[6] |= FLAG_MT_RATE1; // max rate on H7 + // todo: mys_byte = next channel index ? + // low nibble: index in chan list ? + // high nibble: 0->start from start of list, 1->start from end of list ? + packet[7] = mys_byte[hopping_frequency_no]; + packet[8] = MT99XX_calcChecksum(); + } + else + { // YZ + packet[0] = convert_channel_8b_scale(THROTTLE,0x00,0x64); // throttle + packet[1] = convert_channel_8b_scale(RUDDER ,0x00,0x64); // rudder + packet[2] = convert_channel_8b_scale(AILERON ,0x00,0x64); // aileron + packet[3] = convert_channel_8b_scale(ELEVATOR,0x00,0x64); // elevator + if(packet_count++ >= 23) + { + yz_seq_num ++; + if(yz_seq_num > 2) + yz_seq_num = 0; + packet_count=0; + } + packet[4]= yz_p4_seq[yz_seq_num]; + packet[5]= 0x02; // expert ? (0=unarmed, 1=normal) + packet[6] = 0x80; + packet[7] = packet[0]; + for(uint8_t idx = 1; idx < MT99XX_PACKET_SIZE-2; idx++) + packet[7] += packet[idx]; + packet[8] = 0xff; + } + + NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no] + channel_offset); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); + NRF24L01_FlushTx(); + XN297_WritePayload(packet, MT99XX_PACKET_SIZE); + + hopping_frequency_no++; + if(sub_protocol == YZ) + hopping_frequency_no++; // skip every other channel + + if(hopping_frequency_no > 15) + hopping_frequency_no = 0; + + NRF24L01_SetPower(); +} + +static void __attribute__((unused)) MT99XX_init() +{ + NRF24L01_Initialize(); + NRF24L01_SetTxRxMode(TX_EN); + XN297_SetTXAddr((uint8_t *)"\0xCC\0xCC\0xCC\0xCC\0xCC", 5); + NRF24L01_FlushTx(); + 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_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5 bytes address + NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no auto retransmit + if(sub_protocol == YZ) + NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250Kbps (nRF24L01+ only) + else + NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps + NRF24L01_SetPower(); +} + +static void __attribute__((unused)) MT99XX_initialize_txid() +{ + if(sub_protocol == YZ) + { + rx_tx_addr[0] = 0x53; // test (SB id) + rx_tx_addr[1] = 0x00; + } + checksum_offset = (rx_tx_addr[0] + rx_tx_addr[1]) & 0xff; + channel_offset = (((checksum_offset & 0xf0)>>4) + (checksum_offset & 0x0f)) % 8; +} + +uint16_t MT99XX_callback() +{ + if(IS_BIND_DONE_on) + MT99XX_send_packet(); + else + { + if (bind_counter == 0) + { + rx_tx_addr[2] = 0x00; + rx_tx_addr[3] = 0xCC; + rx_tx_addr[4] = 0xCC; + // set tx address for data packets + XN297_SetTXAddr(rx_tx_addr, 5); + BIND_DONE; + } + else + { + NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]); + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); + NRF24L01_FlushTx(); + XN297_WritePayload(packet, MT99XX_PACKET_SIZE); // bind packet + hopping_frequency_no++; + if(sub_protocol == YZ) + hopping_frequency_no++; // skip every other channel + if(hopping_frequency_no > 15) + hopping_frequency_no = 0; + bind_counter--; + } + } + + return packet_period; +} + +uint16_t initMT99XX(void) +{ + BIND_IN_PROGRESS; // autobind protocol + bind_counter = MT99XX_BIND_COUNT; + + memcpy(hopping_frequency,"\0x02\0x48\0x0C\0x3e\0x16\0x34\0x20\0x2A,\0x2A\0x20\0x34\0x16\0x3e\0x0c\0x48\0x02",16); + + MT99XX_initialize_txid(); + MT99XX_init(); + + packet[0] = 0x20; + if(sub_protocol!=YZ) + { // MT99 & H7 + packet_period = MT99XX_PACKET_PERIOD_MT; + packet[1] = 0x14; + packet[2] = 0x03; + packet[3] = 0x25; + } + else + { // YZ + packet_period = MT99XX_PACKET_PERIOD_YZ; + packet[1] = 0x15; + packet[2] = 0x05; + packet[3] = 0x06; + } + packet[4] = rx_tx_addr[0]; // 1th byte for data state tx address + packet[5] = rx_tx_addr[1]; // 2th byte for data state tx address (always 0x00 on Yi Zhan ?) + packet[6] = 0x00; // 3th byte for data state tx address (always 0x00 ?) + packet[7] = checksum_offset; // checksum offset + packet[8] = 0xAA; // fixed + packet_count=0; + return MT99XX_INITIAL_WAIT+MT99XX_PACKET_PERIOD_MT; +} +#endif diff --git a/Multiprotocol/Telemetry.ino b/Multiprotocol/Telemetry.ino index 48f8f2c..39555d7 100644 --- a/Multiprotocol/Telemetry.ino +++ b/Multiprotocol/Telemetry.ino @@ -37,6 +37,24 @@ void compute_RSSIdbm(){ RSSI_dBm += 65; } +void frsky_check_telemetry(uint8_t *pkt,uint8_t len) +{ + if(pkt[1] != rx_tx_addr[3] || pkt[2] != rx_tx_addr[2] || len != pkt[0] + 3) + {//only packets with the required id and packet length + for(uint8_t i=3;i<6;i++) + pktt[i]=0; + return; + } + else + { + for (uint8_t i=3;i0) + telemetry_counter=(telemetry_counter+1)%32; + } +} + void frsky_link_frame() { frame[0] = 0xFE; diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 44d44d6..3558c99 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -42,7 +42,7 @@ #define V2X2_NRF24L01_INO #define YD717_NRF24L01_INO //#define FRSKYX_CC2500_INO -//#define MT99XX_NRF24L01_INO +#define MT99XX_NRF24L01_INO //Update this table to set which protocol and all associated settings are called for the corresponding dial number static const PPM_Parameters PPM_prot[15]= diff --git a/Multiprotocol/multiprotocol.h b/Multiprotocol/multiprotocol.h index f3fa019..c1b3f35 100644 --- a/Multiprotocol/multiprotocol.h +++ b/Multiprotocol/multiprotocol.h @@ -244,6 +244,8 @@ struct PPM_Parameters #define Servo_AUX7 Servo_AUX & _BV(6) #define Servo_AUX8 Servo_AUX & _BV(7) +#define GET_FLAG(ch, mask) ( ch ? mask : 0) + //************************ //*** Power settings *** //************************ From 846292442c80c8cfe19df042cc741d2fb266f7a8 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 1 Feb 2016 15:19:12 +0100 Subject: [PATCH 034/293] CX10 sub protocol details --- README.md | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 8730e8c..79fda2b 100644 --- a/README.md +++ b/README.md @@ -169,8 +169,8 @@ SymaX||NRF24L01 |SYMAX5C SLT||NRF24L01 CX10||NRF24L01 - |CX10_GREEN - |CX10_BLUE + |GREEN + |BLUE |DM007 |Q282 |JC3015_1 @@ -248,12 +248,12 @@ A|E|T|R|FLIP|RATE Rate: -100%=rate 1, 0%=rate 2, +100%=rate 3 -#####Sub_protocol CX10_GREEN +#####Sub_protocol GREEN Models: Cheerson CX-10 green pcb Same channels assignement as above. -#####Sub_protocol CX10_BLUE +#####Sub_protocol BLUE Models: Cheerson CX-10 blue pcb & some newer red pcb, CX-10A, CX-10C, CX11, CX12, Floureon FX10, JJRC DHD D1 CH5|CH6|CH7|CH8 @@ -262,31 +262,33 @@ FLIP|RATE|PICTURE|VIDEO Rate: -100%=rate 1, 0%=rate 2, +100%=rate 3 or headless for CX-10A -#####Sub_protocol CX10_DM007 +#####Sub_protocol DM007 CH5|CH6|CH7|CH8|CH9 ---|---|---|---|--- FLIP|MODE|PICTURE|VIDEO|HEADLESS -#####Sub_protocol CX10_Q282 and CX10_Q242 +#####Sub_protocol Q282 and Q242 CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 ---|---|---|---|---|---|---|--- FLIP|LED|PICTURE|VIDEO|HEADLESS|RTH|XCAL|YCAL -#####Sub_protocol CX10_JC3015_1 +Model: JXD 509 is using CX10_Q282 with CH12=Start/Stop motors + +#####Sub_protocol JC3015_1 CH5|CH6|CH7|CH8 ---|---|---|--- FLIP|MODE|PICTURE|VIDEO -#####Sub_protocol CX10_JC3015_2 +#####Sub_protocol JC3015_2 CH5|CH6|CH7|CH8 ---|---|---|--- FLIP|MODE|LED|DFLIP -#####Sub_protocol CX10_MK33041 +#####Sub_protocol MK33041 CH5|CH6|CH7|CH8|CH9|CH10 ---|---|---|---|---|--- From d2d70dcb389b7a8859476752d22dbe499964d13f Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 1 Feb 2016 15:21:14 +0100 Subject: [PATCH 035/293] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 79fda2b..3eb9664 100644 --- a/README.md +++ b/README.md @@ -126,7 +126,7 @@ Dial|Protocol|Sub_protocol|RX Num|Power|Auto Bind|Option|RF Module 9|KN|WLTOYS|0|High|No|0|NRF24L01 10|SYMAX|SYMAX|0|High|No|0|NRF24L01 11|SLT|-|0|High|No|0|NRF24L01 -12|CX10|CX10_BLUE|0|High|No|0|NRF24L01 +12|CX10|BLUE|0|High|No|0|NRF24L01 13|CG023|CG023|0|High|No|0|NRF24L01 14|BAYANG|-|0|High|No|0|NRF24L01 15|SYMAX|SYMAX5C|0|High|No|0|NRF24L01 @@ -274,7 +274,7 @@ CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 ---|---|---|---|---|---|---|--- FLIP|LED|PICTURE|VIDEO|HEADLESS|RTH|XCAL|YCAL -Model: JXD 509 is using CX10_Q282 with CH12=Start/Stop motors +Model: JXD 509 is using Q282 with CH12=Start/Stop motors #####Sub_protocol JC3015_1 From c059915bd366aea2a0b144485cc29bcffc45b9cd Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 1 Feb 2016 15:22:58 +0100 Subject: [PATCH 036/293] Update README.md --- README.md | 3 --- 1 file changed, 3 deletions(-) diff --git a/README.md b/README.md index 3eb9664..ca04a89 100644 --- a/README.md +++ b/README.md @@ -187,7 +187,6 @@ ESky||NRF24L01 MT99XX||NRF24L01 |MT |H7 - |YZ Note: - The dial should be set to 0 for serial. Which means all protocol selection pins should be left unconnected. @@ -396,8 +395,6 @@ A|E|T|R|FLIP||PICTURE|VIDEO|PITCH_Trim|ROLL_Trim Models: MT99xx #####Sub_protocol H7 Models: Eachine H7 -#####Sub_protocol YZ -Models: YIZHAN YZ i6S ####SLT Autobind protocol From c26de3bd675c2774c72d2ea8d0539c470c0665c0 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 2 Feb 2016 16:00:34 +0100 Subject: [PATCH 037/293] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ca04a89..35d9bdf 100644 --- a/README.md +++ b/README.md @@ -456,7 +456,7 @@ You also need some [antennas](http://www.banggood.com/2_4GHz-3dBi-RP-SMA-Connect ###Board The main program is running on an ATMEGA328p running @16MHz and 3.3V. -An [Arduino pro mini](http://www.banggood.com/Wholesale-New-Ver-Pro-Mini-ATMEGA328-328p-5V-16MHz-Arduino-Compatible-Nano-Size-p-68534.html) can be used to build your own Multimodule. +An [Arduino pro mini 16Mhz/5V](http://www.banggood.com/Wholesale-New-Ver-Pro-Mini-ATMEGA328-328p-5V-16MHz-Arduino-Compatible-Nano-Size-p-68534.html) powered at 3.3V (yes it works) can be used to build your own Multimodule. Using stripboard: From 626613b545ce5390ae019423a4a699628308f058 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 2 Feb 2016 16:02:16 +0100 Subject: [PATCH 038/293] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 35d9bdf..ba40567 100644 --- a/README.md +++ b/README.md @@ -17,7 +17,7 @@ The source code is partly based on the Deviation TX project, thanks to all the d [Hardware](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#hardware) -[Compilation and programmation](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#compilation) +[Compilation and programmation](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#compilation-and-programmation) [Troubleshooting](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#troubleshooting) From 4f23af070e76d07d0477118aa9cef2db76de98e0 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 3 Feb 2016 17:49:42 +0100 Subject: [PATCH 039/293] Update README.md --- README.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index ba40567..3a53810 100644 --- a/README.md +++ b/README.md @@ -526,17 +526,21 @@ This will make sure your ATMEGA328 is well configured and the global TX ID is no - fast blink: bind in progress. - on: normal operation. +###Protocol selection +####Input Mode - PPM +- The protocol/mode selection must be done before the power is applied. +- Connect 1 to 4 of the selection protocol pins to GND. + +####Input Mode - Serial +- Make sure you have done the mods to the v2.3c PCB by adding the 1k and 330 ohm resistors as indicated in the [Board section] (https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#board). +- Leave all 4 selection pins unconnected. + ###Bind Make sure to follow this procedure: press the bind button, apply power and then release it after 1sec. The LED should be blinking fast indicating a bind status and then fixed on when the bind period is over. It's normal that the LED turns off when you press the bind button, this behavior is not controlled by the Atmega328. For serial, the preffered method is to bind via the GUI protocol page. It migth happen that your module is always binding at power up. If this is the case, there is a big chance that you are using an Arduino Pro Mini with an external status LED. To work around this issue connect a 10K resistor between D13 and 3.3V. -###Protocol selection -For serial, leave all 4 selection pins unconnected. -For PPM, connect 1 to 4 of the selection protocol pins to GND. -The protocol/mode selection must be done before the power is applied. - ###Report issues You can report your problem using the [GitHub issue](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/issues) system or go to the [Main thread on RCGROUPS](http://www.rcgroups.com/forums/showthread.php?t=2165676) to ask your question. Please provide the following information: From 855ca771941e84ebb45f57467e24e99c3fa459bd Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 3 Feb 2016 18:24:56 +0100 Subject: [PATCH 040/293] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 3a53810..09e9958 100644 --- a/README.md +++ b/README.md @@ -532,7 +532,7 @@ This will make sure your ATMEGA328 is well configured and the global TX ID is no - Connect 1 to 4 of the selection protocol pins to GND. ####Input Mode - Serial -- Make sure you have done the mods to the v2.3c PCB by adding the 1k and 330 ohm resistors as indicated in the [Board section] (https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#board). +- Make sure you have done the mods to the v2.3c PCB by adding the 2.2k and 330 ohm resistors as indicated in the [Board section] (https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#board). - Leave all 4 selection pins unconnected. ###Bind From c90db8594ac3c702a5de261965693e76ff61a0a1 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 3 Feb 2016 18:32:08 +0100 Subject: [PATCH 041/293] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 09e9958..20deaf9 100644 --- a/README.md +++ b/README.md @@ -474,8 +474,7 @@ or build your own board using [SMD components](http://www.rcgroups.com/forums/sh ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7952726-108-thumb-image-62c29cf2.jpg?d=1433909893) ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7952733-114-thumb-P4100002.JPG?d=1433910155) ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7952734-189-thumb-P4100003.JPG?d=1433910159) -If you build this PCB v2.3c and want to enable serial mode for er9x/ersky9x, you should do [this mod](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8180322-194-multi.jpg): -![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t8180322-35-thumb-multi.jpg?d=1440422869) +**If you build this PCB v2.3c and want to enable serial mode for er9x/ersky9x, you have to do [this mod](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8667856-242-multi.jpg).** ###Schematic From db8e4a03a888a334fd67664319bcdf96d6e6128e Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 4 Feb 2016 13:24:16 +0100 Subject: [PATCH 042/293] New protocol MJXQ and FTDI upload method --- README.md | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) diff --git a/README.md b/README.md index 20deaf9..6b2bce0 100644 --- a/README.md +++ b/README.md @@ -187,6 +187,12 @@ ESky||NRF24L01 MT99XX||NRF24L01 |MT |H7 + |YZ +MJXQ||NRF24L01 + |WLH08 + |X600 + |X800 + |H26D Note: - The dial should be set to 0 for serial. Which means all protocol selection pins should be left unconnected. @@ -384,6 +390,18 @@ Dual Rate: +100%=full range, Throttle Hold: +100%=hold, Idle Up: +100%=3D, GYRO: #####Sub_protocol FEILUN Same channels assignement as above. +####MJXQ +Autobind protocol + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13 +---|---|---|---|---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP|LED|PICTURE|VIDEO|HEADLESS|RTH|AUTOFLIP|PAN|TILT + +#####Sub_protocol WLH08 +#####Sub_protocol X600 +#####Sub_protocol X800 +#####Sub_protocol H26D + ####MT99XX Autobind protocol @@ -395,6 +413,8 @@ A|E|T|R|FLIP||PICTURE|VIDEO|PITCH_Trim|ROLL_Trim Models: MT99xx #####Sub_protocol H7 Models: Eachine H7 +#####Sub_protocol YZ +In progress... ####SLT Autobind protocol @@ -508,6 +528,17 @@ From the Arduino environment, you can use this shortcut to compile and upload to To flash the latest provided hex file under [Release](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases), you can use a tool like [AVR Burn-O-Mat](http://avr8-burn-o-mat.aaabbb.de/), set the microcontroller to m328p and flash it. +###Upload the code using FTDI (USB serial to TTL) +Use this method only for Arduino Pro Mini boards with bootloader. + +Use an external FTDI adapter like [this one](http://www.banggood.com/FT232RL-FTDI-USB-To-TTL-Serial-Converter-Adapter-Module-For-Arduino-p-917226.html). + +The programmer should be set to 3.3V or nothing to not supply any over voltage to the multimodule and avoid any damages. + +From the Arduino environment, you can use Upload button which will compile and upload to the module: Skecth->Upload (Ctrl+U) + +To upload the latest provided hex file under [Release](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases), you can use a tool like [XLoader](http://russemotto.com/xloader/), set the microcontroller to Atmega328 and upload it. + ###Set fuses Use a tool like [AVR Burn-O-Mat](http://avr8-burn-o-mat.aaabbb.de/) to set the fuses of the Atmega328 to: - Low Fuse 0xFF From 86d3d2627341914db8d6435d9d4bc70376b41c62 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 4 Feb 2016 13:35:16 +0100 Subject: [PATCH 043/293] New protocol MJXQ --- Multiprotocol/CG023_nrf24l01.ino | 49 +++--- Multiprotocol/CX10_nrf24l01.ino | 76 +++++---- Multiprotocol/KN_nrf24l01.ino | 8 +- Multiprotocol/MJXQ_nrf24l01.ino | 247 ++++++++++++++++++++++++++++++ Multiprotocol/MT99xx_nrf24l01.ino | 10 +- Multiprotocol/Multiprotocol.ino | 8 +- Multiprotocol/V2X2_nrf24l01.ino | 6 +- Multiprotocol/_Config.h | 36 +++-- Multiprotocol/multiprotocol.h | 14 ++ 9 files changed, 360 insertions(+), 94 deletions(-) create mode 100644 Multiprotocol/MJXQ_nrf24l01.ino diff --git a/Multiprotocol/CG023_nrf24l01.ino b/Multiprotocol/CG023_nrf24l01.ino index de31672..0e5c0ce 100644 --- a/Multiprotocol/CG023_nrf24l01.ino +++ b/Multiprotocol/CG023_nrf24l01.ino @@ -104,6 +104,8 @@ static void __attribute__((unused)) CG023_send_packet(uint8_t bind) packet[6] = 0x08; packet[7] = 0x03; packet[9] = throttle; + if(rudder==0x01) rudder=0; // Small deadband + if(rudder==0x81) rudder=0; // Small deadband packet[10] = rudder; packet[11] = elevator; packet[12] = aileron; @@ -112,15 +114,11 @@ static void __attribute__((unused)) CG023_send_packet(uint8_t bind) packet[14] = 0x20; packet[15] = 0x20; packet[16] = 0x20; - packet[17] = H8_3D_FLAG_RATE_HIGH; - if(Servo_AUX1) - packet[17] |= H8_3D_FLAG_FLIP; - if(Servo_AUX2) - packet[17] |= H8_3D_FLAG_LIGTH; //H22 light - if(Servo_AUX3) - packet[17] |= H8_3D_FLAG_HEADLESS; - if(Servo_AUX4) - packet[17] |= H8_3D_FLAG_RTH; // 180/360 flip mode on H8 3D + packet[17] = H8_3D_FLAG_RATE_HIGH + | GET_FLAG(Servo_AUX1,H8_3D_FLAG_FLIP) + | GET_FLAG(Servo_AUX2,H8_3D_FLAG_LIGTH) //H22 light + | GET_FLAG(Servo_AUX3,H8_3D_FLAG_HEADLESS) + | GET_FLAG(Servo_AUX4,H8_3D_FLAG_RTH); // 180/360 flip mode on H8 3D if(Servo_AUX5) packet[18] = H8_3D_FLAG_CALIBRATE; } @@ -152,32 +150,21 @@ static void __attribute__((unused)) CG023_send_packet(uint8_t bind) if(sub_protocol==CG023) { // rate - packet[13] = CG023_FLAG_RATE_HIGH; - // flags - if(Servo_AUX1) - packet[13] |= CG023_FLAG_FLIP; - if(Servo_AUX2) - packet[13] |= CG023_FLAG_LED_OFF; - if(Servo_AUX3) - packet[13] |= CG023_FLAG_STILL; - if(Servo_AUX4) - packet[13] |= CG023_FLAG_VIDEO; - if(Servo_AUX5) - packet[13] |= CG023_FLAG_EASY; + packet[13] = CG023_FLAG_RATE_HIGH + | GET_FLAG(Servo_AUX1,CG023_FLAG_FLIP) + | GET_FLAG(Servo_AUX2,CG023_FLAG_LED_OFF) + | GET_FLAG(Servo_AUX3,CG023_FLAG_STILL) + | GET_FLAG(Servo_AUX4,CG023_FLAG_VIDEO) + | GET_FLAG(Servo_AUX5,CG023_FLAG_EASY); } else {// YD829 // rate - packet[13] = YD829_FLAG_RATE_HIGH; - // flags - if(Servo_AUX1) - packet[13] |= YD829_FLAG_FLIP; - if(Servo_AUX3) - packet[13] |= YD829_FLAG_STILL; - if(Servo_AUX4) - packet[13] |= YD829_FLAG_VIDEO; - if(Servo_AUX5) - packet[13] |= YD829_FLAG_HEADLESS; + packet[13] = YD829_FLAG_RATE_HIGH + | GET_FLAG(Servo_AUX1,YD829_FLAG_FLIP) + | GET_FLAG(Servo_AUX3,YD829_FLAG_STILL) + | GET_FLAG(Servo_AUX4,YD829_FLAG_VIDEO) + | GET_FLAG(Servo_AUX5,YD829_FLAG_HEADLESS); } packet[14] = 0; } diff --git a/Multiprotocol/CX10_nrf24l01.ino b/Multiprotocol/CX10_nrf24l01.ino index bf62c44..6722fcd 100644 --- a/Multiprotocol/CX10_nrf24l01.ino +++ b/Multiprotocol/CX10_nrf24l01.ino @@ -12,7 +12,7 @@ You should have received a copy of the GNU General Public License along with Multiprotocol. If not, see . */ -// compatible with Cheerson CX-10 blue & newer red pcb, CX-10A, CX11, CX-10 green pcb, DM007, Floureon FX-10, CX-Stars +// compatible with Cheerson CX-10 blue & newer red pcb, CX-10A, CX11, CX-10 green pcb, DM007, Floureon FX-10, JXD 509 (Q282) // Last sync with hexfet new_protocols/cx10_nrf24l01.c dated 2015-11-26 #if defined(CX10_NRF24L01_INO) @@ -27,7 +27,7 @@ #define CX10A_PACKET_PERIOD 6000 #define CX10A_BIND_COUNT 400 // 2 seconds -#define INITIAL_WAIT 500 +#define CX10_INITIAL_WAIT 500 // flags #define CX10_FLAG_FLIP 0x10 // goes to rudder channel @@ -38,8 +38,8 @@ #define CX10_FLAG_SNAPSHOT 0x04 // frequency channel management -#define RF_BIND_CHANNEL 0x02 -#define NUM_RF_CHANNELS 4 +#define CX10_RF_BIND_CHANNEL 0x02 +#define CX10_NUM_RF_CHANNELS 4 enum { CX10_BIND1 = 0, @@ -87,63 +87,61 @@ static void __attribute__((unused)) CX10_Write_Packet(uint8_t bind) switch(sub_protocol) { case CX10_BLUE: - if(Servo_AUX3) flags |= 0x10; // Channel 7 - picture - if(Servo_AUX4) flags |= 0x08; // Channel 8 - video + flags |= GET_FLAG(!Servo_AUX3, 0x10) // Channel 7 - picture + |GET_FLAG( Servo_AUX4, 0x08); // Channel 8 - video break; case Q282: case Q242: memcpy(&packet[15], "\x10\x10\xaa\xaa\x00\x00", 6); //FLIP|LED|PICTURE|VIDEO|HEADLESS|RTH|XCAL|YCAL - if(Servo_AUX1) flags2 =0x80; // Channel 5 - FLIP - if(Servo_AUX2) flags2|=0x40; // Channel 6 - LED - - if(Servo_AUX5) flags2|=0x08; // Channel 9 - HEADLESS + flags2 = GET_FLAG(Servo_AUX1, 0x80) // Channel 5 - FLIP + |GET_FLAG(Servo_AUX2, 0x40) // Channel 6 - LED + |GET_FLAG(Servo_AUX5, 0x08) // Channel 9 - HEADLESS + |GET_FLAG(Servo_AUX7, 0x04) // Channel 11 - XCAL + |GET_FLAG(Servo_AUX8, 0x02); // Channel 12 - YCAL or Start/Stop motors on JXD 509 + if(sub_protocol==Q282) { - if(Servo_AUX3) flags2|=0x10; // Channel 7 - picture - if(Servo_AUX4) // Channel 8 - video + flags=3; + if(Servo_AUX4) // Channel 8 - video { if (!(video_state & 0x20)) video_state ^= 0x21; } else if (video_state & 0x20) video_state &= 0x01; - flags2 |= video_state; - flags=3; + flags2 |= video_state + |GET_FLAG(Servo_AUX3,0x10); // Channel 7 - picture } else { - if(Servo_AUX3) flags2|=0x01; // Channel 7 - picture - if(Servo_AUX4) flags2|=0x10; // Channel 8 - video flags=2; + flags2|= GET_FLAG(Servo_AUX3,0x01) // Channel 7 - picture + |GET_FLAG(Servo_AUX4,0x10); // Channel 8 - video packet[17]=0x00; packet[18]=0x00; } - if(Servo_AUX6) flags |=0x80; // Channel 10 - RTH - if(Servo_AUX7) flags2|=0x04; // Channel 11 - XCAL - if(Servo_AUX8) flags2|=0x02; // Channel 12 - YCAL + if(Servo_AUX6) flags |=0x80; // Channel 10 - RTH break; case DM007: //FLIP|MODE|PICTURE|VIDEO|HEADLESS - if(Servo_AUX3) flags2 = CX10_FLAG_SNAPSHOT; // Channel 7 - picture - if(Servo_AUX4) flags2|= CX10_FLAG_VIDEO; // Channel 8 - video - if(Servo_AUX5) flags |= CX10_FLAG_HEADLESS; // Channel 9 - headless - break; - case JC3015_1: - //FLIP|MODE|PICTURE|VIDEO - if(Servo_AUX3) flags2 = _BV(3); // Channel 7 - picture - if(Servo_AUX4) flags2|= _BV(4); // Channel 8 - video + flags2= GET_FLAG(Servo_AUX3,CX10_FLAG_SNAPSHOT) // Channel 7 - picture + |GET_FLAG(Servo_AUX4,CX10_FLAG_VIDEO); // Channel 8 - video + if(Servo_AUX5) flags |= CX10_FLAG_HEADLESS; // Channel 9 - headless break; case JC3015_2: //FLIP|MODE|LED|DFLIP - if(Servo_AUX3) flags2 = _BV(3); // Channel 7 - LED - if(Servo_AUX4) flags2|= _BV(4); // Channel 8 - DFLIP + if(Servo_AUX4) packet[12] &= ~CX10_FLAG_FLIP; + case JC3015_1: + //FLIP|MODE|PICTURE|VIDEO + flags2= GET_FLAG(Servo_AUX3,_BV(3)) // Channel 7 + |GET_FLAG(Servo_AUX4,_BV(4)); // Channel 8 break; case MK33041: //FLIP|MODE|PICTURE|VIDEO|HEADLESS|RTH - if(Servo_AUX3) flags |= _BV(7); // Channel 7 - picture - if(Servo_AUX4) flags2 = _BV(0); // Channel 8 - video - if(Servo_AUX5) flags2|= _BV(5); // Channel 9 - headless - if(Servo_AUX6) flags |= _BV(2); // Channel 10 - rth + flags|=GET_FLAG(Servo_AUX3,_BV(7)) // Channel 7 - picture + |GET_FLAG(Servo_AUX6,_BV(2)); // Channel 10 - rth + flags2=GET_FLAG(Servo_AUX4,_BV(0)) // Channel 8 - video + |GET_FLAG(Servo_AUX5,_BV(5)); // Channel 9 - headless break; } packet[13+offset]=flags; @@ -153,11 +151,11 @@ static void __attribute__((unused)) CX10_Write_Packet(uint8_t bind) // Why CRC0? xn297 does not interpret it - either 16-bit CRC or nothing XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP)); if (bind) - NRF24L01_WriteReg(NRF24L01_05_RF_CH, RF_BIND_CHANNEL); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, CX10_RF_BIND_CHANNEL); else { NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]); - hopping_frequency_no %= NUM_RF_CHANNELS; + hopping_frequency_no %= CX10_NUM_RF_CHANNELS; } // clear packet status bits and TX FIFO NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); @@ -179,7 +177,7 @@ static void __attribute__((unused)) CX10_init() NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgment on all data pipes NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, packet_length); // rx pipe 0 (used only for blue board) - NRF24L01_WriteReg(NRF24L01_05_RF_CH, RF_BIND_CHANNEL); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, CX10_RF_BIND_CHANNEL); NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps NRF24L01_SetPower(); } @@ -236,7 +234,7 @@ uint16_t CX10_callback() { return packet_period; } -static void __attribute__((unused)) initialize_txid() +static void __attribute__((unused)) CX10_initialize_txid() { rx_tx_addr[1]%= 0x30; if(sub_protocol==Q282) @@ -287,10 +285,10 @@ uint16_t initCX10(void) phase = CX10_BIND1; bind_counter = CX10_BIND_COUNT; } - initialize_txid(); + CX10_initialize_txid(); CX10_init(); BIND_IN_PROGRESS; // autobind protocol - return INITIAL_WAIT+packet_period; + return CX10_INITIAL_WAIT+packet_period; } #endif diff --git a/Multiprotocol/KN_nrf24l01.ino b/Multiprotocol/KN_nrf24l01.ino index 53e902d..9e0775b 100644 --- a/Multiprotocol/KN_nrf24l01.ino +++ b/Multiprotocol/KN_nrf24l01.ino @@ -144,13 +144,13 @@ static void __attribute__((unused)) kn_update_packet_control_data() packet[11] = 0x64; // R flags=0; - if (Servo_data[AUX1] > PPM_SWITCH) + if (Servo_AUX1) flags = KN_FLAG_DR; - if (Servo_data[AUX2] > PPM_SWITCH) + if (Servo_AUX2) flags |= KN_FLAG_TH; - if (Servo_data[AUX3] > PPM_SWITCH) + if (Servo_AUX3) flags |= KN_FLAG_IDLEUP; - if (Servo_data[AUX4] > PPM_SWITCH) + if (Servo_AUX4) flags |= KN_FLAG_GYRO3; packet[12] = flags; diff --git a/Multiprotocol/MJXQ_nrf24l01.ino b/Multiprotocol/MJXQ_nrf24l01.ino new file mode 100644 index 0000000..484e798 --- /dev/null +++ b/Multiprotocol/MJXQ_nrf24l01.ino @@ -0,0 +1,247 @@ +/* + 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 . + */ +// compatible with MJX WLH08, X600, X800, H26D +// Last sync with hexfet new_protocols/mjxq_nrf24l01.c dated 2016-01-17 + +#if defined(MJXQ_NRF24L01_INO) + +#include "iface_nrf24l01.h" + +#define MJXQ_BIND_COUNT 150 +#define MJXQ_PACKET_PERIOD 4000 // Timeout for callback in uSec +#define MJXQ_INITIAL_WAIT 500 +#define MJXQ_PACKET_SIZE 16 +#define MJXQ_RF_NUM_CHANNELS 4 +#define MJXQ_ADDRESS_LENGTH 5 + +#define MJXQ_PAN_TILT_COUNT 16 // for H26D - match stock tx timing +#define MJXQ_PAN_DOWN 0x08 +#define MJXQ_PAN_UP 0x04 +#define MJXQ_TILT_DOWN 0x20 +#define MJXQ_TILT_UP 0x10 +static uint8_t __attribute__((unused)) MJXQ_pan_tilt_value() +{ +// Servo_AUX8 PAN // H26D +// Servo_AUX9 TILT + uint8_t pan = 0; + packet_count++; + if(packet_count & MJXQ_PAN_TILT_COUNT) + { + if(Servo_AUX8) + pan=MJXQ_PAN_UP; + if(Servo_data[AUX8]PPM_MIN_COMMAND) + pan=MJXQ_TILT_UP; + if(Servo_data[AUX9]> 1) +static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind) +{ + packet[0] = convert_channel_8b(THROTTLE); + packet[1] = convert_channel_s8b(RUDDER); + packet[4] = 0x40; // rudder does not work well with dyntrim + packet[2] = convert_channel_s8b(ELEVATOR); + packet[5] = MJXQ_CHAN2TRIM(packet[2]); // trim elevator + packet[3] = convert_channel_s8b(AILERON); + packet[6] = MJXQ_CHAN2TRIM(packet[3]); // trim aileron + packet[7] = rx_tx_addr[0]; + packet[8] = rx_tx_addr[1]; + packet[9] = rx_tx_addr[2]; + + packet[10] = 0x00; // overwritten below for feature bits + packet[11] = 0x00; // overwritten below for X600 + packet[12] = 0x00; + packet[13] = 0x00; + + packet[14] = 0xC0; // bind value + +// Servo_AUX1 FLIP +// Servo_AUX2 LED +// Servo_AUX3 PICTURE +// Servo_AUX4 VIDEO +// Servo_AUX5 HEADLESS +// Servo_AUX6 RTH +// Servo_AUX7 AUTOFLIP // X800, X600 + switch(sub_protocol) + { + case H26D: + packet[10]=MJXQ_pan_tilt_value(); + // fall through on purpose - no break + case WLH08: + packet[10] += GET_FLAG(Servo_AUX6, 0x02) //RTH + | GET_FLAG(Servo_AUX5, 0x01); //HEADLESS + if (!bind) + { + packet[14] = 0x04 + | GET_FLAG(Servo_AUX1, 0x01) //FLIP + | GET_FLAG(Servo_AUX3, 0x08) //PICTURE + | GET_FLAG(Servo_AUX4, 0x10) //VIDEO + | GET_FLAG(!Servo_AUX2, 0x20); // air/ground mode + } + break; + case X600: + if(Servo_AUX5) //HEADLESS + { // driven trims cause issues when headless is enabled + packet[5] = 0x40; + packet[6] = 0x40; + } + packet[10] = GET_FLAG(!Servo_AUX2, 0x02); //LED + packet[11] = GET_FLAG(Servo_AUX6, 0x01); //RTH + if (!bind) + { + packet[14] = 0x02 // always high rates by bit2 = 1 + | GET_FLAG(Servo_AUX1, 0x04) //FLIP + | GET_FLAG(Servo_AUX7, 0x10) //AUTOFLIP + | GET_FLAG(Servo_AUX5, 0x20); //HEADLESS + } + break; + case X800: + default: + packet[10] = 0x10 + | GET_FLAG(!Servo_AUX2, 0x02) //LED + | GET_FLAG(Servo_AUX7, 0x01); //AUTOFLIP + if (!bind) + { + packet[14] = 0x02 // always high rates by bit2 = 1 + | GET_FLAG(Servo_AUX1, 0x04) //FLIP + | GET_FLAG(Servo_AUX3, 0x08) //PICTURE + | GET_FLAG(Servo_AUX4, 0x10); //VIDEO + } + break; + } + + uint8_t sum = packet[0]; + for (uint8_t i=1; i < MJXQ_PACKET_SIZE-1; i++) sum += packet[i]; + packet[15] = sum; + + // Power on, TX mode, 2byte CRC + if (sub_protocol == H26D) + 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, hopping_frequency[hopping_frequency_no++ / 2]); + hopping_frequency_no %= 2 * MJXQ_RF_NUM_CHANNELS; // channels repeated + + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); + NRF24L01_FlushTx(); + + if (sub_protocol == H26D) + NRF24L01_WritePayload(packet, MJXQ_PACKET_SIZE); + else + XN297_WritePayload(packet, MJXQ_PACKET_SIZE); + + NRF24L01_SetPower(); +} + +static void __attribute__((unused)) MJXQ_init() +{ + uint8_t addr[MJXQ_ADDRESS_LENGTH]; + memcpy(addr, "\x6d\x6a\x77\x77\x77", MJXQ_ADDRESS_LENGTH); + if (sub_protocol == WLH08) + memcpy(hopping_frequency, "\x12\x22\x32\x42", MJXQ_RF_NUM_CHANNELS); + else + if (sub_protocol == H26D) + memcpy(hopping_frequency, "\x36\x3e\x46\x2e", MJXQ_RF_NUM_CHANNELS); + else + { + memcpy(hopping_frequency, "\x0a\x35\x42\x3d", MJXQ_RF_NUM_CHANNELS); + memcpy(addr, "\x6d\x6a\x73\x73\x73", MJXQ_RF_NUM_CHANNELS); + } + + + NRF24L01_Initialize(); + NRF24L01_SetTxRxMode(TX_EN); + + if (sub_protocol == H26D) + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, addr, MJXQ_ADDRESS_LENGTH); + else + XN297_SetTXAddr(addr, MJXQ_ADDRESS_LENGTH); + + 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 Acknowledgment on all data pipes + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only + NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits + NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, MJXQ_PACKET_SIZE); // rx pipe 0 (used only for blue board) + NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps + NRF24L01_SetPower(); +} + +static void __attribute__((unused)) MJXQ_init2() +{ + // haven't figured out txid<-->rf channel mapping for MJX models + static const uint8_t rf_map[][4] = { + {0x0A, 0x46, 0x3A, 0x42}, + {0x0A, 0x3C, 0x36, 0x3F}, + {0x0A, 0x43, 0x36, 0x3F} }; + if (sub_protocol == H26D) + memcpy(hopping_frequency, "\x32\x3e\x42\x4e", MJXQ_RF_NUM_CHANNELS); + else + if (sub_protocol == WLH08) + memcpy(hopping_frequency, rf_map[rx_tx_addr[0]%3], MJXQ_RF_NUM_CHANNELS); +} + +static void __attribute__((unused)) MJXQ_initialize_txid() +{ + // haven't figured out txid<-->rf channel mapping for MJX models + static const uint8_t tx_map[][3]={ + {0xF8, 0x4F, 0x1C}, + {0xC8, 0x6E, 0x02}, + {0x48, 0x6A, 0x40} }; + if (sub_protocol == WLH08) + rx_tx_addr[0]&=0xF8; // txid must be multiple of 8 + else + memcpy(rx_tx_addr,tx_map[rx_tx_addr[0]%3],3); +} + +uint16_t MJXQ_callback() +{ + if(IS_BIND_DONE_on) + MJXQ_send_packet(0); + else + { + if (bind_counter == 0) + { + MJXQ_init2(); + BIND_DONE; + } + else + { + bind_counter--; + MJXQ_send_packet(1); + } + } + + return MJXQ_PACKET_PERIOD; +} + +uint16_t initMJXQ(void) +{ + BIND_IN_PROGRESS; // autobind protocol + bind_counter = MJXQ_BIND_COUNT; + MJXQ_initialize_txid(); + MJXQ_init(); + packet_count=0; + return MJXQ_INITIAL_WAIT+MJXQ_PACKET_PERIOD; +} + +#endif diff --git a/Multiprotocol/MT99xx_nrf24l01.ino b/Multiprotocol/MT99xx_nrf24l01.ino index b9909a9..ab4c825 100644 --- a/Multiprotocol/MT99xx_nrf24l01.ino +++ b/Multiprotocol/MT99xx_nrf24l01.ino @@ -90,8 +90,8 @@ static void __attribute__((unused)) MT99XX_send_packet() { // YZ packet[0] = convert_channel_8b_scale(THROTTLE,0x00,0x64); // throttle packet[1] = convert_channel_8b_scale(RUDDER ,0x00,0x64); // rudder - packet[2] = convert_channel_8b_scale(AILERON ,0x00,0x64); // aileron - packet[3] = convert_channel_8b_scale(ELEVATOR,0x00,0x64); // elevator + packet[2] = convert_channel_8b_scale(ELEVATOR,0x00,0x64); // elevator + packet[3] = convert_channel_8b_scale(AILERON ,0x00,0x64); // aileron if(packet_count++ >= 23) { yz_seq_num ++; @@ -99,8 +99,8 @@ static void __attribute__((unused)) MT99XX_send_packet() yz_seq_num = 0; packet_count=0; } - packet[4]= yz_p4_seq[yz_seq_num]; - packet[5]= 0x02; // expert ? (0=unarmed, 1=normal) + packet[4] = yz_p4_seq[yz_seq_num]; + packet[5] = 0x02; // expert ? (0=unarmed, 1=normal) packet[6] = 0x80; packet[7] = packet[0]; for(uint8_t idx = 1; idx < MT99XX_PACKET_SIZE-2; idx++) @@ -127,7 +127,6 @@ static void __attribute__((unused)) MT99XX_init() { NRF24L01_Initialize(); NRF24L01_SetTxRxMode(TX_EN); - XN297_SetTXAddr((uint8_t *)"\0xCC\0xCC\0xCC\0xCC\0xCC", 5); NRF24L01_FlushTx(); 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 @@ -139,6 +138,7 @@ static void __attribute__((unused)) MT99XX_init() else NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps NRF24L01_SetPower(); + XN297_SetTXAddr((uint8_t *)"\0xCC\0xCC\0xCC\0xCC\0xCC", 5); } static void __attribute__((unused)) MT99XX_initialize_txid() diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 44a4bcf..b76d74f 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -420,6 +420,12 @@ static void protocol_init() next_callback=initMT99XX(); remote_callback = MT99XX_callback; break; +#endif +#if defined(MJXQ_NRF24L01_INO) + case MODE_MJXQ: + next_callback=initMJXQ(); + remote_callback = MJXQ_callback; + break; #endif } @@ -502,7 +508,7 @@ static void module_reset() case MODE_DEVO: CYRF_Reset(); break; - default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY, MODE_MT99XX + default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY, MODE_MT99XX, MODE_MJXQ NRF24L01_Reset(); break; } diff --git a/Multiprotocol/V2X2_nrf24l01.ino b/Multiprotocol/V2X2_nrf24l01.ino index d761c57..887e60e 100644 --- a/Multiprotocol/V2X2_nrf24l01.ino +++ b/Multiprotocol/V2X2_nrf24l01.ino @@ -180,13 +180,13 @@ static void __attribute__((unused)) V2X2_send_packet(uint8_t bind) //Flags2 // Channel 9 - if (Servo_data[AUX5] > PPM_SWITCH) + if (Servo_AUX5) flags2 = V2X2_FLAG_HEADLESS; // Channel 10 - if (Servo_data[AUX6] > PPM_SWITCH) + if (Servo_AUX6) flags2 |= V2X2_FLAG_MAG_CAL_X; // Channel 11 - if (Servo_data[AUX7] > PPM_SWITCH) + if (Servo_AUX7) flags2 |= V2X2_FLAG_MAG_CAL_Y; } // TX id diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 3558c99..f76d79e 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -26,23 +26,28 @@ #define HUB_TELEMETRY //Comment a protocol to exclude it from compilation +//A7105 protocols +#define FLYSKY_A7105_INO +#define HUBSAN_A7105_INO +//CYRF6936 protocols +#define DEVO_CYRF6936_INO +#define DSM2_CYRF6936_INO +//CC2500 protocols +#define FRSKY_CC2500_INO +//#define FRSKYX_CC2500_INO +//NFR24L01 protocols #define BAYANG_NRF24L01_INO #define CG023_NRF24L01_INO #define CX10_NRF24L01_INO -#define DEVO_CYRF6936_INO -#define DSM2_CYRF6936_INO #define ESKY_NRF24L01_INO -#define FLYSKY_A7105_INO -#define FRSKY_CC2500_INO #define HISKY_NRF24L01_INO -#define HUBSAN_A7105_INO #define KN_NRF24L01_INO #define SLT_NRF24L01_INO #define SYMAX_NRF24L01_INO #define V2X2_NRF24L01_INO #define YD717_NRF24L01_INO -//#define FRSKYX_CC2500_INO #define MT99XX_NRF24L01_INO +#define MJXQ_NRF24L01_INO //Update this table to set which protocol and all associated settings are called for the corresponding dial number static const PPM_Parameters PPM_prot[15]= @@ -121,6 +126,11 @@ static const PPM_Parameters PPM_prot[15]= MT99 H7 YZ + MODE_MJXQ + WLH08 + X600 + X800 + H26D RX_Num value between 0 and 15 @@ -152,7 +162,8 @@ enum chan_order{ AUX5, AUX6, AUX7, - AUX8 + AUX8, + AUX9 }; #endif @@ -174,7 +185,8 @@ enum chan_order{ AUX5, AUX6, AUX7, - AUX8 + AUX8, + AUX9 }; #endif @@ -196,7 +208,8 @@ enum chan_order{ AUX5, AUX6, AUX7, - AUX8 + AUX8, + AUX9 }; #endif @@ -218,10 +231,11 @@ enum chan_order{ AUX5, AUX6, AUX7, - AUX8 + AUX8, + AUX9 }; #endif #define PPM_MIN_COMMAND 1250 -#define PPM_SWITCH 1550 +#define PPM_SWITCH 1550 #define PPM_MAX_COMMAND 1750 diff --git a/Multiprotocol/multiprotocol.h b/Multiprotocol/multiprotocol.h index c1b3f35..3f735e5 100644 --- a/Multiprotocol/multiprotocol.h +++ b/Multiprotocol/multiprotocol.h @@ -44,6 +44,7 @@ enum PROTOCOLS MODE_FRSKYX = 15, // =>CC2500 MODE_ESKY = 16, // =>NRF24L01 MODE_MT99XX=17, // =>NRF24L01 + MODE_MJXQ=18 // =>NRF24L01 }; enum Flysky @@ -103,6 +104,13 @@ enum MT99XX H7 = 1, YZ = 2 }; +enum MJXQ +{ + WLH08 = 0, + X600 = 1, + X800 = 2, + H26D = 3 +}; #define NONE 0 #define P_HIGH 1 @@ -411,6 +419,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- FrskyX 15 ESky 16 MT99XX 17 + MJXQ 18 BindBit=> 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No @@ -457,6 +466,11 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- MT99 0 H7 1 YZ 2 + sub_protocol==MJXQ + WLH08 0 + X600 1 + X800 2 + H26D 3 Power value => 0x80 0=High/1=Low Stream[3] = option_protocol; option_protocol value is -127..127 From 38e57ccd713a57be77f4f8d6cc3b824017c96028 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 4 Feb 2016 14:19:48 +0100 Subject: [PATCH 044/293] Update README.md --- README.md | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 6b2bce0..5e92260 100644 --- a/README.md +++ b/README.md @@ -110,7 +110,9 @@ Notes: ####Using the dial for PPM input PPM is only allowing access to a subset of existing protocols. -The default association dial position / protocol is listed below. +The protocols, subprotocols and all other settings can be personalized by modifying the **_Config.h** file. + +The default association dial position / protocol in every release is listed below. Dial|Protocol|Sub_protocol|RX Num|Power|Auto Bind|Option|RF Module ----|--------|------------|------|-----|---------|------|--------- @@ -131,9 +133,8 @@ Dial|Protocol|Sub_protocol|RX Num|Power|Auto Bind|Option|RF Module 14|BAYANG|-|0|High|No|0|NRF24L01 15|SYMAX|SYMAX5C|0|High|No|0|NRF24L01 -Notes: +Note: - The dial selection must be done before the power is applied. -- The protocols, subprotocols and all other settings can be personalized by modifying the _Config.h file. ####Using serial input with er9x/ersky9x Serial is allowing access to all existing protocols & sub_protocols listed below. From fa6522222831266f648a4b95e1c2c6bc77ff2e35 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 4 Feb 2016 21:59:49 +0100 Subject: [PATCH 045/293] Added FrSkyX description and telemetry info --- README.md | 27 ++++++++++++++++++++------- 1 file changed, 20 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 5e92260..df55c29 100644 --- a/README.md +++ b/README.md @@ -66,11 +66,13 @@ Notes: ###Telemetry -There are only 2 protocols so far supporting telemetry: Hubsan and Frsky. +There are 3 protocols supporting telemetry: Hubsan, FrSky and FrSkyX. Hubsan displays the battery voltage and TX RSSI. -FRSky displays full telemetry (A0, A1, RX RSSI, TX RSSI and Hub). +FrSky displays full telemetry (A0, A1, RX RSSI, TX RSSI and Hub). + +FrSkyX displays basic telemetry (A1, A2 and RX RSSI). ### If used in PPM mode @@ -353,6 +355,17 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +####FRSKYX +Extended limits supported + +Telemetry enabled for A1 (RxBatt), A2, RSSI + +Option=fine frequency tuning, usually 0 or -41 based on the manufacturer boards + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16 +---|---|---|---|---|---|---|---|---|----|----|----|----|----|----|---- +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16 + ####HISKY CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- @@ -360,7 +373,7 @@ A|E|T|R|GEAR|PITCH|GYRO|CH8 GYRO: -100%=6G, +100%=3G -####HK310 +#####HK310 Models: RX HK-3000, HK3100 and XY3000 (TX are HK-300, HK-310 and TL-3C) CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 @@ -406,16 +419,16 @@ A|E|T|R|FLIP|LED|PICTURE|VIDEO|HEADLESS|RTH|AUTOFLIP|PAN|TILT ####MT99XX Autobind protocol -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10 ----|---|---|---|---|---|---|---|---|--- -A|E|T|R|FLIP||PICTURE|VIDEO|PITCH_Trim|ROLL_Trim +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP|LED|PICTURE|VIDEO|HEADLESS #####Sub_protocol MT Models: MT99xx #####Sub_protocol H7 Models: Eachine H7 #####Sub_protocol YZ -In progress... +Models: Yi Zhan i6S ####SLT Autobind protocol From c5b1e7331246a15dc48a5d46f99d94ea0e47f099 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 4 Feb 2016 22:08:07 +0100 Subject: [PATCH 046/293] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index df55c29..2e409bb 100644 --- a/README.md +++ b/README.md @@ -557,7 +557,7 @@ To upload the latest provided hex file under [Release](https://github.com/pascal Use a tool like [AVR Burn-O-Mat](http://avr8-burn-o-mat.aaabbb.de/) to set the fuses of the Atmega328 to: - Low Fuse 0xFF - High Fuse 0xD2 -- Extended Fuse 0x05 +- Extended Fuse 0x05 (or 0xFD which is the same) This will make sure your ATMEGA328 is well configured and the global TX ID is not erased at each updates. From b393d2666dcfa74ec7bd16939a490dd7cd948e80 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 5 Feb 2016 17:27:51 +0100 Subject: [PATCH 047/293] Added FrSkyX protocol, Added MT99xx YZ sub protocol, Ram usage optimization --- Multiprotocol/DSM2_cyrf6936.ino | 37 ++- Multiprotocol/FrSkyX_cc2500.ino | 324 ++++++++++++++++++++- Multiprotocol/FrSky_cc2500.ino | 9 +- Multiprotocol/MT99xx_nrf24l01.ino | 41 ++- Multiprotocol/Multiprotocol.ino | 18 +- Multiprotocol/NRF24l01_SPI.ino | 53 +++- Multiprotocol/Telemetry.ino | 469 ++++++++++++++++++++---------- Multiprotocol/_Config.h | 55 ++-- Multiprotocol/iface_nrf24l01.h | 15 +- Multiprotocol/multiprotocol.h | 65 ++--- 10 files changed, 794 insertions(+), 292 deletions(-) diff --git a/Multiprotocol/DSM2_cyrf6936.ino b/Multiprotocol/DSM2_cyrf6936.ino index e6769a6..928d24e 100644 --- a/Multiprotocol/DSM2_cyrf6936.ino +++ b/Multiprotocol/DSM2_cyrf6936.ino @@ -42,8 +42,7 @@ enum { DSM2_CH2_READ_B = BIND_COUNT1 + 10, }; - -const uint8_t pncodes[5][9][8] = { +const uint8_t PROGMEM pncodes[5][9][8] = { /* Note these are in order transmitted (LSB 1st) */ { /* Row 0 */ /* Col 0 */ {0x03, 0xBC, 0x6E, 0x8A, 0xEF, 0xBD, 0xFE, 0xF8}, @@ -102,6 +101,12 @@ const uint8_t pncodes[5][9][8] = { }, }; +static void __attribute__((unused)) read_code(uint8_t *buf, uint8_t row, uint8_t col, uint8_t len) +{ + for(uint8_t i=0;i. - */ +/* ************************** + * By Midelic on RCGroups * + ************************** + 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(FRSKYX_CC2500_INO) + + #include "iface_cc2500.h" + + uint8_t chanskip; + uint8_t calData[48][3]; + uint8_t channr; + uint8_t pass_ = 1 ; + uint8_t counter_rst; + uint8_t ctr; + uint8_t FS_flag=0; + // uint8_t ptr[4]={0x01,0x12,0x23,0x30}; + //uint8_t ptr[4]={0x00,0x11,0x22,0x33}; + + const PROGMEM uint8_t hop_data[]={ + 0x02, 0xD4, 0xBB, 0xA2, 0x89, + 0x70, 0x57, 0x3E, 0x25, 0x0C, + 0xDE, 0xC5, 0xAC, 0x93, 0x7A, + 0x61, 0x48, 0x2F, 0x16, 0xE8, + 0xCF, 0xB6, 0x9D, 0x84, 0x6B, + 0x52, 0x39, 0x20, 0x07, 0xD9, + 0xC0, 0xA7, 0x8E, 0x75, 0x5C, + 0x43, 0x2A, 0x11, 0xE3, 0xCA, + 0xB1, 0x98, 0x7F, 0x66, 0x4D, + 0x34, 0x1B, 0x00, 0x1D, 0x03 + }; -#include "iface_cc2500.h" + uint8_t hop(uint8_t byte) + { + return pgm_read_byte_near(&hop_data[byte]); + } + uint16_t initFrSkyX() + { + while(!chanskip) + { + randomSeed((uint32_t)analogRead(A6) << 10 | analogRead(A7)); + chanskip=random(0xfefefefe)%47; + } + while((chanskip-ctr)%4) + ctr=(ctr+1)%4; + + counter_rst=(chanskip-ctr)>>2; + //for test*************** + //rx_tx_addr[3]=0xB3; + //rx_tx_addr[2]=0xFD; + //************************ + frskyX_init(); + // + if(IS_AUTOBIND_FLAG_on) + { + state = FRSKY_BIND; + initialize_data(1); + } + else + { + state = FRSKY_DATA1; + initialize_data(0); + } + return 10000; + } + + uint16_t ReadFrSkyX() + { + switch(state) + { + default: + set_start(47); + CC2500_SetPower(); + cc2500_strobe(CC2500_SFRX); + // + frskyX_build_bind_packet(); + cc2500_strobe(CC2500_SIDLE); + cc2500_writeFifo(packet, packet[0]+1); + state++; + return 9000; + case FRSKY_BIND_DONE: + initialize_data(0); + channr=0; + BIND_DONE; + state++; + break; + case FRSKY_DATA1: + LED_ON; + CC2500_SetTxRxMode(TX_EN); + set_start(channr); + CC2500_SetPower(); + cc2500_strobe(CC2500_SFRX); + channr = (channr+chanskip)%47; + cc2500_strobe(CC2500_SIDLE); + cc2500_writeFifo(packet, packet[0]+1); + // + frskyX_data_frame(); + state++; + return 5500; + case FRSKY_DATA2: + CC2500_SetTxRxMode(RX_EN); + cc2500_strobe(CC2500_SIDLE); + state++; + return 200; + case FRSKY_DATA3: + cc2500_strobe(CC2500_SRX); + state++; + return 3000; + case FRSKY_DATA4: + len = cc2500_readReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F; + if (len &&(len>8) & 0x0F)|(chan_1 << 4))); + packet[9+i+2]=crc_Byte(chan_1>>4); + } + //packet[21]=crc_Byte(0x08);//first + packet[21]=crc_Byte(0x80);//??? when received first telemetry frame is changed to 0x80 + //packet[21]=crc_Byte(ptr[p]);//??? + //p=(p+1)%4;//repeating 4 bytes sequence pattern every 4th frame. + + pass_=lpass+1; + + for (uint8_t i=22;i<28;i++) + packet[i]=crc_Byte(0); + + packet[28]=highByte(crc); + packet[29]=lowByte(crc); + } -#endif + uint16_t scaleForPXX( uint8_t i ) + { //mapped 860,2140(125%) range to 64,1984(PXX values); + return (uint16_t)(((Servo_data[i]-PPM_MIN)*3)>>1)+64; + } + + uint8_t crc_Byte( uint8_t byte ) + { + crc = (crc<<8) ^ pgm_read_word(&CRCTable[((uint8_t)(crc>>8) ^ byte) & 0xFF]); + return byte; + } +#endif \ No newline at end of file diff --git a/Multiprotocol/FrSky_cc2500.ino b/Multiprotocol/FrSky_cc2500.ino index dae03c7..f3c6d3c 100644 --- a/Multiprotocol/FrSky_cc2500.ino +++ b/Multiprotocol/FrSky_cc2500.ino @@ -20,7 +20,6 @@ //##########Variables######## //uint32_t state; //uint8_t len; -uint8_t telemetry_counter=0; /* enum { @@ -128,8 +127,6 @@ static void __attribute__((unused)) frsky2way_build_bind_packet() packet[17] = 0x01; } - - static void __attribute__((unused)) frsky2way_data_frame() {//pachet[4] is telemetry user frame counter(hub) //11 d7 2d 22 00 01 c9 c9 ca ca 88 88 ca ca c9 ca 88 88 @@ -138,7 +135,11 @@ static void __attribute__((unused)) frsky2way_data_frame() packet[1] = rx_tx_addr[3]; packet[2] = rx_tx_addr[2]; packet[3] = counter;// - packet[4]=telemetry_counter; + #if defined TELEMETRY + packet[4] = telemetry_counter; + #else + packet[4] = 0x00; + #endif packet[5] = 0x01; // diff --git a/Multiprotocol/MT99xx_nrf24l01.ino b/Multiprotocol/MT99xx_nrf24l01.ino index ab4c825..51415b7 100644 --- a/Multiprotocol/MT99xx_nrf24l01.ino +++ b/Multiprotocol/MT99xx_nrf24l01.ino @@ -37,29 +37,16 @@ enum{ FLAG_MT_FLIP = 0x80, }; -enum{ - // flags going to ?????? (Yi Zhan i6S)ROLL - BLABLA, -}; - enum { MT99XX_INIT = 0, MT99XX_BIND, MT99XX_DATA }; -static uint8_t __attribute__((unused)) MT99XX_calcChecksum() -{ - uint8_t result=checksum_offset; - for(uint8_t i=0; i<8; i++) - result += packet[i]; - return result; -} - static void __attribute__((unused)) MT99XX_send_packet() { - static const uint8_t yz_p4_seq[] = {0xa0, 0x20, 0x60}; - static const uint8_t mys_byte[] = { + const uint8_t yz_p4_seq[] = {0xa0, 0x20, 0x60}; + const uint8_t mys_byte[] = { 0x01, 0x11, 0x02, 0x12, 0x03, 0x13, 0x04, 0x14, 0x05, 0x15, 0x06, 0x16, 0x07, 0x17, 0x00, 0x10 }; @@ -71,8 +58,8 @@ static void __attribute__((unused)) MT99XX_send_packet() packet[1] = convert_channel_8b_scale(RUDDER ,0x00,0xE1); // rudder packet[2] = convert_channel_8b_scale(AILERON ,0x00,0xE1); // aileron packet[3] = convert_channel_8b_scale(ELEVATOR,0x00,0xE1); // elevator - packet[4] = convert_channel_8b_scale(AUX5,0x00,0x3F); // pitch trim (0x3f-0x20-0x00) - packet[5] = convert_channel_8b_scale(AUX6,0x00,0x3F); // roll trim (0x00-0x20-0x3f) + packet[4] = 0x20; // pitch trim (0x3f-0x20-0x00) + packet[5] = 0x20; // roll trim (0x00-0x20-0x3f) packet[6] = GET_FLAG( Servo_AUX1, FLAG_MT_FLIP ) | GET_FLAG( Servo_AUX3, FLAG_MT_SNAPSHOT ) | GET_FLAG( Servo_AUX4, FLAG_MT_VIDEO ); @@ -84,7 +71,10 @@ static void __attribute__((unused)) MT99XX_send_packet() // low nibble: index in chan list ? // high nibble: 0->start from start of list, 1->start from end of list ? packet[7] = mys_byte[hopping_frequency_no]; - packet[8] = MT99XX_calcChecksum(); + uint8_t result=checksum_offset; + for(uint8_t i=0; i<8; i++) + result += packet[i]; + packet[8] = result; } else { // YZ @@ -100,8 +90,12 @@ static void __attribute__((unused)) MT99XX_send_packet() packet_count=0; } packet[4] = yz_p4_seq[yz_seq_num]; - packet[5] = 0x02; // expert ? (0=unarmed, 1=normal) - packet[6] = 0x80; + packet[5] = 0x02 // expert ? (0=unarmed, 1=normal) + | GET_FLAG(Servo_AUX4, 0x10) //VIDEO + | GET_FLAG(Servo_AUX1, 0x80) //FLIP + | GET_FLAG(Servo_AUX5, 0x04) //HEADLESS + | GET_FLAG(Servo_AUX3, 0x20); //SNAPSHOT + packet[6] = GET_FLAG(Servo_AUX2, 0x80); //LED packet[7] = packet[0]; for(uint8_t idx = 1; idx < MT99XX_PACKET_SIZE-2; idx++) packet[7] += packet[idx]; @@ -138,6 +132,9 @@ static void __attribute__((unused)) MT99XX_init() else NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps NRF24L01_SetPower(); + + XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP) | (sub_protocol == YZ ? BV(XN297_UNSCRAMBLED):0) ); + XN297_SetTXAddr((uint8_t *)"\0xCC\0xCC\0xCC\0xCC\0xCC", 5); } @@ -210,8 +207,8 @@ uint16_t initMT99XX(void) packet[2] = 0x05; packet[3] = 0x06; } - packet[4] = rx_tx_addr[0]; // 1th byte for data state tx address - packet[5] = rx_tx_addr[1]; // 2th byte for data state tx address (always 0x00 on Yi Zhan ?) + packet[4] = rx_tx_addr[0]; // 1st byte for data state tx address + packet[5] = rx_tx_addr[1]; // 2nd byte for data state tx address (always 0x00 on Yi Zhan ?) packet[6] = 0x00; // 3th byte for data state tx address (always 0x00 ?) packet[7] = checksum_offset; // checksum offset packet[8] = 0xAA; // fixed diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index b76d74f..38c23aa 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -47,7 +47,7 @@ uint8_t Servo_AUX; // PPM variable volatile uint16_t PPM_data[NUM_CHN]; -// NRF variables +// Protocol variables uint8_t rx_tx_addr[5]; uint8_t phase; uint16_t bind_counter; @@ -64,6 +64,7 @@ uint8_t hopping_frequency_no=0; uint8_t rf_ch_num; uint8_t throttle, rudder, elevator, aileron; uint8_t flags; +uint16_t crc; // uint32_t state; uint8_t len; @@ -91,13 +92,14 @@ uint8_t prev_protocol=0; #define MAX_PKT 27 uint8_t pkt[MAX_PKT];//telemetry receiving packets #if defined(TELEMETRY) -uint8_t pktt[MAX_PKT];//telemetry receiving packets -volatile uint8_t tx_head; -volatile uint8_t tx_tail; -uint8_t v_lipo; -int16_t RSSI_dBm; -//const uint8_t RSSI_offset=72;//69 71.72 values db -uint8_t telemetry_link=0; + uint8_t pktt[MAX_PKT];//telemetry receiving packets + volatile uint8_t tx_head; + volatile uint8_t tx_tail; + uint8_t v_lipo; + int16_t RSSI_dBm; + //const uint8_t RSSI_offset=72;//69 71.72 values db + uint8_t telemetry_link=0; + uint8_t telemetry_counter=0; #endif // Callback diff --git a/Multiprotocol/NRF24l01_SPI.ino b/Multiprotocol/NRF24l01_SPI.ino index c14f5d5..cec1439 100644 --- a/Multiprotocol/NRF24l01_SPI.ino +++ b/Multiprotocol/NRF24l01_SPI.ino @@ -257,6 +257,7 @@ uint8_t NRF24L01_packet_ack() /////////////// // XN297 emulation layer +uint8_t xn297_scramble_enabled; uint8_t xn297_addr_len; uint8_t xn297_tx_addr[5]; uint8_t xn297_rx_addr[5]; @@ -269,9 +270,16 @@ static const uint8_t xn297_scramble[] = { 0x1b, 0x5d, 0x19, 0x10, 0x24, 0xd3, 0xdc, 0x3f, 0x8e, 0xc5, 0x2f}; -static const uint16_t xn297_crc_xorout[] = { - 0x0000, 0x3448, 0x9BA7, 0x8BBB, 0x85E1, 0x3E8C, // 1st entry is missing, probably never needed - 0x451E, 0x18E6, 0x6B24, 0xE7AB, 0x3828, 0x814B, // it's used for 3-byte address w/ 0 byte payload only +const uint16_t PROGMEM xn297_crc_xorout[] = { + 0x0000, 0x3d5f, 0xa6f1, 0x3a23, 0xaa16, 0x1caf, + 0x62b2, 0xe0eb, 0x0821, 0xbe07, 0x5f1a, 0xaf15, + 0x4f0a, 0xad24, 0x5e48, 0xed34, 0x068c, 0xf2c9, + 0x1852, 0xdf36, 0x129d, 0xb17c, 0xd5f5, 0x70d7, + 0xb798, 0x5133, 0x67db, 0xd94e}; + +const uint16_t PROGMEM xn297_crc_xorout_scrambled[] = { + 0x0000, 0x3448, 0x9BA7, 0x8BBB, 0x85E1, 0x3E8C, + 0x451E, 0x18E6, 0x6B24, 0xE7AB, 0x3828, 0x814B, 0xD461, 0xF494, 0x2503, 0x691D, 0xFE8B, 0x9BA7, 0x8B17, 0x2920, 0x8B5F, 0x61B1, 0xD391, 0x7401, 0x2138, 0x129F, 0xB3A0, 0x2988}; @@ -327,16 +335,21 @@ void XN297_SetRXAddr(const uint8_t* addr, uint8_t len) memcpy(buf, addr, len); memcpy(xn297_rx_addr, addr, len); for (uint8_t i = 0; i < xn297_addr_len; ++i) - buf[i] = xn297_rx_addr[i] ^ xn297_scramble[xn297_addr_len-i-1]; + { + buf[i] = xn297_rx_addr[i]; + if(xn297_scramble_enabled) + buf[i] ^= xn297_scramble[xn297_addr_len-i-1]; + } NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, len-2); NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, buf, 5); } -void XN297_Configure(uint8_t flags) +void XN297_Configure(uint16_t flags) { + xn297_scramble_enabled = !(flags & BV(XN297_UNSCRAMBLED)); xn297_crc = !!(flags & BV(NRF24L01_00_EN_CRC)); flags &= ~(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO)); - NRF24L01_WriteReg(NRF24L01_00_CONFIG, flags); + NRF24L01_WriteReg(NRF24L01_00_CONFIG, flags & 0xFF); } void XN297_WritePayload(uint8_t* msg, uint8_t len) @@ -352,12 +365,20 @@ void XN297_WritePayload(uint8_t* msg, uint8_t len) buf[last++] = 0x55; } for (uint8_t i = 0; i < xn297_addr_len; ++i) - buf[last++] = xn297_tx_addr[xn297_addr_len-i-1] ^ xn297_scramble[i]; - - for (uint8_t i = 0; i < len; ++i) { + { + buf[last] = xn297_tx_addr[xn297_addr_len-i-1]; + if(xn297_scramble_enabled) + buf[last] ^= xn297_scramble[i]; + last++; + } + for (uint8_t i = 0; i < len; ++i) + { // bit-reverse bytes in packet uint8_t b_out = bit_reverse(msg[i]); - buf[last++] = b_out ^ xn297_scramble[xn297_addr_len+i]; + buf[last] = b_out; + if(xn297_scramble_enabled) + buf[last] ^= xn297_scramble[xn297_addr_len+i]; + last++; } if (xn297_crc) { @@ -365,7 +386,10 @@ void XN297_WritePayload(uint8_t* msg, uint8_t len) uint16_t crc = 0xb5d2; for (uint8_t i = offset; i < last; ++i) crc = crc16_update(crc, buf[i]); - crc ^= xn297_crc_xorout[xn297_addr_len - 3 + len]; + if(xn297_scramble_enabled) + crc ^= pgm_read_word(&xn297_crc_xorout_scrambled[xn297_addr_len - 3 + len]); + else + crc ^= pgm_read_word(&xn297_crc_xorout[xn297_addr_len - 3 + len]); buf[last++] = crc >> 8; buf[last++] = crc & 0xff; } @@ -374,9 +398,14 @@ void XN297_WritePayload(uint8_t* msg, uint8_t len) void XN297_ReadPayload(uint8_t* msg, uint8_t len) { + // TODO: if xn297_crc==1, check CRC before filling *msg NRF24L01_ReadPayload(msg, len); for(uint8_t i=0; i>5); - if(pktt[len-2] >=128) - RSSI_dBm -= 82; - else - RSSI_dBm += 65; -} - -void frsky_check_telemetry(uint8_t *pkt,uint8_t len) -{ - if(pkt[1] != rx_tx_addr[3] || pkt[2] != rx_tx_addr[2] || len != pkt[0] + 3) - {//only packets with the required id and packet length - for(uint8_t i=3;i<6;i++) - pktt[i]=0; - return; - } - else - { - for (uint8_t i=3;i0) - telemetry_counter=(telemetry_counter+1)%32; - } -} - -void frsky_link_frame() -{ - frame[0] = 0xFE; - if ((cur_protocol[0]&0x1F)==MODE_FRSKY) - { - compute_RSSIdbm(); - frame[1] = pktt[3]; - frame[2] = pktt[4]; - frame[3] = (uint8_t)RSSI_dBm; - frame[4] = pktt[5]*2; - } - else - if ((cur_protocol[0]&0x1F)==MODE_HUBSAN) - { - frame[1] = v_lipo*2; //v_lipo; common 0x2A=42/10=4.2V - frame[2] = frame[1]; - frame[3] = 0x00; - frame[4] = (uint8_t)RSSI_dBm; - } - frame[5] = frame[6] = frame[7] = frame[8] = 0; - frskySendStuffed(); -} - -#if defined HUB_TELEMETRY -void frsky_user_frame() -{ - uint8_t indexx = 0, c=0, j=8, n=0, i; - - if(pktt[6]>0 && pktt[6]<=MAX_PKTX) - {//only valid hub frames - frame[0] = 0xFD; - frame[1] = 0; - frame[2] = pktt[7]; + + void compute_RSSIdbm(){ - switch(pass) - { - case 0: - indexx=pktt[6]; - for(i=0;i>5); + if(pktt[len-2] >=128) + RSSI_dBm -= 82; + else + RSSI_dBm += 65; + } + + void frsky_check_telemetry(uint8_t *pkt,uint8_t len) + { + if(pkt[1] != rx_tx_addr[3] || pkt[2] != rx_tx_addr[2] || len != pkt[0] + 3) + {//only packets with the required id and packet length + for(uint8_t i=3;i<6;i++) + pktt[i]=0; return; - frame[1] = index; + } + else + { + for (uint8_t i=3;i0) + telemetry_counter=(telemetry_counter+1)%32; + } + } + + void frsky_link_frame() + { + frame[0] = 0xFE; + if ((cur_protocol[0]&0x1F)==MODE_FRSKY) + { + compute_RSSIdbm(); + frame[1] = pktt[3]; + frame[2] = pktt[4]; + frame[3] = (uint8_t)RSSI_dBm; + frame[4] = pktt[5]*2; + } + else + if ((cur_protocol[0]&0x1F)==MODE_HUBSAN) + { + frame[1] = v_lipo*2; //v_lipo; common 0x2A=42/10=4.2V + frame[2] = frame[1]; + frame[3] = 0x00; + frame[4] = (uint8_t)RSSI_dBm; + } + frame[5] = frame[6] = frame[7] = frame[8] = 0; frskySendStuffed(); } - else - pass=0; -} -#endif - -void frskyUpdate() -{ - if(telemetry_link) - { - frsky_link_frame(); - telemetry_link=0; - return; - } + #if defined HUB_TELEMETRY - if(!telemetry_link && (cur_protocol[0]&0x1F) != MODE_HUBSAN ) - frsky_user_frame(); + void frsky_user_frame() + { + uint8_t indexx = 0, c=0, j=8, n=0, i; + + if(pktt[6]>0 && pktt[6]<=MAX_PKTX) + {//only valid hub frames + frame[0] = 0xFD; + frame[1] = 0; + frame[2] = pktt[7]; + + switch(pass) + { + case 0: + indexx=pktt[6]; + for(i=0;i0) + { + crc_s += p[i]; //0-1FF + crc_s += crc_s >> 8; //0-100 + crc_s &= 0x00ff; + } + } + } + + void sportIdle() + { + Serial_write(0x7e); + } + void sportSendFrame() + { + //at the moment only SWR RSSI,RxBt and A2. + sport_counter = (sport_counter + 1) %9; + + for (uint8_t i=5;i<8;i++) + frame[i]=0; + + switch (sport_counter) + { + case 0: // SWR + frame[0] = 0x98; + frame[1] = 0x10; + frame[2] = 0x05; + frame[3] = 0xf1; + frame[4] = 0x20;//dummy values if swr 20230f00 + frame[5] = 0x23; + frame[6] = 0x0F; + frame[7] = 0x00; + break; + case 1: // RSSI + frame[0] = 0x98; + frame[1] = 0x10; + frame[2] = 0x01; + frame[3] = 0xf1; + frame[4] = rssi; + break; + case 2: //BATT + frame[0] = 0x98; + frame[1] = 0x10; + frame[2] = 0x04; + frame[3] = 0xf1; + frame[4] = RxBt;//a1; + break; + case 3: //ADC2(A2) + frame[0] = 0x1A; + frame[1] = 0x10; + frame[2] = 0x03; + frame[3] = 0xf1; + frame[4] = ADC2;//a2;; + break; + default: + sportIdle(); + return; + } + sportSend(frame); + } + + void process_sport_data()//only for ADC2 + { + uint8_t j=7; + if(pktt[6]>0 && pktt[6]<=USER_MAX_BYTES) + { + for(uint8_t i=0;i<6;i++) + if(pktt[j++]==0x03) + if(pktt[j]==0xF1) + { + ADC2=pktt[j+1]; + break; + } + pktt[6]=0;//new frame + } + } + #endif + + + void frskyUpdate() + { + if(telemetry_link && (cur_protocol[0]&0x1F) != MODE_FRSKYX ) + { + frsky_link_frame(); + telemetry_link=0; + return; + } + #if defined HUB_TELEMETRY + if(!telemetry_link && (cur_protocol[0]&0x1F) != MODE_HUBSAN && (cur_protocol[0]&0x1F) != MODE_FRSKYX) + { + frsky_user_frame(); + return; + } + #endif + #if defined SPORT_TELEMETRY + if ((cur_protocol[0]&0x1F)==MODE_FRSKYX) + { + if(telemetry_link) + { + process_sport_data(); + if(pktt[4]>0x36) + rssi=pktt[4]/2; + else + RxBt=pktt[4]; + telemetry_link=0; + } + uint32_t now = micros(); + if ((now - last) > SPORT_TIME) + { + sportSendFrame(); + last = now; + } + } + #endif + } + #endif \ No newline at end of file diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index f76d79e..83bf3ec 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -23,31 +23,40 @@ //Uncomment to enable telemetry #define TELEMETRY -#define HUB_TELEMETRY + +//Comment if a module is not installed +#define A7105_INSTALLED +#define CYRF6936_INSTALLED +#define CC2500_INSTALLED +#define NFR24L01_INSTALLED //Comment a protocol to exclude it from compilation -//A7105 protocols -#define FLYSKY_A7105_INO -#define HUBSAN_A7105_INO -//CYRF6936 protocols -#define DEVO_CYRF6936_INO -#define DSM2_CYRF6936_INO -//CC2500 protocols -#define FRSKY_CC2500_INO -//#define FRSKYX_CC2500_INO -//NFR24L01 protocols -#define BAYANG_NRF24L01_INO -#define CG023_NRF24L01_INO -#define CX10_NRF24L01_INO -#define ESKY_NRF24L01_INO -#define HISKY_NRF24L01_INO -#define KN_NRF24L01_INO -#define SLT_NRF24L01_INO -#define SYMAX_NRF24L01_INO -#define V2X2_NRF24L01_INO -#define YD717_NRF24L01_INO -#define MT99XX_NRF24L01_INO -#define MJXQ_NRF24L01_INO +#ifdef A7105_INSTALLED + #define FLYSKY_A7105_INO + #define HUBSAN_A7105_INO +#endif +#ifdef CYRF6936_INSTALLED + #define DEVO_CYRF6936_INO + #define DSM2_CYRF6936_INO +#endif +#ifdef CC2500_INSTALLED + #define FRSKY_CC2500_INO + #define FRSKYX_CC2500_INO +#endif +#ifdef NFR24L01_INSTALLED + #define BAYANG_NRF24L01_INO + #define CG023_NRF24L01_INO + #define CX10_NRF24L01_INO + #define ESKY_NRF24L01_INO + #define HISKY_NRF24L01_INO + #define KN_NRF24L01_INO + #define SLT_NRF24L01_INO + #define SYMAX_NRF24L01_INO + #define V2X2_NRF24L01_INO + #define YD717_NRF24L01_INO + #define MT99XX_NRF24L01_INO + #define MJXQ_NRF24L01_INO +#endif //Update this table to set which protocol and all associated settings are called for the corresponding dial number static const PPM_Parameters PPM_prot[15]= diff --git a/Multiprotocol/iface_nrf24l01.h b/Multiprotocol/iface_nrf24l01.h index 1acf438..92ff9e1 100644 --- a/Multiprotocol/iface_nrf24l01.h +++ b/Multiprotocol/iface_nrf24l01.h @@ -102,18 +102,7 @@ enum { #define REUSE_TX_PL 0xE3 //#define NOP 0xFF -/* -void NRF24L01_Initialize(); -byte NRF24L01_WriteReg(byte reg, byte data); -byte NRF24L01_WriteRegisterMulti(byte reg, byte data[], byte length); -byte NRF24L01_WritePayload(byte *data, byte len); -byte NRF24L01_ReadReg(byte reg); -byte NRF24L01_ReadRegisterMulti(byte reg, byte data[], byte length); -byte NRF24L01_ReadPayload(byte *data, byte len); +// XN297 emulation layer +#define XN297_UNSCRAMBLED 8 -byte NRF24L01_FlushTx(); -byte NRF24L01_FlushRx(); -byte NRF24L01_Activate(byte code); - -*/ #endif \ No newline at end of file diff --git a/Multiprotocol/multiprotocol.h b/Multiprotocol/multiprotocol.h index 3f735e5..ec6e437 100644 --- a/Multiprotocol/multiprotocol.h +++ b/Multiprotocol/multiprotocol.h @@ -353,41 +353,40 @@ enum { //******************* const uint16_t PROGMEM CRCTable[]= { - 0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf, - 0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7, - 0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e, - 0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876, - 0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd, - 0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5, - 0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c, - 0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974, - 0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb, - 0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3, - 0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a, - 0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72, - 0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9, - 0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1, - 0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738, - 0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70, - 0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7, - 0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff, - 0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036, - 0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e, - 0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5, - 0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd, - 0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134, - 0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c, - 0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3, - 0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb, - 0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232, - 0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a, - 0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1, - 0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9, - 0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330, - 0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78 + 0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf, + 0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7, + 0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e, + 0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876, + 0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd, + 0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5, + 0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c, + 0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974, + 0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb, + 0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3, + 0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a, + 0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72, + 0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9, + 0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1, + 0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738, + 0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70, + 0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7, + 0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff, + 0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036, + 0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e, + 0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5, + 0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd, + 0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134, + 0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c, + 0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3, + 0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb, + 0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232, + 0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a, + 0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1, + 0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9, + 0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330, + 0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78 }; - //**************************************** //*** MULTI protocol serial definition *** //**************************************** From d6338e9daf03eb11f5b808e6719b66efb3a98366 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 5 Feb 2016 18:44:26 +0100 Subject: [PATCH 048/293] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 2e409bb..ba8398a 100644 --- a/README.md +++ b/README.md @@ -356,6 +356,8 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ####FRSKYX +Models: FrSky receivers X4R, X6R and X8R. + Extended limits supported Telemetry enabled for A1 (RxBatt), A2, RSSI From c863d5976b04fba532c8e56fc22002a24cfc0d86 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sat, 6 Feb 2016 11:33:38 +0100 Subject: [PATCH 049/293] Fix MT99xx... --- Multiprotocol/MT99xx_nrf24l01.ino | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/Multiprotocol/MT99xx_nrf24l01.ino b/Multiprotocol/MT99xx_nrf24l01.ino index 51415b7..5e719ed 100644 --- a/Multiprotocol/MT99xx_nrf24l01.ino +++ b/Multiprotocol/MT99xx_nrf24l01.ino @@ -135,7 +135,7 @@ static void __attribute__((unused)) MT99XX_init() XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP) | (sub_protocol == YZ ? BV(XN297_UNSCRAMBLED):0) ); - XN297_SetTXAddr((uint8_t *)"\0xCC\0xCC\0xCC\0xCC\0xCC", 5); + XN297_SetTXAddr((uint8_t *)"\xCC\xCC\xCC\xCC\xCC", 5); } static void __attribute__((unused)) MT99XX_initialize_txid() @@ -187,7 +187,7 @@ uint16_t initMT99XX(void) BIND_IN_PROGRESS; // autobind protocol bind_counter = MT99XX_BIND_COUNT; - memcpy(hopping_frequency,"\0x02\0x48\0x0C\0x3e\0x16\0x34\0x20\0x2A,\0x2A\0x20\0x34\0x16\0x3e\0x0c\0x48\0x02",16); + memcpy(hopping_frequency,"\x02\x48\x0C\x3e\x16\x34\x20\x2A\x2A\x20\x34\x16\x3e\x0c\x48\x02",16); MT99XX_initialize_txid(); MT99XX_init(); @@ -207,11 +207,11 @@ uint16_t initMT99XX(void) packet[2] = 0x05; packet[3] = 0x06; } - packet[4] = rx_tx_addr[0]; // 1st byte for data state tx address - packet[5] = rx_tx_addr[1]; // 2nd byte for data state tx address (always 0x00 on Yi Zhan ?) - packet[6] = 0x00; // 3th byte for data state tx address (always 0x00 ?) + packet[4] = rx_tx_addr[0]; // 1st byte for data state tx address + packet[5] = rx_tx_addr[1]; // 2nd byte for data state tx address (always 0x00 on Yi Zhan ?) + packet[6] = 0x00; // 3rd byte for data state tx address (always 0x00 ?) packet[7] = checksum_offset; // checksum offset - packet[8] = 0xAA; // fixed + packet[8] = 0xAA; // fixed packet_count=0; return MT99XX_INITIAL_WAIT+MT99XX_PACKET_PERIOD_MT; } From 9f2f7eff5b728c9290fe5130c045d32aa8d07855 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 8 Feb 2016 09:20:35 +0100 Subject: [PATCH 050/293] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ba8398a..73b57fb 100644 --- a/README.md +++ b/README.md @@ -332,7 +332,7 @@ A|E|T|R|CH5|CH6|CH7|CH8 #####Sub_protocol V9X9 CH5|CH6|CH7|CH8 ---|---|---|--- -UNK|LIGHT|PICTURE|VIDEO +FLIP|LIGHT|PICTURE|VIDEO #####Sub_protocol V6X6 CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 From d67afd43961d93a58b75006acf416cd6f3b2ef8c Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 9 Feb 2016 08:55:56 +0100 Subject: [PATCH 051/293] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 73b57fb..c778e1c 100644 --- a/README.md +++ b/README.md @@ -431,6 +431,7 @@ Models: MT99xx Models: Eachine H7 #####Sub_protocol YZ Models: Yi Zhan i6S +Only one model can be flown at the same time since the ID is hardcoded. ####SLT Autobind protocol From 84b1a9bbec8d25ac284b6a18df022fb674a6fb0b Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 10 Feb 2016 10:42:39 +0100 Subject: [PATCH 052/293] PCB v2.3d --- PCB v2.3d/Multipro-txV2-3d-cache.lib | 412 ++++ PCB v2.3d/Multipro-txV2-3d.cmp | 248 ++ PCB v2.3d/Multipro-txV2-3d.kicad_pcb | 3253 ++++++++++++++++++++++++++ PCB v2.3d/Multipro-txV2-3d.net | 644 +++++ PCB v2.3d/Multipro-txV2-3d.pro | 41 + PCB v2.3d/Multipro-txV2-3d.sch | 1452 ++++++++++++ PCB v2.3d/Readme.txt | 35 + 7 files changed, 6085 insertions(+) create mode 100644 PCB v2.3d/Multipro-txV2-3d-cache.lib create mode 100644 PCB v2.3d/Multipro-txV2-3d.cmp create mode 100644 PCB v2.3d/Multipro-txV2-3d.kicad_pcb create mode 100644 PCB v2.3d/Multipro-txV2-3d.net create mode 100644 PCB v2.3d/Multipro-txV2-3d.pro create mode 100644 PCB v2.3d/Multipro-txV2-3d.sch create mode 100644 PCB v2.3d/Readme.txt diff --git a/PCB v2.3d/Multipro-txV2-3d-cache.lib b/PCB v2.3d/Multipro-txV2-3d-cache.lib new file mode 100644 index 0000000..907ee9d --- /dev/null +++ b/PCB v2.3d/Multipro-txV2-3d-cache.lib @@ -0,0 +1,412 @@ +EESchema-LIBRARY Version 2.3 Date: 05/02/2016 16:56:43 +#encoding utf-8 +# +# +5V +# +DEF +5V #PWR 0 40 Y Y 1 F P +F0 "#PWR" 0 90 20 H I C CNN +F1 "+5V" 0 90 30 H V C CNN +F2 "~" 0 0 60 H V C CNN +F3 "~" 0 0 60 H V C CNN +DRAW +X +5V 1 0 0 0 U 20 20 0 0 W N +C 0 50 20 0 1 0 N +P 4 0 1 0 0 0 0 30 0 30 0 30 N +ENDDRAW +ENDDEF +# +# +BATT +# +DEF +BATT #PWR 0 0 Y Y 1 F P +F0 "#PWR" 0 -50 20 H I C CNN +F1 "+BATT" 0 100 30 H V C CNN +F2 "~" 0 0 60 H V C CNN +F3 "~" 0 0 60 H V C CNN +DRAW +X +BATT 1 0 0 0 U 20 20 0 0 w N +C 0 60 20 0 1 0 N +P 3 0 1 0 0 0 0 40 0 40 N +ENDDRAW +ENDDEF +# +# 3V3 +# +DEF 3V3 #PWR 0 0 Y Y 1 F P +F0 "#PWR" 0 100 40 H I C CNN +F1 "3V3" 0 125 40 H V C CNN +F2 "~" 0 0 60 H V C CNN +F3 "~" 0 0 60 H V C CNN +DRAW +X 3V3 1 0 0 0 U 30 30 0 0 W N +P 2 0 1 0 0 60 0 0 N +P 6 0 1 0 0 60 20 40 0 90 -20 40 0 60 0 60 N +ENDDRAW +ENDDEF +# +# A7105 +# +DEF A7105 U 0 40 Y Y 1 F N +F0 "U" 500 650 60 H V C CNN +F1 "A7105" 0 800 60 H V C CNN +F2 "~" 0 -400 60 H V C CNN +F3 "~" 0 -400 60 H V C CNN +DRAW +S 400 -800 -350 700 0 1 0 N +X 3V3 1 -650 550 300 R 70 70 1 1 I +X SCS 2 -650 400 300 R 70 70 1 1 I +X GND 3 -650 250 300 R 70 70 1 1 I +X SCK 4 -650 100 300 R 70 70 1 1 I +X SDIO 5 -650 -50 300 R 70 70 1 1 I +X GIO1 6 -650 -200 300 R 70 70 1 1 I +X GIO2 7 -650 -350 300 R 70 70 1 1 O +X RXEN 8 -650 -500 300 R 70 70 1 1 I +X TXEN 9 -650 -650 300 R 70 70 1 1 O +ENDDRAW +ENDDEF +# +# ATMEGA168A-A +# +DEF ATMEGA168A-A IC 0 40 Y Y 1 F N +F0 "IC" -750 1250 40 H V L BNN +F1 "ATMEGA168A-A" 400 -1400 40 H V L BNN +F2 "TQFP32" 0 0 30 H V C CIN +F3 "~" 0 0 60 H V C CNN +ALIAS ATMEGA48A-A ATMEGA48PA-A ATMEGA88A-A ATMEGA88PA-A ATMEGA168PA-A ATMEGA328-A ATMEGA328P-A +DRAW +S -750 1200 850 -1300 0 1 10 f +X (PCINT19/OC2B/INT1)PD3 1 1000 -800 150 L 40 40 1 1 B +X (PCINT20/XCK/T0)PD4 2 1000 -900 150 L 40 40 1 1 B +X GND 3 -900 -1200 150 R 40 40 1 1 W +X VCC 4 -900 1100 150 R 40 40 1 1 W +X GND 5 -900 -1100 150 R 40 40 1 1 W +X VCC 6 -900 1000 150 R 40 40 1 1 W +X (PCINT6/XTAL1/TOSC1)PB6 7 1000 500 150 L 40 40 1 1 B +X (PCINT7/XTAL2/TOSC2)PB7 8 1000 400 150 L 40 40 1 1 B +X (PCINT21/OC0B/T1)PD5 9 1000 -1000 150 L 40 40 1 1 B +X (PCINT22/OC0A/AIN0)PD6 10 1000 -1100 150 L 40 40 1 1 B +X AREF 20 -900 500 150 R 40 40 1 1 B +X (PCINT16/RXD)PD0 30 1000 -500 150 L 40 40 1 1 B +X (PCINT23/AIN1)PD7 11 1000 -1200 150 L 40 40 1 1 B +X GND 21 -900 -1000 150 R 40 40 1 1 W +X (PCINT17/TXD)PD1 31 1000 -600 150 L 40 40 1 1 B +X (PCINT0/CLKO/ICP1)PB0 12 1000 1100 150 L 40 40 1 1 B +X ADC7 22 -900 -350 150 R 40 40 1 1 N +X (PCINT18/INT0)PD2 32 1000 -700 150 L 40 40 1 1 B +X (PCINT1/OC1A)PB1 13 1000 1000 150 L 40 40 1 1 B +X (PCINT8/ADC0)PC0 23 1000 250 150 L 40 40 1 1 B +X (PCINT2/OC1B/~SS~)PB2 14 1000 900 150 L 40 40 1 1 B +X (PCINT9/ADC1)PC1 24 1000 150 150 L 40 40 1 1 B +X (PCINT3/OC2A/MOSI)PB3 15 1000 800 150 L 40 40 1 1 B +X (PCINT10/ADC2)PC2 25 1000 50 150 L 40 40 1 1 B +X (PCINT4/MISO)PB4 16 1000 700 150 L 40 40 1 1 B +X (PCINT11/ADC3)PC3 26 1000 -50 150 L 40 40 1 1 B +X (PCINT5/SCK)PB5 17 1000 600 150 L 40 40 1 1 B +X (PCINT12/SDA/ADC4)PC4 27 1000 -150 150 L 40 40 1 1 B +X AVCC 18 -900 800 150 R 40 40 1 1 W +X (PCINT14/SCL/ADC5)PC5 28 1000 -250 150 L 40 40 1 1 B +X ADC6 19 -900 -250 150 R 40 40 1 1 N +X (PCINT14/~RESET~)PC6 29 1000 -350 150 L 40 40 1 1 B +ENDDRAW +ENDDEF +# +# C +# +DEF C C 0 10 N Y 1 F N +F0 "C" 0 100 40 H V L CNN +F1 "C" 6 -85 40 H V L CNN +F2 "~" 38 -150 30 H V C CNN +F3 "~" 0 0 60 H V C CNN +$FPLIST + SM* + C? + C1-1 +$ENDFPLIST +DRAW +P 2 0 1 20 -80 -30 80 -30 N +P 2 0 1 20 -80 30 80 30 N +X ~ 1 0 200 170 D 40 40 1 1 P +X ~ 2 0 -200 170 U 40 40 1 1 P +ENDDRAW +ENDDEF +# +# CC2500 +# +DEF CC2500 U 0 40 Y Y 1 F N +F0 "U" 500 600 60 H V C CNN +F1 "CC2500" 0 700 60 H V C CNN +F2 "~" 0 -400 60 H V C CNN +F3 "~" 0 -400 60 H V C CNN +DRAW +S 400 -900 -350 650 0 1 0 N +X 3V3 1 -650 550 300 R 70 70 1 1 I +X SI 2 -650 400 300 R 70 70 1 1 I +X SCLK 3 -650 250 300 R 70 70 1 1 I +X SO 4 -650 100 300 R 70 70 1 1 I +X GDO2 5 -650 -50 300 R 70 70 1 1 I +X GND 6 -650 -200 300 R 70 70 1 1 I +X GDOo 7 -650 -350 300 R 70 70 1 1 I +X CSn 8 -650 -500 300 R 70 70 1 1 I +X PA_EN 9 -650 -650 300 R 70 70 1 1 I +X LNA_EN 10 -650 -800 300 R 70 70 1 1 I +ENDDRAW +ENDDEF +# +# CONN_2 +# +DEF CONN_2 P 0 40 Y N 1 F N +F0 "P" -50 0 40 V V C CNN +F1 "CONN_2" 50 0 40 V V C CNN +F2 "~" 0 0 60 H V C CNN +F3 "~" 0 0 60 H V C CNN +DRAW +S -100 150 100 -150 0 1 0 N +X P1 1 -350 100 250 R 60 60 1 1 P I +X PM 2 -350 -100 250 R 60 60 1 1 P I +ENDDRAW +ENDDEF +# +# CONN_3X2 +# +DEF CONN_3X2 P 0 40 Y N 1 F N +F0 "P" 0 250 50 H V C CNN +F1 "CONN_3X2" 0 50 40 V V C CNN +F2 "~" 0 0 60 H V C CNN +F3 "~" 0 0 60 H V C CNN +DRAW +S -100 200 100 -100 0 1 0 N +X 1 1 -400 150 300 R 60 60 1 1 P I +X 2 2 400 150 300 L 60 60 1 1 P I +X 3 3 -400 50 300 R 60 60 1 1 P I +X 4 4 400 50 300 L 60 60 1 1 P I +X 5 5 -400 -50 300 R 60 60 1 1 P I +X 6 6 400 -50 300 L 60 60 1 1 P I +ENDDRAW +ENDDEF +# +# CONN_5 +# +DEF CONN_5 P 0 40 Y Y 1 F N +F0 "P" -50 0 50 V V C CNN +F1 "CONN_5" 50 0 50 V V C CNN +F2 "~" 0 0 60 H V C CNN +F3 "~" 0 0 60 H V C CNN +DRAW +S -100 250 100 -250 0 1 0 f +X ~ 1 -400 200 300 R 60 60 1 1 P I +X ~ 2 -400 100 300 R 60 60 1 1 P I +X ~ 3 -400 0 300 R 60 60 1 1 P I +X ~ 4 -400 -100 300 R 60 60 1 1 P I +X ~ 5 -400 -200 300 R 60 60 1 1 P I +ENDDRAW +ENDDEF +# +# CP1 +# +DEF CP1 C 0 10 N N 1 F N +F0 "C" 50 100 50 H V L CNN +F1 "CP1" 50 -100 50 H V L CNN +F2 "~" 0 0 60 H V C CNN +F3 "~" 0 0 60 H V C CNN +$FPLIST + CP* + SM* +$ENDFPLIST +DRAW +T 0 -50 100 80 0 0 0 + Normal 0 C C +A 0 -200 180 563 1236 0 1 15 N 100 -50 -100 -50 +P 4 0 1 15 -100 50 100 50 50 50 50 50 N +X ~ 1 0 200 150 D 40 40 1 1 P +X ~ 2 0 -200 180 U 40 40 1 1 P +ENDDRAW +ENDDEF +# +# CRYSTAL +# +DEF CRYSTAL X 0 40 N N 1 F N +F0 "X" 0 150 60 H V C CNN +F1 "CRYSTAL" 0 -150 60 H V C CNN +F2 "~" 0 0 60 H V C CNN +F3 "~" 0 0 60 H V C CNN +DRAW +P 2 0 1 16 -100 100 -100 -100 N +P 2 0 1 16 100 100 100 -100 N +P 5 0 1 12 -50 50 50 50 50 -50 -50 -50 -50 50 f +X 1 1 -300 -50 200 R 40 40 1 1 P +X 2 2 -300 50 200 R 40 40 1 1 P +X 3 3 300 50 200 L 40 40 1 1 P +X 4 4 300 -50 200 L 40 40 1 1 P +ENDDRAW +ENDDEF +# +# CYRF6936 +# +DEF CYRF6936 U 0 40 Y Y 1 F N +F0 "U" 0 1000 60 H V C CNN +F1 "CYRF6936" 0 800 60 H V C CNN +F2 "~" 0 -400 60 H V C CNN +F3 "~" 0 -400 60 H V C CNN +DRAW +S 400 -800 -350 700 0 1 0 N +X 5.0V 1 -650 500 300 R 70 70 1 1 I +X NCS 2 -650 350 300 R 70 70 1 1 I +X SCK 4 -650 200 300 R 70 70 1 1 I +X GND 5 -650 50 300 R 70 70 1 1 I +X GND 6 -650 -100 300 R 70 70 1 1 I +X MOSI 8 -650 -250 300 R 70 70 1 1 I +X RST 9 -650 -400 300 R 70 70 1 1 I +X MISO 10 -650 -600 300 R 70 70 1 1 I +ENDDRAW +ENDDEF +# +# GND +# +DEF ~GND #PWR 0 0 Y Y 1 F P +F0 "#PWR" 0 0 30 H I C CNN +F1 "GND" 0 -70 30 H I C CNN +F2 "~" 0 0 60 H V C CNN +F3 "~" 0 0 60 H V C CNN +DRAW +P 4 0 1 0 -50 0 0 -50 50 0 -50 0 N +X GND 1 0 0 0 U 30 30 1 1 W N +ENDDRAW +ENDDEF +# +# HEX_DIP +# +DEF HEX_DIP SW 0 40 Y Y 1 F N +F0 "SW" 0 -350 60 H V C CNN +F1 "HEX_DIP" 0 350 60 H V C CNN +F2 "~" 0 0 60 H V C CNN +F3 "~" 0 0 60 H V C CNN +DRAW +S -200 250 200 -250 0 1 0 N +P 4 0 1 0 50 50 -50 0 50 -100 50 50 F +X 1 1 500 -150 300 L 50 50 1 1 O +X C 2 500 0 300 L 50 50 1 1 P +X 4 3 500 150 300 L 50 50 1 1 O +X 2 4 -500 150 300 R 50 50 1 1 O +X C 5 -500 0 300 R 50 50 1 1 P +X 8 6 -500 -150 300 R 50 50 1 1 O +ENDDRAW +ENDDEF +# +# JUMPER +# +DEF JUMPER JP 0 30 Y N 1 F N +F0 "JP" 0 150 60 H V C CNN +F1 "JUMPER" 0 -80 40 H V C CNN +F2 "~" 0 0 60 H V C CNN +F3 "~" 0 0 60 H V C CNN +DRAW +A 0 -26 125 1426 373 0 1 0 N -98 50 99 50 +C -100 0 35 0 1 0 N +C 100 0 35 0 1 0 N +X 1 1 -300 0 165 R 60 60 0 1 P +X 2 2 300 0 165 L 60 60 0 1 P +ENDDRAW +ENDDEF +# +# LED +# +DEF LED D 0 40 Y N 1 F N +F0 "D" 0 100 50 H V C CNN +F1 "LED" 0 -100 50 H V C CNN +F2 "~" 0 0 60 H V C CNN +F3 "~" 0 0 60 H V C CNN +$FPLIST + LED-3MM + LED-5MM + LED-10MM + LED-0603 + LED-0805 + LED-1206 + LEDV +$ENDFPLIST +DRAW +P 2 0 1 0 50 50 50 -50 N +P 3 0 1 0 -50 50 50 0 -50 -50 F +P 3 0 1 0 65 -40 110 -80 105 -55 N +P 3 0 1 0 80 -25 125 -65 120 -40 N +X A 1 -200 0 150 R 40 40 1 1 P +X K 2 200 0 150 L 40 40 1 1 P +ENDDRAW +ENDDEF +# +# NCP1117ST50T3G +# +DEF NCP1117ST50T3G U 0 30 Y Y 1 F N +F0 "U" 150 -196 40 H V C CNN +F1 "NCP1117ST50T3G" 0 200 40 H V C CNN +F2 "~" 0 0 60 H V C CNN +F3 "~" 0 0 60 H V C CNN +ALIAS NCP1117ST12T3G NCP1117ST15T3G NCP1117ST18T3G NCP1117ST20T3G NCP1117ST25T3G NCP1117ST285T3G NCP1117ST33T3G +$FPLIST + SOT223 +$ENDFPLIST +DRAW +S -250 -150 250 150 0 1 10 f +X GND 1 0 -250 100 U 40 40 1 1 W +X VO 2 400 50 150 L 40 40 1 1 w +X VI 3 -400 50 150 R 40 40 1 1 W +ENDDRAW +ENDDEF +# +# NRF24L01 +# +DEF NRF24L01 U 0 40 Y Y 1 F N +F0 "U" 500 650 60 H V C CNN +F1 "NRF24L01" 0 800 60 H V C CNN +F2 "~" 0 -400 60 H V C CNN +F3 "~" 0 -400 60 H V C CNN +DRAW +S 400 -650 -350 700 0 1 0 N +X GND 1 -650 550 300 R 70 70 1 1 I +X 3V3 2 -650 400 300 R 70 70 1 1 I +X CE 3 -650 250 300 R 70 70 1 1 I +X CSN 4 -650 100 300 R 70 70 1 1 I +X SCK 5 -650 -50 300 R 70 70 1 1 I +X MOSI 6 -650 -200 300 R 70 70 1 1 I +X MISO 7 -650 -350 300 R 70 70 1 1 I +X IRQ 8 -650 -500 300 R 70 70 1 1 N +ENDDRAW +ENDDEF +# +# R +# +DEF R R 0 0 N Y 1 F N +F0 "R" 80 0 40 V V C CNN +F1 "R" 7 1 40 V V C CNN +F2 "~" -70 0 30 V V C CNN +F3 "~" 0 0 30 H V C CNN +$FPLIST + R? + SM0603 + SM0805 + R?-* + SM1206 +$ENDFPLIST +DRAW +S -40 150 40 -150 0 1 12 N +X ~ 1 0 250 100 D 60 60 1 1 P +X ~ 2 0 -250 100 U 60 60 1 1 P +ENDDRAW +ENDDEF +# +# SW_PUSH_4_Pin +# +DEF SW_PUSH_4_Pin SW 0 40 N N 1 F N +F0 "SW" 150 110 50 H V C CNN +F1 "SW_PUSH_4_Pin" 0 -200 50 H V C CNN +F2 "~" 0 0 60 H V C CNN +F3 "~" 0 0 60 H V C CNN +DRAW +S -170 50 170 60 0 1 0 N +P 4 0 1 0 -40 60 -30 90 30 90 40 60 N +X 1 1 -300 0 200 R 60 60 0 1 P I +X 3 3 300 0 200 L 60 60 0 1 P I +X 2 2 -300 -100 200 R 50 50 1 1 I I +X 4 4 300 -100 200 L 50 50 1 1 I I +ENDDRAW +ENDDEF +# +#End Library diff --git a/PCB v2.3d/Multipro-txV2-3d.cmp b/PCB v2.3d/Multipro-txV2-3d.cmp new file mode 100644 index 0000000..f43c236 --- /dev/null +++ b/PCB v2.3d/Multipro-txV2-3d.cmp @@ -0,0 +1,248 @@ +Cmp-Mod V01 Created by CvPcb (2013-07-07 BZR 4022)-stable date = 05/02/2016 14:40:56 + +BeginCmp +TimeStamp = /53C2AE5B; +Reference = C1; +ValeurCmp = 22uF; +IdModule = c_tant_B; +EndCmp + +BeginCmp +TimeStamp = /53BC5DA8; +Reference = C2; +ValeurCmp = 0.1uF; +IdModule = SM0603_Capa; +EndCmp + +BeginCmp +TimeStamp = /53C2AE76; +Reference = C3; +ValeurCmp = 22uF; +IdModule = c_tant_B; +EndCmp + +BeginCmp +TimeStamp = /53BC62F4; +Reference = C4; +ValeurCmp = 18pF; +IdModule = SM0603_Capa; +EndCmp + +BeginCmp +TimeStamp = /53BC631E; +Reference = C5; +ValeurCmp = 18pF; +IdModule = SM0603_Capa; +EndCmp + +BeginCmp +TimeStamp = /53C2B150; +Reference = C6; +ValeurCmp = 22uF; +IdModule = c_tant_B; +EndCmp + +BeginCmp +TimeStamp = /54845FE2; +Reference = C7; +ValeurCmp = 0.1uF; +IdModule = SM0603_Capa; +EndCmp + +BeginCmp +TimeStamp = /53BC617C; +Reference = D1; +ValeurCmp = LED; +IdModule = LED-0603; +EndCmp + +BeginCmp +TimeStamp = /53C2D9F8; +Reference = D2; +ValeurCmp = LED; +IdModule = LED-0603; +EndCmp + +BeginCmp +TimeStamp = /53BC5C99; +Reference = IC1; +ValeurCmp = ATMEGA328-A; +IdModule = TQFP32; +EndCmp + +BeginCmp +TimeStamp = /53FE5887; +Reference = JP1; +ValeurCmp = JUMPER; +IdModule = c_0603; +EndCmp + +BeginCmp +TimeStamp = /53FE5896; +Reference = JP2; +ValeurCmp = JUMPER; +IdModule = c_0603; +EndCmp + +BeginCmp +TimeStamp = /56B4E4E1; +Reference = JP3; +ValeurCmp = JUMPER; +IdModule = c_0603; +EndCmp + +BeginCmp +TimeStamp = /56B4EFD5; +Reference = JP4; +ValeurCmp = JUMPER; +IdModule = c_0603; +EndCmp + +BeginCmp +TimeStamp = /53C2DBCC; +Reference = P1; +ValeurCmp = ISP; +IdModule = pin_array_3x2; +EndCmp + +BeginCmp +TimeStamp = /53FE5423; +Reference = P2; +ValeurCmp = CONN_5; +IdModule = MOLEX_4455_N2X5; +EndCmp + +BeginCmp +TimeStamp = /56B4E4CA; +Reference = P3; +ValeurCmp = CONN_2; +IdModule = PIN_ARRAY_2X1; +EndCmp + +BeginCmp +TimeStamp = /53BC5FEA; +Reference = R1; +ValeurCmp = 10K; +IdModule = SM0603_Resistor; +EndCmp + +BeginCmp +TimeStamp = /53C2B990; +Reference = R2; +ValeurCmp = 2K2; +IdModule = SM0603_Resistor; +EndCmp + +BeginCmp +TimeStamp = /53C2B99F; +Reference = R3; +ValeurCmp = 1K; +IdModule = SM0603_Resistor; +EndCmp + +BeginCmp +TimeStamp = /53BC6125; +Reference = R4; +ValeurCmp = 1K; +IdModule = SM0603_Resistor; +EndCmp + +BeginCmp +TimeStamp = /53C2B787; +Reference = R5; +ValeurCmp = 2K2; +IdModule = SM0603_Resistor; +EndCmp + +BeginCmp +TimeStamp = /53C2D8C4; +Reference = R6; +ValeurCmp = 1K; +IdModule = SM0603_Resistor; +EndCmp + +BeginCmp +TimeStamp = /54DCE006; +Reference = R7; +ValeurCmp = 2K2; +IdModule = SM0603_Resistor; +EndCmp + +BeginCmp +TimeStamp = /56B4E6D8; +Reference = R8; +ValeurCmp = 470; +IdModule = SM0603_Resistor; +EndCmp + +BeginCmp +TimeStamp = /54394777; +Reference = SW1; +ValeurCmp = HEX_DIP; +IdModule = DIP-6__300; +EndCmp + +BeginCmp +TimeStamp = /56B4EC6E; +Reference = SW2; +ValeurCmp = BIND; +IdModule = SW_PUSH_6x4.5MM; +EndCmp + +BeginCmp +TimeStamp = /56B4EC7B; +Reference = SW3; +ValeurCmp = RESET; +IdModule = Switch_SMT5mm; +EndCmp + +BeginCmp +TimeStamp = /53C2ACE9; +Reference = U1; +ValeurCmp = NCP1117ST50T3G; +IdModule = SOT223; +EndCmp + +BeginCmp +TimeStamp = /53C2AD08; +Reference = U2; +ValeurCmp = NCP1117ST33T3G; +IdModule = SOT223; +EndCmp + +BeginCmp +TimeStamp = /53C2BF57; +Reference = U3; +ValeurCmp = CYRF6936; +IdModule = CYRF6936; +EndCmp + +BeginCmp +TimeStamp = /53C2C184; +Reference = U4; +ValeurCmp = A7105; +IdModule = XL7105-D03B; +EndCmp + +BeginCmp +TimeStamp = /53C2C24E; +Reference = U5; +ValeurCmp = NRF24L01; +IdModule = NRF24L01; +EndCmp + +BeginCmp +TimeStamp = /53C2C3F4; +Reference = U6; +ValeurCmp = CC2500; +IdModule = header_10_2mm; +EndCmp + +BeginCmp +TimeStamp = /53BC62D3; +Reference = X1; +ValeurCmp = 16MHz; +IdModule = crystal_FA238-TSX3225; +EndCmp + +EndListe diff --git a/PCB v2.3d/Multipro-txV2-3d.kicad_pcb b/PCB v2.3d/Multipro-txV2-3d.kicad_pcb new file mode 100644 index 0000000..9e0c533 --- /dev/null +++ b/PCB v2.3d/Multipro-txV2-3d.kicad_pcb @@ -0,0 +1,3253 @@ +(kicad_pcb (version 3) (host pcbnew "(2013-07-07 BZR 4022)-stable") + + (general + (links 101) + (no_connects 0) + (area 105.584144 58.5 183.200001 116.700001) + (thickness 1.6) + (drawings 18) + (tracks 492) + (zones 0) + (modules 38) + (nets 39) + ) + + (page A) + (layers + (15 F.Cu signal) + (0 B.Cu signal) + (16 B.Adhes user) + (17 F.Adhes user) + (18 B.Paste user) + (19 F.Paste user) + (20 B.SilkS user) + (21 F.SilkS user) + (22 B.Mask user) + (23 F.Mask user) + (24 Dwgs.User user) + (25 Cmts.User user) + (26 Eco1.User user) + (27 Eco2.User user) + (28 Edge.Cuts user) + ) + + (setup + (last_trace_width 0.254) + (user_trace_width 0.4) + (user_trace_width 0.6) + (user_trace_width 1) + (trace_clearance 0.254) + (zone_clearance 0.25) + (zone_45_only no) + (trace_min 0.254) + (segment_width 0.4) + (edge_width 0.1) + (via_size 0.889) + (via_drill 0.635) + (via_min_size 0.254) + (via_min_drill 0.127) + (user_via 0.254 0.127) + (user_via 0.381 0.254) + (uvia_size 0.254) + (uvia_drill 0.127) + (uvias_allowed yes) + (uvia_min_size 0.254) + (uvia_min_drill 0.127) + (pcb_text_width 0.3) + (pcb_text_size 1.5 1.5) + (mod_edge_width 0.15) + (mod_text_size 1 1) + (mod_text_width 0.15) + (pad_size 1.69926 1.69926) + (pad_drill 1) + (pad_to_mask_clearance 0) + (aux_axis_origin 0 0) + (visible_elements 7FFFFFBF) + (pcbplotparams + (layerselection 284983297) + (usegerberextensions true) + (excludeedgelayer true) + (linewidth 0.150000) + (plotframeref false) + (viasonmask false) + (mode 1) + (useauxorigin false) + (hpglpennumber 1) + (hpglpenspeed 20) + (hpglpendiameter 15) + (hpglpenoverlay 2) + (psnegative false) + (psa4output false) + (plotreference true) + (plotvalue true) + (plotothertext true) + (plotinvisibletext false) + (padsonsilk false) + (subtractmaskfromsilk true) + (outputformat 1) + (mirror false) + (drillshape 0) + (scaleselection 1) + (outputdirectory "Gerber Files/")) + ) + + (net 0 "") + (net 1 +5V) + (net 2 /A0) + (net 3 /A7105_CSN) + (net 4 /BATT) + (net 5 /CC25_CSN) + (net 6 /CC25_LANEN) + (net 7 /CC25_PAEN) + (net 8 /CYRF_CSN) + (net 9 /CYRF_RST) + (net 10 /D10) + (net 11 /D11) + (net 12 /D12) + (net 13 /D3) + (net 14 /MISO) + (net 15 /MOSI) + (net 16 /NRF_CE) + (net 17 /NRF_CSN) + (net 18 /PB5) + (net 19 /PPM_IN) + (net 20 /RESET) + (net 21 /RX) + (net 22 /SCK) + (net 23 /TX) + (net 24 /xtl1) + (net 25 /xtl2) + (net 26 3V3) + (net 27 GND) + (net 28 N-0000012) + (net 29 N-0000013) + (net 30 N-0000019) + (net 31 N-000002) + (net 32 N-0000020) + (net 33 N-0000021) + (net 34 N-0000022) + (net 35 N-0000023) + (net 36 N-0000025) + (net 37 N-0000034) + (net 38 N-0000043) + + (net_class Default "This is the default net class." + (clearance 0.254) + (trace_width 0.254) + (via_dia 0.889) + (via_drill 0.635) + (uvia_dia 0.254) + (uvia_drill 0.127) + (add_net "") + (add_net +5V) + (add_net /A0) + (add_net /A7105_CSN) + (add_net /BATT) + (add_net /CC25_CSN) + (add_net /CC25_LANEN) + (add_net /CC25_PAEN) + (add_net /CYRF_CSN) + (add_net /CYRF_RST) + (add_net /D10) + (add_net /D11) + (add_net /D12) + (add_net /D3) + (add_net /MISO) + (add_net /MOSI) + (add_net /NRF_CE) + (add_net /NRF_CSN) + (add_net /PB5) + (add_net /PPM_IN) + (add_net /RESET) + (add_net /RX) + (add_net /SCK) + (add_net /TX) + (add_net /xtl1) + (add_net /xtl2) + (add_net 3V3) + (add_net GND) + (add_net N-0000012) + (add_net N-0000013) + (add_net N-0000019) + (add_net N-000002) + (add_net N-0000020) + (add_net N-0000021) + (add_net N-0000022) + (add_net N-0000023) + (add_net N-0000025) + (add_net N-0000034) + (add_net N-0000043) + ) + + (module MOLEX_4455_N2X5 (layer F.Cu) (tedit 56B4BA39) (tstamp 53FE56C1) + (at 178.1 108.5 270) + (descr "Double rangee de contacts 2 x 5 pins") + (tags CONN) + (path /53FE5423) + (fp_text reference P2 (at 0 -2.54 270) (layer F.SilkS) + (effects (font (size 1.016 1.016) (thickness 0.2032))) + ) + (fp_text value CONN_5 (at 0.254 8.128 270) (layer F.SilkS) hide + (effects (font (size 1.016 1.016) (thickness 0.2032))) + ) + (fp_line (start -6.35 -1.524) (end -6.35 6.6548) (layer F.SilkS) (width 0.3048)) + (fp_line (start 6.35 -1.524) (end 6.35 6.6548) (layer F.SilkS) (width 0.3048)) + (fp_line (start -6.35 -1.524) (end 6.35 -1.524) (layer F.SilkS) (width 0.3048)) + (fp_line (start 6.35 6.6548) (end -6.35 6.6548) (layer F.SilkS) (width 0.3048)) + (pad 1 thru_hole rect (at -5.08 3.81 270) (size 1.778 1.778) (drill 1.0668) + (layers *.Cu *.Mask F.SilkS) + (net 19 /PPM_IN) + ) + (pad 2 thru_hole circle (at -2.54 3.81 270) (size 1.778 1.778) (drill 1.0668) + (layers *.Cu *.Mask F.SilkS) + (net 36 N-0000025) + ) + (pad 3 thru_hole circle (at 0 3.81 270) (size 1.778 1.778) (drill 1.0668) + (layers *.Cu *.Mask F.SilkS) + (net 4 /BATT) + ) + (pad 4 thru_hole circle (at 2.54 3.81 270) (size 1.778 1.778) (drill 1.0668) + (layers *.Cu *.Mask F.SilkS) + (net 27 GND) + ) + (pad 5 thru_hole circle (at 5.08 3.81 270) (size 1.778 1.778) (drill 1.0668) + (layers *.Cu *.Mask F.SilkS) + (net 32 N-0000020) + ) + (pad "" np_thru_hole circle (at 0 0 270) (size 1.778 1.778) (drill 1.778) + (layers *.Cu *.Mask F.SilkS) + ) + (pad "" np_thru_hole circle (at 2.54 0 270) (size 1.778 1.778) (drill 1.778) + (layers *.Cu *.Mask F.SilkS) + ) + (pad "" np_thru_hole circle (at 5.08 0 270) (size 1.778 1.778) (drill 1.778) + (layers *.Cu *.Mask F.SilkS) + ) + (pad "" np_thru_hole circle (at -2.54 0 270) (size 1.778 1.778) (drill 1.778) + (layers *.Cu *.Mask F.SilkS) + ) + (pad "" np_thru_hole circle (at -5.08 0 270) (size 1.778 1.778) (drill 1.778) + (layers *.Cu *.Mask F.SilkS) + ) + (model pin_array/pins_array_5x1.wrl + (at (xyz 0 0 0)) + (scale (xyz 1 1 1)) + (rotate (xyz 0 0 0)) + ) + ) + + (module SOT223 (layer F.Cu) (tedit 54BBF448) (tstamp 5489DFE1) + (at 169 96 270) + (descr "module CMS SOT223 4 pins") + (tags "CMS SOT") + (path /53C2ACE9) + (attr smd) + (fp_text reference U1 (at -3.1 -6.65 360) (layer F.SilkS) + (effects (font (size 1.016 1.016) (thickness 0.2032))) + ) + (fp_text value NCP1117ST50T3G (at 0 0.762 270) (layer F.SilkS) + (effects (font (size 0.5 0.5) (thickness 0.125))) + ) + (fp_line (start -3.556 1.524) (end -3.556 4.572) (layer F.SilkS) (width 0.2032)) + (fp_line (start -3.556 4.572) (end 3.556 4.572) (layer F.SilkS) (width 0.2032)) + (fp_line (start 3.556 4.572) (end 3.556 1.524) (layer F.SilkS) (width 0.2032)) + (fp_line (start -3.556 -1.524) (end -3.556 -2.286) (layer F.SilkS) (width 0.2032)) + (fp_line (start -3.556 -2.286) (end -2.032 -4.572) (layer F.SilkS) (width 0.2032)) + (fp_line (start -2.032 -4.572) (end 2.032 -4.572) (layer F.SilkS) (width 0.2032)) + (fp_line (start 2.032 -4.572) (end 3.556 -2.286) (layer F.SilkS) (width 0.2032)) + (fp_line (start 3.556 -2.286) (end 3.556 -1.524) (layer F.SilkS) (width 0.2032)) + (pad 4 smd rect (at 0 -3.302 270) (size 3.8 4) + (layers F.Cu F.Paste F.Mask) + ) + (pad 2 smd rect (at 0 3.302 270) (size 1.5 2.032) + (layers F.Cu F.Paste F.Mask) + (net 1 +5V) + ) + (pad 3 smd rect (at 2.286 3.302 270) (size 1.5 2.032) + (layers F.Cu F.Paste F.Mask) + (net 4 /BATT) + ) + (pad 1 smd rect (at -2.286 3.302 270) (size 1.5 2.032) + (layers F.Cu F.Paste F.Mask) + (net 27 GND) + ) + (model smd/SOT223.wrl + (at (xyz 0 0 0)) + (scale (xyz 0.4 0.4 0.4)) + (rotate (xyz 0 0 0)) + ) + ) + + (module DIP-6__300 (layer F.Cu) (tedit 548E3887) (tstamp 53C2D6AB) + (at 146.6 109.7 270) + (descr "6 pins DIL package, round pads") + (tags DIL) + (path /54394777) + (fp_text reference SW1 (at -5.4 -0.1 360) (layer F.SilkS) + (effects (font (size 1.016 1.016) (thickness 0.2032))) + ) + (fp_text value HEX_DIP (at 0.7 0 270) (layer F.SilkS) + (effects (font (size 0.889 0.889) (thickness 0.2032))) + ) + (fp_line (start -4.445 -2.54) (end 4.445 -2.54) (layer F.SilkS) (width 0.381)) + (fp_line (start 4.445 -2.54) (end 4.445 2.54) (layer F.SilkS) (width 0.381)) + (fp_line (start 4.445 2.54) (end -4.445 2.54) (layer F.SilkS) (width 0.381)) + (fp_line (start -4.445 2.54) (end -4.445 -2.54) (layer F.SilkS) (width 0.381)) + (fp_line (start -4.445 -0.635) (end -3.175 -0.635) (layer F.SilkS) (width 0.381)) + (fp_line (start -3.175 -0.635) (end -3.175 0.635) (layer F.SilkS) (width 0.381)) + (fp_line (start -3.175 0.635) (end -4.445 0.635) (layer F.SilkS) (width 0.381)) + (pad 1 thru_hole rect (at -2.54 3.81 270) (size 1.7 1.7) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 10 /D10) + ) + (pad 2 thru_hole circle (at 0 3.81 270) (size 1.7 1.7) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 27 GND) + ) + (pad 3 thru_hole circle (at 2.54 3.81 270) (size 1.7 1.7) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 12 /D12) + ) + (pad 4 thru_hole circle (at 2.54 -3.81 270) (size 1.7 1.7) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 11 /D11) + ) + (pad 5 thru_hole circle (at 0 -3.81 270) (size 1.7 1.7) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 27 GND) + ) + (pad 6 thru_hole circle (at -2.54 -3.81 270) (size 1.7 1.7) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 2 /A0) + ) + (model dil/dil_6.wrl + (at (xyz 0 0 0)) + (scale (xyz 1 1 1)) + (rotate (xyz 0 0 0)) + ) + ) + + (module SOT223 (layer F.Cu) (tedit 54947BEE) (tstamp 5489DFF1) + (at 153 96 90) + (descr "module CMS SOT223 4 pins") + (tags "CMS SOT") + (path /53C2AD08) + (attr smd) + (fp_text reference U2 (at 4 -4.1 180) (layer F.SilkS) + (effects (font (size 1.016 1.016) (thickness 0.2032))) + ) + (fp_text value NCP1117ST33T3G (at -0.2 0.8 90) (layer F.SilkS) + (effects (font (size 0.5 0.5) (thickness 0.125))) + ) + (fp_line (start -3.556 1.524) (end -3.556 4.572) (layer F.SilkS) (width 0.2032)) + (fp_line (start -3.556 4.572) (end 3.556 4.572) (layer F.SilkS) (width 0.2032)) + (fp_line (start 3.556 4.572) (end 3.556 1.524) (layer F.SilkS) (width 0.2032)) + (fp_line (start -3.556 -1.524) (end -3.556 -2.286) (layer F.SilkS) (width 0.2032)) + (fp_line (start -3.556 -2.286) (end -2.032 -4.572) (layer F.SilkS) (width 0.2032)) + (fp_line (start -2.032 -4.572) (end 2.032 -4.572) (layer F.SilkS) (width 0.2032)) + (fp_line (start 2.032 -4.572) (end 3.556 -2.286) (layer F.SilkS) (width 0.2032)) + (fp_line (start 3.556 -2.286) (end 3.556 -1.524) (layer F.SilkS) (width 0.2032)) + (pad 4 smd rect (at 0 -3.302 90) (size 3.8 4) + (layers F.Cu F.Paste F.Mask) + ) + (pad 2 smd rect (at 0 3.302 90) (size 1.5 2.032) + (layers F.Cu F.Paste F.Mask) + (net 26 3V3) + ) + (pad 3 smd rect (at 2.286 3.302 90) (size 1.5 2.032) + (layers F.Cu F.Paste F.Mask) + (net 1 +5V) + ) + (pad 1 smd rect (at -2.286 3.302 90) (size 1.5 2.032) + (layers F.Cu F.Paste F.Mask) + (net 27 GND) + ) + (model smd/SOT223.wrl + (at (xyz 0 0 0)) + (scale (xyz 0.4 0.4 0.4)) + (rotate (xyz 0 0 0)) + ) + ) + + (module XL7105-D03B (layer F.Cu) (tedit 54837681) (tstamp 547F531E) + (at 153.4 77.7 270) + (descr "Double rangee de contacts 2 x 5 pins") + (tags CONN) + (path /53C2C184) + (fp_text reference U4 (at -2.7 6.4 360) (layer F.SilkS) + (effects (font (size 1.016 1.016) (thickness 0.2032))) + ) + (fp_text value A7105 (at -2.7 2.4 360) (layer F.SilkS) + (effects (font (size 1.016 1.016) (thickness 0.2032))) + ) + (fp_line (start -6 -9) (end 20 -9) (layer F.SilkS) (width 0.3048)) + (fp_line (start 20 -9) (end 20 9) (layer F.SilkS) (width 0.3048)) + (fp_line (start -6 9) (end 20 9) (layer F.SilkS) (width 0.3048)) + (fp_line (start -6 9) (end -6 -9) (layer F.SilkS) (width 0.3048)) + (pad 1 thru_hole rect (at -5 -8 270) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 26 3V3) + ) + (pad 2 thru_hole circle (at -5 -6 270) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 3 /A7105_CSN) + ) + (pad 4 thru_hole circle (at -5 -2 270) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 22 /SCK) + ) + (pad 5 thru_hole circle (at -5 0 270) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 15 /MOSI) + ) + (pad 6 thru_hole circle (at -5 2 270) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 29 N-0000013) + ) + (pad 7 thru_hole circle (at -5 4 270) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 28 N-0000012) + ) + (pad 8 thru_hole circle (at -5 6 270) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 28 N-0000012) + ) + (pad 9 thru_hole circle (at -5 8 270) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 29 N-0000013) + ) + (pad 3 thru_hole circle (at -5 -4 270) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 27 GND) + ) + (model pin_array/pins_array_5x2.wrl + (at (xyz 0 0 0)) + (scale (xyz 1 1 1)) + (rotate (xyz 0 0 0)) + ) + ) + + (module TQFP32 (layer F.Cu) (tedit 56B52925) (tstamp 5436F802) + (at 167 85.3 315) + (path /53BC5C99) + (fp_text reference IC1 (at -4.949747 -5.091169 315) (layer F.SilkS) + (effects (font (size 1.27 1.016) (thickness 0.2032))) + ) + (fp_text value ATMEGA328P (at 0.214253 6.852572 315) (layer F.SilkS) + (effects (font (size 1.27 0.8) (thickness 0.2))) + ) + (fp_line (start 5.0292 2.7686) (end 3.8862 2.7686) (layer F.SilkS) (width 0.1524)) + (fp_line (start 5.0292 -2.7686) (end 3.9116 -2.7686) (layer F.SilkS) (width 0.1524)) + (fp_line (start 5.0292 2.7686) (end 5.0292 -2.7686) (layer F.SilkS) (width 0.1524)) + (fp_line (start 2.794 3.9624) (end 2.794 5.0546) (layer F.SilkS) (width 0.1524)) + (fp_line (start -2.8194 3.9878) (end -2.8194 5.0546) (layer F.SilkS) (width 0.1524)) + (fp_line (start -2.8448 5.0546) (end 2.794 5.08) (layer F.SilkS) (width 0.1524)) + (fp_line (start -2.794 -5.0292) (end 2.7178 -5.0546) (layer F.SilkS) (width 0.1524)) + (fp_line (start -3.8862 -3.2766) (end -3.8862 3.9116) (layer F.SilkS) (width 0.1524)) + (fp_line (start 2.7432 -5.0292) (end 2.7432 -3.9878) (layer F.SilkS) (width 0.1524)) + (fp_line (start -3.2512 -3.8862) (end 3.81 -3.8862) (layer F.SilkS) (width 0.1524)) + (fp_line (start 3.8608 3.937) (end 3.8608 -3.7846) (layer F.SilkS) (width 0.1524)) + (fp_line (start -3.8862 3.937) (end 3.7338 3.937) (layer F.SilkS) (width 0.1524)) + (fp_line (start -5.0292 -2.8448) (end -5.0292 2.794) (layer F.SilkS) (width 0.1524)) + (fp_line (start -5.0292 2.794) (end -3.8862 2.794) (layer F.SilkS) (width 0.1524)) + (fp_line (start -3.87604 -3.302) (end -3.29184 -3.8862) (layer F.SilkS) (width 0.1524)) + (fp_line (start -5.02412 -2.8448) (end -3.87604 -2.8448) (layer F.SilkS) (width 0.1524)) + (fp_line (start -2.794 -3.8862) (end -2.794 -5.03428) (layer F.SilkS) (width 0.1524)) + (fp_circle (center -2.83972 -2.86004) (end -2.43332 -2.60604) (layer F.SilkS) (width 0.1524)) + (pad 8 smd rect (at -4.81584 2.77622 315) (size 1.99898 0.44958) + (layers F.Cu F.Paste F.Mask) + (net 25 /xtl2) + ) + (pad 7 smd rect (at -4.81584 1.97612 315) (size 1.99898 0.44958) + (layers F.Cu F.Paste F.Mask) + (net 24 /xtl1) + ) + (pad 6 smd rect (at -4.81584 1.17602 315) (size 1.99898 0.44958) + (layers F.Cu F.Paste F.Mask) + (net 26 3V3) + ) + (pad 5 smd rect (at -4.81584 0.37592 315) (size 1.99898 0.44958) + (layers F.Cu F.Paste F.Mask) + (net 27 GND) + ) + (pad 4 smd rect (at -4.81584 -0.42418 315) (size 1.99898 0.44958) + (layers F.Cu F.Paste F.Mask) + (net 26 3V3) + ) + (pad 3 smd rect (at -4.81584 -1.22428 315) (size 1.99898 0.44958) + (layers F.Cu F.Paste F.Mask) + (net 27 GND) + ) + (pad 2 smd rect (at -4.81584 -2.02438 315) (size 1.99898 0.44958) + (layers F.Cu F.Paste F.Mask) + (net 22 /SCK) + ) + (pad 1 smd rect (at -4.81584 -2.82448 315) (size 1.99898 0.44958) + (layers F.Cu F.Paste F.Mask) + (net 13 /D3) + ) + (pad 24 smd rect (at 4.7498 -2.8194 315) (size 1.99898 0.44958) + (layers F.Cu F.Paste F.Mask) + ) + (pad 17 smd rect (at 4.7498 2.794 315) (size 1.99898 0.44958) + (layers F.Cu F.Paste F.Mask) + (net 18 /PB5) + ) + (pad 18 smd rect (at 4.7498 1.9812 315) (size 1.99898 0.44958) + (layers F.Cu F.Paste F.Mask) + (net 26 3V3) + ) + (pad 19 smd rect (at 4.7498 1.1684 315) (size 1.99898 0.44958) + (layers F.Cu F.Paste F.Mask) + ) + (pad 20 smd rect (at 4.7498 0.381 315) (size 1.99898 0.44958) + (layers F.Cu F.Paste F.Mask) + (net 38 N-0000043) + ) + (pad 21 smd rect (at 4.7498 -0.4318 315) (size 1.99898 0.44958) + (layers F.Cu F.Paste F.Mask) + (net 27 GND) + ) + (pad 22 smd rect (at 4.7498 -1.2192 315) (size 1.99898 0.44958) + (layers F.Cu F.Paste F.Mask) + ) + (pad 23 smd rect (at 4.7498 -2.032 315) (size 1.99898 0.44958) + (layers F.Cu F.Paste F.Mask) + (net 2 /A0) + ) + (pad 32 smd rect (at -2.82448 -4.826 315) (size 0.44958 1.99898) + (layers F.Cu F.Paste F.Mask) + (net 3 /A7105_CSN) + ) + (pad 31 smd rect (at -2.02692 -4.826 315) (size 0.44958 1.99898) + (layers F.Cu F.Paste F.Mask) + (net 23 /TX) + ) + (pad 30 smd rect (at -1.22428 -4.826 315) (size 0.44958 1.99898) + (layers F.Cu F.Paste F.Mask) + (net 21 /RX) + ) + (pad 29 smd rect (at -0.42672 -4.826 315) (size 0.44958 1.99898) + (layers F.Cu F.Paste F.Mask) + (net 20 /RESET) + ) + (pad 28 smd rect (at 0.37592 -4.826 315) (size 0.44958 1.99898) + (layers F.Cu F.Paste F.Mask) + (net 9 /CYRF_RST) + ) + (pad 27 smd rect (at 1.17348 -4.826 315) (size 0.44958 1.99898) + (layers F.Cu F.Paste F.Mask) + ) + (pad 26 smd rect (at 1.97612 -4.826 315) (size 0.44958 1.99898) + (layers F.Cu F.Paste F.Mask) + ) + (pad 25 smd rect (at 2.77368 -4.826 315) (size 0.44958 1.99898) + (layers F.Cu F.Paste F.Mask) + ) + (pad 9 smd rect (at -2.8194 4.7752 315) (size 0.44958 1.99898) + (layers F.Cu F.Paste F.Mask) + (net 15 /MOSI) + ) + (pad 10 smd rect (at -2.032 4.7752 315) (size 0.44958 1.99898) + (layers F.Cu F.Paste F.Mask) + (net 14 /MISO) + ) + (pad 11 smd rect (at -1.2192 4.7752 315) (size 0.44958 1.99898) + (layers F.Cu F.Paste F.Mask) + (net 5 /CC25_CSN) + ) + (pad 12 smd rect (at -0.4318 4.7752 315) (size 0.44958 1.99898) + (layers F.Cu F.Paste F.Mask) + (net 17 /NRF_CSN) + ) + (pad 13 smd rect (at 0.3556 4.7752 315) (size 0.44958 1.99898) + (layers F.Cu F.Paste F.Mask) + (net 8 /CYRF_CSN) + ) + (pad 14 smd rect (at 1.1684 4.7752 315) (size 0.44958 1.99898) + (layers F.Cu F.Paste F.Mask) + (net 10 /D10) + ) + (pad 15 smd rect (at 1.9812 4.7752 315) (size 0.44958 1.99898) + (layers F.Cu F.Paste F.Mask) + (net 11 /D11) + ) + (pad 16 smd rect (at 2.794 4.7752 315) (size 0.44958 1.99898) + (layers F.Cu F.Paste F.Mask) + (net 12 /D12) + ) + (model smd/tqfp32.wrl + (at (xyz 0 0 0)) + (scale (xyz 1 1 1)) + (rotate (xyz 0 0 0)) + ) + ) + + (module SM0603_Resistor (layer F.Cu) (tedit 5485D93F) (tstamp 53C2D5B2) + (at 151.8 61.7 180) + (path /53C2D8C4) + (attr smd) + (fp_text reference R6 (at -2 0.4 180) (layer F.SilkS) + (effects (font (size 0.50038 0.4572) (thickness 0.1143))) + ) + (fp_text value 1K (at -2.1 -0.4 180) (layer F.SilkS) + (effects (font (size 0.508 0.4572) (thickness 0.1143))) + ) + (fp_line (start -0.50038 -0.6985) (end -1.2065 -0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start -1.2065 -0.6985) (end -1.2065 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start -1.2065 0.6985) (end -0.50038 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 -0.6985) (end 0.50038 -0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 -0.6985) (end 1.2065 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 0.6985) (end 0.50038 0.6985) (layer F.SilkS) (width 0.127)) + (pad 1 smd rect (at -0.762 0 180) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 1 +5V) + ) + (pad 2 smd rect (at 0.762 0 180) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 31 N-000002) + ) + (model smd\resistors\R0603.wrl + (at (xyz 0 0 0.001)) + (scale (xyz 0.5 0.5 0.5)) + (rotate (xyz 0 0 0)) + ) + ) + + (module SM0603_Resistor (layer F.Cu) (tedit 5485D8E4) (tstamp 53C2D5BE) + (at 173.8 76.5 180) + (path /53BC5FEA) + (attr smd) + (fp_text reference R1 (at -2.1 0.4 180) (layer F.SilkS) + (effects (font (size 0.50038 0.4572) (thickness 0.1143))) + ) + (fp_text value 10K (at -2.2 -0.4 180) (layer F.SilkS) + (effects (font (size 0.508 0.4572) (thickness 0.1143))) + ) + (fp_line (start -0.50038 -0.6985) (end -1.2065 -0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start -1.2065 -0.6985) (end -1.2065 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start -1.2065 0.6985) (end -0.50038 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 -0.6985) (end 0.50038 -0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 -0.6985) (end 1.2065 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 0.6985) (end 0.50038 0.6985) (layer F.SilkS) (width 0.127)) + (pad 1 smd rect (at -0.762 0 180) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 26 3V3) + ) + (pad 2 smd rect (at 0.762 0 180) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 20 /RESET) + ) + (model smd\resistors\R0603.wrl + (at (xyz 0 0 0.001)) + (scale (xyz 0.5 0.5 0.5)) + (rotate (xyz 0 0 0)) + ) + ) + + (module SM0603_Resistor (layer F.Cu) (tedit 54D5244B) (tstamp 53C2D5CA) + (at 162.687 105.029 90) + (path /53BC6125) + (attr smd) + (fp_text reference R4 (at -2 -0.5 90) (layer F.SilkS) + (effects (font (size 0.50038 0.4572) (thickness 0.1143))) + ) + (fp_text value 1K (at -2 0.4 90) (layer F.SilkS) + (effects (font (size 0.508 0.4572) (thickness 0.1143))) + ) + (fp_line (start -0.50038 -0.6985) (end -1.2065 -0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start -1.2065 -0.6985) (end -1.2065 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start -1.2065 0.6985) (end -0.50038 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 -0.6985) (end 0.50038 -0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 -0.6985) (end 1.2065 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 0.6985) (end 0.50038 0.6985) (layer F.SilkS) (width 0.127)) + (pad 1 smd rect (at -0.762 0 90) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 18 /PB5) + ) + (pad 2 smd rect (at 0.762 0 90) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 37 N-0000034) + ) + (model smd\resistors\R0603.wrl + (at (xyz 0 0 0.001)) + (scale (xyz 0.5 0.5 0.5)) + (rotate (xyz 0 0 0)) + ) + ) + + (module SM0603_Resistor (layer F.Cu) (tedit 548E3A24) (tstamp 53C2D5D6) + (at 177.927 97.663 90) + (path /53C2B99F) + (attr smd) + (fp_text reference R3 (at 2.3 -0.5 90) (layer F.SilkS) + (effects (font (size 0.50038 0.4572) (thickness 0.1143))) + ) + (fp_text value 1K (at 2.4 0.4 90) (layer F.SilkS) + (effects (font (size 0.508 0.4572) (thickness 0.1143))) + ) + (fp_line (start -0.50038 -0.6985) (end -1.2065 -0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start -1.2065 -0.6985) (end -1.2065 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start -1.2065 0.6985) (end -0.50038 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 -0.6985) (end 0.50038 -0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 -0.6985) (end 1.2065 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 0.6985) (end 0.50038 0.6985) (layer F.SilkS) (width 0.127)) + (pad 1 smd rect (at -0.762 0 90) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 35 N-0000023) + ) + (pad 2 smd rect (at 0.762 0 90) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 27 GND) + ) + (model smd\resistors\R0603.wrl + (at (xyz 0 0 0.001)) + (scale (xyz 0.5 0.5 0.5)) + (rotate (xyz 0 0 0)) + ) + ) + + (module SM0603_Resistor (layer F.Cu) (tedit 548B2438) (tstamp 53C2D5E2) + (at 175.768 97.663 270) + (path /53C2B990) + (attr smd) + (fp_text reference R2 (at -2.7 0 360) (layer F.SilkS) + (effects (font (size 0.50038 0.4572) (thickness 0.1143))) + ) + (fp_text value 2K2 (at -1.8 0 360) (layer F.SilkS) + (effects (font (size 0.508 0.4572) (thickness 0.1143))) + ) + (fp_line (start -0.50038 -0.6985) (end -1.2065 -0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start -1.2065 -0.6985) (end -1.2065 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start -1.2065 0.6985) (end -0.50038 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 -0.6985) (end 0.50038 -0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 -0.6985) (end 1.2065 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 0.6985) (end 0.50038 0.6985) (layer F.SilkS) (width 0.127)) + (pad 1 smd rect (at -0.762 0 270) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 13 /D3) + ) + (pad 2 smd rect (at 0.762 0 270) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 19 /PPM_IN) + ) + (model smd\resistors\R0603.wrl + (at (xyz 0 0 0.001)) + (scale (xyz 0.5 0.5 0.5)) + (rotate (xyz 0 0 0)) + ) + ) + + (module SM0603_Resistor (layer F.Cu) (tedit 5485D8C6) (tstamp 53C2D5EE) + (at 173.8 74.5) + (path /53C2B787) + (attr smd) + (fp_text reference R5 (at 2 -0.3) (layer F.SilkS) + (effects (font (size 0.50038 0.4572) (thickness 0.1143))) + ) + (fp_text value 2K2 (at 2.1 0.5) (layer F.SilkS) + (effects (font (size 0.508 0.4572) (thickness 0.1143))) + ) + (fp_line (start -0.50038 -0.6985) (end -1.2065 -0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start -1.2065 -0.6985) (end -1.2065 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start -1.2065 0.6985) (end -0.50038 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 -0.6985) (end 0.50038 -0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 -0.6985) (end 1.2065 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 0.6985) (end 0.50038 0.6985) (layer F.SilkS) (width 0.127)) + (pad 1 smd rect (at -0.762 0) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 16 /NRF_CE) + ) + (pad 2 smd rect (at 0.762 0) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 26 3V3) + ) + (model smd\resistors\R0603.wrl + (at (xyz 0 0 0.001)) + (scale (xyz 0.5 0.5 0.5)) + (rotate (xyz 0 0 0)) + ) + ) + + (module pin_array_3x2 (layer F.Cu) (tedit 54BD6662) (tstamp 5489FDE0) + (at 175.4 62.1 180) + (descr "Double rangee de contacts 2 x 4 pins") + (tags CONN) + (path /53C2DBCC) + (fp_text reference P1 (at -2.1 -3.6 180) (layer F.SilkS) + (effects (font (size 1.016 1.016) (thickness 0.2032))) + ) + (fp_text value ISP (at 4.7 0.1 270) (layer F.SilkS) + (effects (font (size 1.016 1.016) (thickness 0.2032))) + ) + (fp_line (start 3.81 2.54) (end -3.81 2.54) (layer F.SilkS) (width 0.2032)) + (fp_line (start -3.81 -2.54) (end 3.81 -2.54) (layer F.SilkS) (width 0.2032)) + (fp_line (start 3.81 -2.54) (end 3.81 2.54) (layer F.SilkS) (width 0.2032)) + (fp_line (start -3.81 2.54) (end -3.81 -2.54) (layer F.SilkS) (width 0.2032)) + (pad 1 thru_hole rect (at -2.54 1.27 180) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 12 /D12) + ) + (pad 2 thru_hole circle (at -2.54 -1.27 180) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 26 3V3) + ) + (pad 3 thru_hole circle (at 0 1.27 180) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 18 /PB5) + ) + (pad 4 thru_hole circle (at 0 -1.27 180) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 11 /D11) + ) + (pad 5 thru_hole circle (at 2.54 1.27 180) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 20 /RESET) + ) + (pad 6 thru_hole circle (at 2.54 -1.27 180) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 27 GND) + ) + (model pin_array/pins_array_3x2.wrl + (at (xyz 0 0 0)) + (scale (xyz 1 1 1)) + (rotate (xyz 0 0 0)) + ) + ) + + (module header_10_2mm (layer F.Cu) (tedit 548371C5) (tstamp 53C4106C) + (at 164.2 66.9 180) + (path /53C2C3F4) + (fp_text reference U6 (at 9.7 -2.1 180) (layer F.SilkS) + (effects (font (size 1 1) (thickness 0.15))) + ) + (fp_text value CC2500 (at 5.2 -2.1 180) (layer F.SilkS) + (effects (font (size 1 1) (thickness 0.15))) + ) + (pad 5 thru_hole circle (at -1 0 180) (size 1.5 1.5) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 6 /CC25_LANEN) + ) + (pad 4 thru_hole circle (at -3 0 180) (size 1.5 1.5) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 14 /MISO) + ) + (pad 3 thru_hole circle (at -5 0 180) (size 1.5 1.5) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 22 /SCK) + ) + (pad 2 thru_hole circle (at -7 0 180) (size 1.5 1.5) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 15 /MOSI) + ) + (pad 1 thru_hole rect (at -9 0 180) (size 1.5 1.5) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 26 3V3) + ) + (pad 6 thru_hole circle (at 1 0 180) (size 1.5 1.5) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 27 GND) + ) + (pad 7 thru_hole circle (at 3 0 180) (size 1.5 1.5) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 7 /CC25_PAEN) + ) + (pad 8 thru_hole circle (at 5 0 180) (size 1.5 1.5) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 5 /CC25_CSN) + ) + (pad 9 thru_hole circle (at 7 0 180) (size 1.5 1.5) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 7 /CC25_PAEN) + ) + (pad 10 thru_hole circle (at 9 0 180) (size 1.5 1.5) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 6 /CC25_LANEN) + ) + ) + + (module crystal_FA238-TSX3225 (layer F.Cu) (tedit 54BD4DE8) (tstamp 53C41078) + (at 158.1 80.9 45) + (descr "crystal Epson Toyocom FA-238 and TSX-3225 series") + (path /53BC62D3) + (fp_text reference X1 (at -1.131371 2.687006 135) (layer F.SilkS) + (effects (font (size 0.8 0.8) (thickness 0.15))) + ) + (fp_text value 16MHz (at 3.11127 -3.11127 135) (layer F.SilkS) + (effects (font (size 0.8 0.8) (thickness 0.15))) + ) + (fp_line (start -1.6 -1.3) (end 1.6 -1.3) (layer F.SilkS) (width 0.15)) + (fp_line (start 1.6 -1.3) (end 1.6 1.3) (layer F.SilkS) (width 0.15)) + (fp_line (start 1.6 1.3) (end -1.6 1.3) (layer F.SilkS) (width 0.15)) + (fp_line (start -1.6 1.3) (end -1.6 -1.3) (layer F.SilkS) (width 0.15)) + (pad 1 smd rect (at -1.1 0.8 45) (size 1.4 1.2) + (layers F.Cu F.Paste F.Mask) + (net 25 /xtl2) + ) + (pad 2 smd rect (at 1.1 0.8 45) (size 1.4 1.2) + (layers F.Cu F.Paste F.Mask) + (net 27 GND) + ) + (pad 4 smd rect (at -1.1 -0.8 45) (size 1.4 1.2) + (layers F.Cu F.Paste F.Mask) + (net 27 GND) + ) + (pad 3 smd rect (at 1.1 -0.8 45) (size 1.4 1.2) + (layers F.Cu F.Paste F.Mask) + (net 24 /xtl1) + ) + (model smd/smd_crystal&oscillator/crystal_4pins_smd.wrl + (at (xyz 0 0 0)) + (scale (xyz 0.24 0.24 0.24)) + (rotate (xyz 0 0 0)) + ) + ) + + (module c_tant_B (layer F.Cu) (tedit 5495C078) (tstamp 53C2D65C) + (at 168 101.5) + (descr "SMT capacitor, tantalum size B") + (path /53C2AE5B) + (fp_text reference C1 (at 3.65 0) (layer F.SilkS) + (effects (font (size 1 1) (thickness 0.2))) + ) + (fp_text value 22uF (at 0 1.9685) (layer F.SilkS) hide + (effects (font (size 0.50038 0.50038) (thickness 0.11938))) + ) + (fp_line (start 1.2065 -1.397) (end 1.2065 1.397) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.778 -1.397) (end -1.778 -1.397) (layer F.SilkS) (width 0.127)) + (fp_line (start -1.778 -1.397) (end -1.778 1.397) (layer F.SilkS) (width 0.127)) + (fp_line (start -1.778 1.397) (end 1.778 1.397) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.778 1.397) (end 1.778 -1.397) (layer F.SilkS) (width 0.127)) + (pad 1 smd rect (at 1.524 0) (size 1.95072 2.49936) + (layers F.Cu F.Paste F.Mask) + (net 4 /BATT) + ) + (pad 2 smd rect (at -1.524 0) (size 1.95072 2.49936) + (layers F.Cu F.Paste F.Mask) + (net 27 GND) + ) + (model smd/capacitors/c_tant_B.wrl + (at (xyz 0 0 0)) + (scale (xyz 1 1 1)) + (rotate (xyz 0 0 0)) + ) + ) + + (module c_tant_B (layer F.Cu) (tedit 548B25A1) (tstamp 54A2CEA9) + (at 149 101.5) + (descr "SMT capacitor, tantalum size B") + (path /53C2B150) + (fp_text reference C6 (at -1.5 -2.5) (layer F.SilkS) + (effects (font (size 1 1) (thickness 0.2))) + ) + (fp_text value 22uF (at 0 1.9685) (layer F.SilkS) hide + (effects (font (size 0.50038 0.50038) (thickness 0.11938))) + ) + (fp_line (start 1.2065 -1.397) (end 1.2065 1.397) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.778 -1.397) (end -1.778 -1.397) (layer F.SilkS) (width 0.127)) + (fp_line (start -1.778 -1.397) (end -1.778 1.397) (layer F.SilkS) (width 0.127)) + (fp_line (start -1.778 1.397) (end 1.778 1.397) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.778 1.397) (end 1.778 -1.397) (layer F.SilkS) (width 0.127)) + (pad 1 smd rect (at 1.524 0) (size 1.95072 2.49936) + (layers F.Cu F.Paste F.Mask) + (net 26 3V3) + ) + (pad 2 smd rect (at -1.524 0) (size 1.95072 2.49936) + (layers F.Cu F.Paste F.Mask) + (net 27 GND) + ) + (model smd/capacitors/c_tant_B.wrl + (at (xyz 0 0 0)) + (scale (xyz 1 1 1)) + (rotate (xyz 0 0 0)) + ) + ) + + (module Hole_4mm (layer F.Cu) (tedit 56B4BA4A) (tstamp 547F85C2) + (at 160.782 77.216) + (fp_text reference Hole_4mm (at -8.7 37.75) (layer F.SilkS) hide + (effects (font (size 1 1) (thickness 0.15))) + ) + (fp_text value "" (at -0.01 6.4) (layer F.SilkS) + (effects (font (size 1 1) (thickness 0.15))) + ) + (pad "" np_thru_hole circle (at -3.6 35.2) (size 4 4) (drill 4) + (layers *.Cu *.Mask F.SilkS) + ) + ) + + (module Switch_SMT5mm (layer F.Cu) (tedit 54D4438A) (tstamp 547F53D1) + (at 146.6 66.5) + (path /56B4EC7B) + (fp_text reference SW3 (at -2.8 4) (layer F.SilkS) + (effects (font (size 1 1) (thickness 0.15))) + ) + (fp_text value RESET (at 1.5 4) (layer F.SilkS) + (effects (font (size 1 1) (thickness 0.2))) + ) + (pad 1 smd rect (at -3.1 -1.85) (size 1.8 1.1) + (layers F.Cu F.Paste F.Mask) + (net 20 /RESET) + ) + (pad 2 smd rect (at 3.1 -1.85) (size 1.8 1.1) + (layers F.Cu F.Paste F.Mask) + (net 20 /RESET) + ) + (pad 3 smd rect (at -3.1 1.85) (size 1.8 1.1) + (layers F.Cu F.Paste F.Mask) + (net 27 GND) + ) + (pad 4 smd rect (at 3.1 1.85) (size 1.8 1.1) + (layers F.Cu F.Paste F.Mask) + (net 27 GND) + ) + ) + + (module NRF24L01 (layer F.Cu) (tedit 5488B26F) (tstamp 547F85B0) + (at 170.6 71.1) + (descr "Double rangee de contacts 2 x 4 pins") + (tags CONN) + (path /53C2C24E) + (fp_text reference U5 (at 6.9 -1.1 90) (layer F.SilkS) + (effects (font (size 1.016 1.016) (thickness 0.2032))) + ) + (fp_text value NRF24L01 (at 7.4 5.7 90) (layer F.SilkS) + (effects (font (size 1.016 1.016) (thickness 0.2032))) + ) + (fp_line (start -7.5 -2.54) (end 8.5 -2.54) (layer F.SilkS) (width 0.3048)) + (fp_line (start 8.5 -2.54) (end 8.5 29.54) (layer F.SilkS) (width 0.3048)) + (fp_line (start 8.5 29.54) (end -7.5 29.54) (layer F.SilkS) (width 0.3048)) + (fp_line (start -7.5 -2.54) (end -7.5 29.54) (layer F.SilkS) (width 0.3048)) + (pad 1 thru_hole rect (at 3.76682 -1.20904 180) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 27 GND) + ) + (pad 2 thru_hole circle (at 3.76682 1.33096 180) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 26 3V3) + ) + (pad 3 thru_hole circle (at 1.22682 -1.20904 180) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 16 /NRF_CE) + ) + (pad 4 thru_hole circle (at 1.22682 1.33096 180) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 17 /NRF_CSN) + ) + (pad 5 thru_hole circle (at -1.31318 -1.20904 180) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 22 /SCK) + ) + (pad 6 thru_hole circle (at -1.31318 1.33096 180) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 15 /MOSI) + ) + (pad 7 thru_hole circle (at -3.85318 -1.20904 180) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 14 /MISO) + ) + (pad 8 thru_hole circle (at -3.85318 1.33096 180) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + ) + (model pin_array/pins_array_4x2.wrl + (at (xyz 0 0 0)) + (scale (xyz 1 1 1)) + (rotate (xyz 0 0 0)) + ) + ) + + (module CYRF6936 (layer F.Cu) (tedit 548B2075) (tstamp 547F7A40) + (at 160 62.3) + (path /53C2BF57) + (fp_text reference U3 (at -4 2.7) (layer F.SilkS) + (effects (font (size 1 1) (thickness 0.15))) + ) + (fp_text value CYRF6936 (at 1.3 2.7) (layer F.SilkS) + (effects (font (size 1 1) (thickness 0.15))) + ) + (pad 5 thru_hole circle (at 0 -1) (size 1.5 1.5) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 27 GND) + ) + (pad 4 thru_hole circle (at -2 1) (size 1.5 1.5) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 22 /SCK) + ) + (pad 3 thru_hole circle (at -2 -1) (size 1.5 1.5) (drill 1) + (layers *.Cu *.Mask F.SilkS) + ) + (pad 2 thru_hole circle (at -4 1) (size 1.5 1.5) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 8 /CYRF_CSN) + ) + (pad 1 thru_hole rect (at -4 -1) (size 1.5 1.5) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 1 +5V) + ) + (pad 6 thru_hole circle (at 0 1) (size 1.5 1.5) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 27 GND) + ) + (pad 7 thru_hole circle (at 2 -1) (size 1.5 1.5) (drill 1) + (layers *.Cu *.Mask F.SilkS) + ) + (pad 8 thru_hole circle (at 2 1) (size 1.5 1.5) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 15 /MOSI) + ) + (pad 9 thru_hole circle (at 4 -1) (size 1.5 1.5) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 9 /CYRF_RST) + ) + (pad 10 thru_hole circle (at 4 1) (size 1.5 1.5) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 14 /MISO) + ) + ) + + (module LED-0603 (layer F.Cu) (tedit 54D4435F) (tstamp 53C2D650) + (at 147.4 61.7 180) + (descr "LED 0603 smd package") + (tags "LED led 0603 SMD smd SMT smt smdled SMDLED smtled SMTLED") + (path /53C2D9F8) + (attr smd) + (fp_text reference D2 (at 0 -1.2 180) (layer F.SilkS) + (effects (font (size 0.508 0.508) (thickness 0.127))) + ) + (fp_text value LED (at 0 1.016 180) (layer F.SilkS) + (effects (font (size 0.508 0.508) (thickness 0.127))) + ) + (fp_line (start 0.44958 -0.44958) (end 0.44958 0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0.44958 0.44958) (end 0.84836 0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0.84836 -0.44958) (end 0.84836 0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0.44958 -0.44958) (end 0.84836 -0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start -0.84836 -0.44958) (end -0.84836 0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start -0.84836 0.44958) (end -0.44958 0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start -0.44958 -0.44958) (end -0.44958 0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start -0.84836 -0.44958) (end -0.44958 -0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0 -0.44958) (end 0 -0.29972) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0 -0.29972) (end 0.29972 -0.29972) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0.29972 -0.44958) (end 0.29972 -0.29972) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0 -0.44958) (end 0.29972 -0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0 0.29972) (end 0 0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0 0.44958) (end 0.29972 0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0.29972 0.29972) (end 0.29972 0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0 0.29972) (end 0.29972 0.29972) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0 -0.14986) (end 0 0.14986) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0 0.14986) (end 0.29972 0.14986) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0.29972 -0.14986) (end 0.29972 0.14986) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0 -0.14986) (end 0.29972 -0.14986) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0.44958 -0.39878) (end -0.44958 -0.39878) (layer F.SilkS) (width 0.1016)) + (fp_line (start 0.44958 0.39878) (end -0.44958 0.39878) (layer F.SilkS) (width 0.1016)) + (pad 1 smd rect (at -0.7493 0 180) (size 0.79756 0.79756) + (layers F.Cu F.Paste F.Mask) + (net 31 N-000002) + ) + (pad 2 smd rect (at 0.7493 0 180) (size 0.79756 0.79756) + (layers F.Cu F.Paste F.Mask) + (net 27 GND) + ) + ) + + (module LED-0603 locked (layer F.Cu) (tedit 54D4432E) (tstamp 53C2D626) + (at 168 104.3) + (descr "LED 0603 smd package") + (tags "LED led 0603 SMD smd SMT smt smdled SMDLED smtled SMTLED") + (path /53BC617C) + (attr smd) + (fp_text reference D1 (at 0 -1.016) (layer F.SilkS) + (effects (font (size 0.508 0.508) (thickness 0.127))) + ) + (fp_text value LED (at 0 1.016) (layer F.SilkS) + (effects (font (size 0.508 0.508) (thickness 0.127))) + ) + (fp_line (start 0.44958 -0.44958) (end 0.44958 0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0.44958 0.44958) (end 0.84836 0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0.84836 -0.44958) (end 0.84836 0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0.44958 -0.44958) (end 0.84836 -0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start -0.84836 -0.44958) (end -0.84836 0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start -0.84836 0.44958) (end -0.44958 0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start -0.44958 -0.44958) (end -0.44958 0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start -0.84836 -0.44958) (end -0.44958 -0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0 -0.44958) (end 0 -0.29972) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0 -0.29972) (end 0.29972 -0.29972) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0.29972 -0.44958) (end 0.29972 -0.29972) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0 -0.44958) (end 0.29972 -0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0 0.29972) (end 0 0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0 0.44958) (end 0.29972 0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0.29972 0.29972) (end 0.29972 0.44958) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0 0.29972) (end 0.29972 0.29972) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0 -0.14986) (end 0 0.14986) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0 0.14986) (end 0.29972 0.14986) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0.29972 -0.14986) (end 0.29972 0.14986) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0 -0.14986) (end 0.29972 -0.14986) (layer F.SilkS) (width 0.06604)) + (fp_line (start 0.44958 -0.39878) (end -0.44958 -0.39878) (layer F.SilkS) (width 0.1016)) + (fp_line (start 0.44958 0.39878) (end -0.44958 0.39878) (layer F.SilkS) (width 0.1016)) + (pad 1 smd rect (at -0.7493 0) (size 0.79756 0.79756) + (layers F.Cu F.Paste F.Mask) + (net 37 N-0000034) + ) + (pad 2 smd rect (at 0.7493 0) (size 0.79756 0.79756) + (layers F.Cu F.Paste F.Mask) + (net 27 GND) + ) + ) + + (module LOGO (layer B.Cu) (tedit 54A2CE43) (tstamp 54A2CE24) + (at 176.276 78.486 90) + (fp_text reference "" (at 0 -3.89382 90) (layer B.SilkS) hide + (effects (font (size 1.524 1.524) (thickness 0.3048)) (justify mirror)) + ) + (fp_text value "" (at 0 3.89382 90) (layer B.SilkS) hide + (effects (font (size 1.524 1.524) (thickness 0.3048)) (justify mirror)) + ) + (fp_poly (pts (xy 2.34188 1.143) (xy 2.28854 1.32842) (xy 2.17678 1.64084) (xy 2.17424 1.64338) + (xy 1.98882 2.1463) (xy 0.80518 2.39522) (xy 0.80518 2.11582) (xy 0.80518 1.69418) + (xy 0.80518 1.27) (xy 0.50292 1.27) (xy 0.20828 1.31572) (xy 0.04572 1.45796) + (xy 0 1.69418) (xy 0.05334 1.94056) (xy 0.22352 2.07772) (xy 0.50292 2.11582) + (xy 0.80518 2.11582) (xy 0.80518 2.39522) (xy 0.67818 2.42316) (xy 0.22352 2.51714) + (xy -0.1778 2.59842) (xy -0.42418 2.64668) (xy -0.42418 1.97866) (xy -0.44704 1.88976) + (xy -0.53848 1.93802) (xy -0.54864 1.94564) (xy -0.70358 2.0066) (xy -0.85598 1.97866) + (xy -0.93218 1.88214) (xy -0.93218 1.87452) (xy -0.86106 1.79832) (xy -0.71628 1.74244) + (xy -0.508 1.6383) (xy -0.43942 1.50114) (xy -0.50546 1.36906) (xy -0.69342 1.2827) + (xy -0.8255 1.27) (xy -0.98044 1.31826) (xy -1.01092 1.41732) (xy -0.98806 1.4986) + (xy -0.96012 1.4605) (xy -0.8636 1.37922) (xy -0.72136 1.35636) (xy -0.6096 1.397) + (xy -0.59182 1.44272) (xy -0.66548 1.52908) (xy -0.8382 1.61798) (xy -0.84582 1.62052) + (xy -1.02616 1.73228) (xy -1.1049 1.88214) (xy -1.06426 2.01422) (xy -0.99568 2.05994) + (xy -0.76962 2.11074) (xy -0.56388 2.09804) (xy -0.43942 2.02692) (xy -0.42418 1.97866) + (xy -0.42418 2.64668) (xy -0.49022 2.66192) (xy -0.6858 2.69748) (xy -0.73406 2.7051) + (xy -0.82296 2.64668) (xy -1.00076 2.48158) (xy -1.23698 2.23774) (xy -1.51384 1.93802) + (xy -1.5621 1.88468) (xy -2.29362 1.05918) (xy -1.90246 1.03124) (xy -1.67132 1.00838) + (xy -1.57988 0.97028) (xy -1.6002 0.89916) (xy -1.6129 0.88392) (xy -1.65354 0.78486) + (xy -1.63068 0.635) (xy -1.53416 0.39878) (xy -1.44526 0.20828) (xy -1.30302 -0.0508) + (xy -1.1811 -0.23114) (xy -1.10236 -0.29464) (xy -1.09474 -0.2921) (xy -1.04648 -0.18288) + (xy -1.02108 0.04064) (xy -1.01854 0.32004) (xy -1.03632 0.5969) (xy -1.07442 0.81534) + (xy -1.1176 0.9144) (xy -1.12268 0.95504) (xy -1.03124 0.98298) (xy -0.82296 1.0033) + (xy -0.4826 1.01346) (xy 0 1.016) (xy 0.49022 1.01346) (xy 0.82804 1.0033) + (xy 1.03378 0.98298) (xy 1.12268 0.95504) (xy 1.1176 0.9144) (xy 1.03124 0.72898) + (xy 1.0795 0.51816) (xy 1.24206 0.32004) (xy 1.49606 0.16764) (xy 1.62814 0.12446) + (xy 1.80594 0.10668) (xy 1.905 0.20066) (xy 1.94564 0.2921) (xy 2.0193 0.57658) + (xy 2.0193 0.8128) (xy 1.9431 0.94996) (xy 1.92532 0.96012) (xy 1.92532 0.9906) + (xy 2.05994 1.00838) (xy 2.0955 1.00838) (xy 2.25044 1.016) (xy 2.33172 1.04902) + (xy 2.34188 1.143) (xy 2.34188 1.143)) (layer B.SilkS) (width 0.00254)) + (fp_poly (pts (xy 2.9083 -0.59436) (xy 2.71018 0.04064) (xy 2.60858 0.34036) (xy 2.51968 0.56134) + (xy 2.46126 0.6731) (xy 2.4511 0.67818) (xy 2.39268 0.60198) (xy 2.30378 0.40132) + (xy 2.19456 0.1143) (xy 2.07772 -0.21844) (xy 1.9685 -0.56388) (xy 1.87706 -0.87884) + (xy 1.81864 -1.12776) (xy 1.8034 -1.27) (xy 1.8034 -1.27762) (xy 1.81102 -1.36398) + (xy 1.75514 -1.41224) (xy 1.60274 -1.4351) (xy 1.31826 -1.44018) (xy 1.27 -1.44018) + (xy 0.9652 -1.4351) (xy 0.79756 -1.41732) (xy 0.73152 -1.3716) (xy 0.73152 -1.29032) + (xy 0.7366 -1.27508) (xy 0.72898 -1.12776) (xy 0.6731 -0.8636) (xy 0.58166 -0.52578) + (xy 0.50546 -0.2794) (xy 0.32766 0.23622) (xy 0.18034 0.59944) (xy 0.05588 0.82296) + (xy -0.05588 0.92202) (xy -0.16002 0.90678) (xy -0.19812 0.87376) (xy -0.23114 0.75946) + (xy -0.24892 0.51562) (xy -0.25908 0.18542) (xy -0.25654 -0.1905) (xy -0.24384 -0.5715) + (xy -0.22352 -0.9144) (xy -0.19558 -1.17856) (xy -0.16002 -1.32588) (xy -0.1524 -1.33858) + (xy -0.13462 -1.39192) (xy -0.2286 -1.42494) (xy -0.45974 -1.43764) (xy -0.635 -1.44018) + (xy -0.94234 -1.43256) (xy -1.1049 -1.41224) (xy -1.14046 -1.36906) (xy -1.1176 -1.33858) + (xy -1.05156 -1.1938) (xy -1.01854 -0.96012) (xy -1.016 -0.89916) (xy -1.016 -0.5588) + (xy -1.31318 -0.84582) (xy -1.53162 -1.0922) (xy -1.60274 -1.26238) (xy -1.53162 -1.36906) + (xy -1.50368 -1.3843) (xy -1.50622 -1.41224) (xy -1.64338 -1.43002) (xy -1.70942 -1.43256) + (xy -2.02438 -1.44018) (xy -1.91516 -1.7526) (xy -1.8161 -1.97104) (xy -1.70688 -2.11582) + (xy -1.68656 -2.12852) (xy -1.56972 -2.16662) (xy -1.32842 -2.22758) (xy -0.99568 -2.30124) + (xy -0.60706 -2.3876) (xy -0.19558 -2.47396) (xy 0.20828 -2.5527) (xy 0.56642 -2.62382) + (xy 0.84582 -2.67208) (xy 1.016 -2.69748) (xy 1.04902 -2.69494) (xy 1.1303 -2.59588) + (xy 1.29032 -2.41046) (xy 1.50622 -2.16916) (xy 1.74752 -1.89992) (xy 1.99136 -1.63322) + (xy 2.2098 -1.397) (xy 2.3749 -1.22174) (xy 2.46126 -1.13538) (xy 2.46888 -1.1303) + (xy 2.47396 -1.10744) (xy 2.51206 -1.0287) (xy 2.63652 -0.88138) (xy 2.6797 -0.83312) + (xy 2.9083 -0.59436) (xy 2.9083 -0.59436)) (layer B.SilkS) (width 0.00254)) + (fp_poly (pts (xy -1.61036 -0.8382) (xy -1.78816 -0.65278) (xy -2.01422 -0.34036) (xy -2.23012 0.08128) + (xy -2.36728 0.4445) (xy -2.45618 0.67564) (xy -2.53746 0.74676) (xy -2.63398 0.6731) + (xy -2.69494 0.5842) (xy -2.75844 0.46228) (xy -2.71526 0.46228) (xy -2.70256 0.4699) + (xy -2.63398 0.47498) (xy -2.64668 0.35052) (xy -2.6543 0.22352) (xy -2.6035 0.22352) + (xy -2.54762 0.21082) (xy -2.56032 0.09652) (xy -2.57048 -0.03048) (xy -2.51968 -0.03048) + (xy -2.4638 -0.04318) (xy -2.4765 -0.15748) (xy -2.49174 -0.28194) (xy -2.46126 -0.29972) + (xy -2.40538 -0.35306) (xy -2.3241 -0.52578) (xy -2.25298 -0.72644) (xy -2.1082 -1.19126) + (xy -1.85928 -1.01346) (xy -1.61036 -0.8382) (xy -1.61036 -0.8382)) (layer B.SilkS) (width 0.00254)) + (fp_poly (pts (xy 1.74244 -0.18034) (xy 1.71196 -0.16764) (xy 1.59004 -0.14732) (xy 1.4605 -0.11684) + (xy 1.31318 -0.0889) (xy 1.27 -0.09652) (xy 1.2954 -0.18796) (xy 1.35128 -0.38608) + (xy 1.38938 -0.508) (xy 1.50622 -0.889) (xy 1.60274 -0.635) (xy 1.69926 -0.37592) + (xy 1.74244 -0.23622) (xy 1.74244 -0.18034) (xy 1.74244 -0.18034)) (layer B.SilkS) (width 0.00254)) + (fp_poly (pts (xy 0.59182 1.68656) (xy 0.5588 1.93548) (xy 0.46736 2.03708) (xy 0.32766 1.9812) + (xy 0.25654 1.91008) (xy 0.1778 1.7145) (xy 0.21082 1.51892) (xy 0.33782 1.38684) + (xy 0.40132 1.36906) (xy 0.52324 1.3716) (xy 0.57912 1.45034) (xy 0.59182 1.64846) + (xy 0.59182 1.68656) (xy 0.59182 1.68656)) (layer B.SilkS) (width 0.00254)) + ) + + (module SM0603_Resistor (layer F.Cu) (tedit 5051B21B) (tstamp 56B4B6A1) + (at 165.862 110.744) + (path /54DCE006) + (attr smd) + (fp_text reference R7 (at 0.0635 -0.0635 90) (layer F.SilkS) + (effects (font (size 0.50038 0.4572) (thickness 0.1143))) + ) + (fp_text value 2K2 (at -1.69926 0 90) (layer F.SilkS) + (effects (font (size 0.508 0.4572) (thickness 0.1143))) + ) + (fp_line (start -0.50038 -0.6985) (end -1.2065 -0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start -1.2065 -0.6985) (end -1.2065 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start -1.2065 0.6985) (end -0.50038 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 -0.6985) (end 0.50038 -0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 -0.6985) (end 1.2065 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 0.6985) (end 0.50038 0.6985) (layer F.SilkS) (width 0.127)) + (pad 1 smd rect (at -0.762 0) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 34 N-0000022) + ) + (pad 2 smd rect (at 0.762 0) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 21 /RX) + ) + (model smd\resistors\R0603.wrl + (at (xyz 0 0 0.001)) + (scale (xyz 0.5 0.5 0.5)) + (rotate (xyz 0 0 0)) + ) + ) + + (module SM0603_Capa (layer F.Cu) (tedit 5051B1EC) (tstamp 548465A7) + (at 162.306 78.994 45) + (path /54845FE2) + (attr smd) + (fp_text reference C7 (at 0 0 135) (layer F.SilkS) + (effects (font (size 0.508 0.4572) (thickness 0.1143))) + ) + (fp_text value 0.1uF (at -1.651 0 135) (layer F.SilkS) + (effects (font (size 0.508 0.4572) (thickness 0.1143))) + ) + (fp_line (start 0.50038 0.65024) (end 1.19888 0.65024) (layer F.SilkS) (width 0.11938)) + (fp_line (start -0.50038 0.65024) (end -1.19888 0.65024) (layer F.SilkS) (width 0.11938)) + (fp_line (start 0.50038 -0.65024) (end 1.19888 -0.65024) (layer F.SilkS) (width 0.11938)) + (fp_line (start -1.19888 -0.65024) (end -0.50038 -0.65024) (layer F.SilkS) (width 0.11938)) + (fp_line (start 1.19888 -0.635) (end 1.19888 0.635) (layer F.SilkS) (width 0.11938)) + (fp_line (start -1.19888 0.635) (end -1.19888 -0.635) (layer F.SilkS) (width 0.11938)) + (pad 1 smd rect (at -0.762 0 45) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 26 3V3) + ) + (pad 2 smd rect (at 0.762 0 45) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 27 GND) + ) + (model smd\capacitors\C0603.wrl + (at (xyz 0 0 0.001)) + (scale (xyz 0.5 0.5 0.5)) + (rotate (xyz 0 0 0)) + ) + ) + + (module SM0603_Capa (layer F.Cu) (tedit 5051B1EC) (tstamp 53C2D698) + (at 172.466 91.059) + (path /53BC5DA8) + (attr smd) + (fp_text reference C2 (at 0 0 90) (layer F.SilkS) + (effects (font (size 0.508 0.4572) (thickness 0.1143))) + ) + (fp_text value 0.1uF (at -1.651 0 90) (layer F.SilkS) + (effects (font (size 0.508 0.4572) (thickness 0.1143))) + ) + (fp_line (start 0.50038 0.65024) (end 1.19888 0.65024) (layer F.SilkS) (width 0.11938)) + (fp_line (start -0.50038 0.65024) (end -1.19888 0.65024) (layer F.SilkS) (width 0.11938)) + (fp_line (start 0.50038 -0.65024) (end 1.19888 -0.65024) (layer F.SilkS) (width 0.11938)) + (fp_line (start -1.19888 -0.65024) (end -0.50038 -0.65024) (layer F.SilkS) (width 0.11938)) + (fp_line (start 1.19888 -0.635) (end 1.19888 0.635) (layer F.SilkS) (width 0.11938)) + (fp_line (start -1.19888 0.635) (end -1.19888 -0.635) (layer F.SilkS) (width 0.11938)) + (pad 1 smd rect (at -0.762 0) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 38 N-0000043) + ) + (pad 2 smd rect (at 0.762 0) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 27 GND) + ) + (model smd\capacitors\C0603.wrl + (at (xyz 0 0 0.001)) + (scale (xyz 0.5 0.5 0.5)) + (rotate (xyz 0 0 0)) + ) + ) + + (module SM0603_Capa (layer F.Cu) (tedit 5051B1EC) (tstamp 54BBD549) + (at 156.464 78.74 45) + (path /53BC62F4) + (attr smd) + (fp_text reference C4 (at 0 0 135) (layer F.SilkS) + (effects (font (size 0.508 0.4572) (thickness 0.1143))) + ) + (fp_text value 18pF (at -1.651 0 135) (layer F.SilkS) + (effects (font (size 0.508 0.4572) (thickness 0.1143))) + ) + (fp_line (start 0.50038 0.65024) (end 1.19888 0.65024) (layer F.SilkS) (width 0.11938)) + (fp_line (start -0.50038 0.65024) (end -1.19888 0.65024) (layer F.SilkS) (width 0.11938)) + (fp_line (start 0.50038 -0.65024) (end 1.19888 -0.65024) (layer F.SilkS) (width 0.11938)) + (fp_line (start -1.19888 -0.65024) (end -0.50038 -0.65024) (layer F.SilkS) (width 0.11938)) + (fp_line (start 1.19888 -0.635) (end 1.19888 0.635) (layer F.SilkS) (width 0.11938)) + (fp_line (start -1.19888 0.635) (end -1.19888 -0.635) (layer F.SilkS) (width 0.11938)) + (pad 1 smd rect (at -0.762 0 45) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 27 GND) + ) + (pad 2 smd rect (at 0.762 0 45) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 24 /xtl1) + ) + (model smd\capacitors\C0603.wrl + (at (xyz 0 0 0.001)) + (scale (xyz 0.5 0.5 0.5)) + (rotate (xyz 0 0 0)) + ) + ) + + (module SM0603_Capa (layer F.Cu) (tedit 56B50213) (tstamp 53C2D680) + (at 155.956 83.058 135) + (path /53BC631E) + (attr smd) + (fp_text reference C5 (at 0 0 225) (layer F.SilkS) + (effects (font (size 0.508 0.4572) (thickness 0.1143))) + ) + (fp_text value 18pF (at -1.651 0 225) (layer F.SilkS) + (effects (font (size 0.508 0.4572) (thickness 0.1143))) + ) + (fp_line (start 0.50038 0.65024) (end 1.19888 0.65024) (layer F.SilkS) (width 0.11938)) + (fp_line (start -0.50038 0.65024) (end -1.19888 0.65024) (layer F.SilkS) (width 0.11938)) + (fp_line (start 0.50038 -0.65024) (end 1.19888 -0.65024) (layer F.SilkS) (width 0.11938)) + (fp_line (start -1.19888 -0.65024) (end -0.50038 -0.65024) (layer F.SilkS) (width 0.11938)) + (fp_line (start 1.19888 -0.635) (end 1.19888 0.635) (layer F.SilkS) (width 0.11938)) + (fp_line (start -1.19888 0.635) (end -1.19888 -0.635) (layer F.SilkS) (width 0.11938)) + (pad 1 smd rect (at -0.762 0 135) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 25 /xtl2) + ) + (pad 2 smd rect (at 0.762 0 135) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 27 GND) + ) + (model smd\capacitors\C0603.wrl + (at (xyz 0 0 0.001)) + (scale (xyz 0.5 0.5 0.5)) + (rotate (xyz 0 0 0)) + ) + ) + + (module c_tant_B (layer F.Cu) (tedit 56630AA4) (tstamp 53C2D668) + (at 161 96.5 90) + (descr "SMT capacitor, tantalum size B") + (path /53C2AE76) + (fp_text reference C3 (at 4.2 0 180) (layer F.SilkS) + (effects (font (size 1 1) (thickness 0.15))) + ) + (fp_text value 22uF (at 0 2.2 90) (layer F.SilkS) hide + (effects (font (size 0.50038 0.50038) (thickness 0.11938))) + ) + (fp_line (start 2.8065 -1.597) (end 2.8065 1.597) (layer F.SilkS) (width 0.127)) + (fp_line (start 3.278 -1.597) (end -2.878 -1.597) (layer F.SilkS) (width 0.127)) + (fp_line (start -2.878 -1.597) (end -2.878 1.597) (layer F.SilkS) (width 0.127)) + (fp_line (start -2.878 1.597) (end 3.278 1.597) (layer F.SilkS) (width 0.127)) + (fp_line (start 3.278 1.597) (end 3.278 -1.597) (layer F.SilkS) (width 0.127)) + (pad 1 smd rect (at 1.524 0 90) (size 1.95072 2.49936) + (layers F.Cu F.Paste F.Mask) + (net 1 +5V) + ) + (pad 2 smd rect (at -1.524 0 90) (size 1.95072 2.49936) + (layers F.Cu F.Paste F.Mask) + (net 27 GND) + ) + (model smd/capacitors/c_tant_B.wrl + (at (xyz 0 0 0)) + (scale (xyz 1 1 1)) + (rotate (xyz 0 0 0)) + ) + ) + + (module SW_PUSH_6x4.5MM locked (layer F.Cu) (tedit 56B4BC4E) (tstamp 543948E9) + (at 156 104.3) + (path /56B4EC6E) + (fp_text reference SW2 (at 5.8 -2.3) (layer F.SilkS) + (effects (font (size 1.016 1.016) (thickness 0.2032))) + ) + (fp_text value BIND (at 0.1 4.5) (layer F.SilkS) + (effects (font (size 1.016 1.016) (thickness 0.2032))) + ) + (fp_line (start 3.8989 3.24974) (end -3.8989 3.24974) (layer F.SilkS) (width 0.127)) + (fp_line (start -3.8989 -3.24974) (end 3.8989 -3.24974) (layer F.SilkS) (width 0.127)) + (fp_line (start -3.8989 -3.25) (end -3.8989 3.25) (layer F.SilkS) (width 0.127)) + (fp_line (start 3.8989 3.25) (end 3.8989 -3.25) (layer F.SilkS) (width 0.127)) + (fp_circle (center 0 0) (end 0 -2.54) (layer F.SilkS) (width 0.127)) + (pad 2 thru_hole circle (at 3 -2.25) (size 1.69926 1.69926) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 37 N-0000034) + ) + (pad 4 thru_hole circle (at 3 2.25) (size 1.69926 1.69926) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 27 GND) + ) + (pad 1 thru_hole circle (at -3 -2.25) (size 1.69926 1.69926) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 37 N-0000034) + ) + (pad 3 thru_hole circle (at -3 2.25) (size 1.69926 1.69926) (drill 1) + (layers *.Cu *.Mask F.SilkS) + (net 27 GND) + ) + (model packages3d\discret\push_butt_6x4_th.wrl + (at (xyz 0 0 -0.065)) + (scale (xyz 0.3937 0.3937 0.3937)) + (rotate (xyz 180 0 0)) + ) + ) + + (module SM0603_Resistor (layer F.Cu) (tedit 5051B21B) (tstamp 56B4EFA6) + (at 165.862 112.522) + (path /56B4E6D8) + (attr smd) + (fp_text reference R8 (at 0.0635 -0.0635 90) (layer F.SilkS) + (effects (font (size 0.50038 0.4572) (thickness 0.1143))) + ) + (fp_text value 470 (at -1.69926 0 90) (layer F.SilkS) + (effects (font (size 0.508 0.4572) (thickness 0.1143))) + ) + (fp_line (start -0.50038 -0.6985) (end -1.2065 -0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start -1.2065 -0.6985) (end -1.2065 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start -1.2065 0.6985) (end -0.50038 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 -0.6985) (end 0.50038 -0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 -0.6985) (end 1.2065 0.6985) (layer F.SilkS) (width 0.127)) + (fp_line (start 1.2065 0.6985) (end 0.50038 0.6985) (layer F.SilkS) (width 0.127)) + (pad 1 smd rect (at -0.762 0) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 30 N-0000019) + ) + (pad 2 smd rect (at 0.762 0) (size 0.635 1.143) + (layers F.Cu F.Paste F.Mask) + (net 23 /TX) + ) + (model smd\resistors\R0603.wrl + (at (xyz 0 0 0.001)) + (scale (xyz 0.5 0.5 0.5)) + (rotate (xyz 0 0 0)) + ) + ) + + (module PIN_ARRAY_2X1 (layer F.Cu) (tedit 4565C520) (tstamp 56B4EFB0) + (at 162.052 111.887 90) + (descr "Connecteurs 2 pins") + (tags "CONN DEV") + (path /56B4E4CA) + (fp_text reference P3 (at 0 -1.905 90) (layer F.SilkS) + (effects (font (size 0.762 0.762) (thickness 0.1524))) + ) + (fp_text value CONN_2 (at 0 -1.905 90) (layer F.SilkS) hide + (effects (font (size 0.762 0.762) (thickness 0.1524))) + ) + (fp_line (start -2.54 1.27) (end -2.54 -1.27) (layer F.SilkS) (width 0.1524)) + (fp_line (start -2.54 -1.27) (end 2.54 -1.27) (layer F.SilkS) (width 0.1524)) + (fp_line (start 2.54 -1.27) (end 2.54 1.27) (layer F.SilkS) (width 0.1524)) + (fp_line (start 2.54 1.27) (end -2.54 1.27) (layer F.SilkS) (width 0.1524)) + (pad 1 thru_hole rect (at -1.27 0 90) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 33 N-0000021) + ) + (pad 2 thru_hole circle (at 1.27 0 90) (size 1.524 1.524) (drill 1.016) + (layers *.Cu *.Mask F.SilkS) + (net 30 N-0000019) + ) + (model pin_array/pins_array_2x1.wrl + (at (xyz 0 0 0)) + (scale (xyz 1 1 1)) + (rotate (xyz 0 0 0)) + ) + ) + + (module c_0603 (layer B.Cu) (tedit 490472AA) (tstamp 56B4EFBC) + (at 165.862 112.522) + (descr "SMT capacitor, 0603") + (path /56B4E4E1) + (fp_text reference JP3 (at 0 0.635) (layer B.SilkS) + (effects (font (size 0.20066 0.20066) (thickness 0.04064)) (justify mirror)) + ) + (fp_text value JUMPER (at 0 -0.635) (layer B.SilkS) hide + (effects (font (size 0.20066 0.20066) (thickness 0.04064)) (justify mirror)) + ) + (fp_line (start 0.5588 -0.4064) (end 0.5588 0.4064) (layer B.SilkS) (width 0.127)) + (fp_line (start -0.5588 0.381) (end -0.5588 -0.4064) (layer B.SilkS) (width 0.127)) + (fp_line (start -0.8128 0.4064) (end 0.8128 0.4064) (layer B.SilkS) (width 0.127)) + (fp_line (start 0.8128 0.4064) (end 0.8128 -0.4064) (layer B.SilkS) (width 0.127)) + (fp_line (start 0.8128 -0.4064) (end -0.8128 -0.4064) (layer B.SilkS) (width 0.127)) + (fp_line (start -0.8128 -0.4064) (end -0.8128 0.4064) (layer B.SilkS) (width 0.127)) + (pad 1 smd rect (at 0.75184 0) (size 0.89916 1.00076) + (layers B.Cu B.Paste B.Mask) + (net 32 N-0000020) + ) + (pad 2 smd rect (at -0.75184 0) (size 0.89916 1.00076) + (layers B.Cu B.Paste B.Mask) + (net 30 N-0000019) + ) + (model smd/capacitors/c_0603.wrl + (at (xyz 0 0 0)) + (scale (xyz 1 1 1)) + (rotate (xyz 0 0 0)) + ) + ) + + (module c_0603 (layer B.Cu) (tedit 56B5245A) (tstamp 56B4EFC8) + (at 165.862 108.966 180) + (descr "SMT capacitor, 0603") + (path /56B4EFD5) + (fp_text reference JP1 (at 0 0.635 180) (layer B.SilkS) + (effects (font (size 0.20066 0.20066) (thickness 0.04064)) (justify mirror)) + ) + (fp_text value JUMPER (at 0 -0.635 180) (layer B.SilkS) hide + (effects (font (size 0.20066 0.20066) (thickness 0.04064)) (justify mirror)) + ) + (fp_line (start 0.5588 -0.4064) (end 0.5588 0.4064) (layer B.SilkS) (width 0.127)) + (fp_line (start -0.5588 0.381) (end -0.5588 -0.4064) (layer B.SilkS) (width 0.127)) + (fp_line (start -0.8128 0.4064) (end 0.8128 0.4064) (layer B.SilkS) (width 0.127)) + (fp_line (start 0.8128 0.4064) (end 0.8128 -0.4064) (layer B.SilkS) (width 0.127)) + (fp_line (start 0.8128 -0.4064) (end -0.8128 -0.4064) (layer B.SilkS) (width 0.127)) + (fp_line (start -0.8128 -0.4064) (end -0.8128 0.4064) (layer B.SilkS) (width 0.127)) + (pad 1 smd rect (at 0.75184 0 180) (size 0.89916 1.00076) + (layers B.Cu B.Paste B.Mask) + (net 13 /D3) + ) + (pad 2 smd rect (at -0.75184 0 180) (size 0.89916 1.00076) + (layers B.Cu B.Paste B.Mask) + (net 35 N-0000023) + ) + (model smd/capacitors/c_0603.wrl + (at (xyz 0 0 0)) + (scale (xyz 1 1 1)) + (rotate (xyz 0 0 0)) + ) + ) + + (module c_0603 (layer B.Cu) (tedit 56B5246C) (tstamp 56B4F25F) + (at 165.862 110.744) + (descr "SMT capacitor, 0603") + (path /53FE5887) + (fp_text reference JP2 (at 0 0.635) (layer B.SilkS) + (effects (font (size 0.20066 0.20066) (thickness 0.04064)) (justify mirror)) + ) + (fp_text value JUMPER (at 0 -0.635) (layer B.SilkS) hide + (effects (font (size 0.20066 0.20066) (thickness 0.04064)) (justify mirror)) + ) + (fp_line (start 0.5588 -0.4064) (end 0.5588 0.4064) (layer B.SilkS) (width 0.127)) + (fp_line (start -0.5588 0.381) (end -0.5588 -0.4064) (layer B.SilkS) (width 0.127)) + (fp_line (start -0.8128 0.4064) (end 0.8128 0.4064) (layer B.SilkS) (width 0.127)) + (fp_line (start 0.8128 0.4064) (end 0.8128 -0.4064) (layer B.SilkS) (width 0.127)) + (fp_line (start 0.8128 -0.4064) (end -0.8128 -0.4064) (layer B.SilkS) (width 0.127)) + (fp_line (start -0.8128 -0.4064) (end -0.8128 0.4064) (layer B.SilkS) (width 0.127)) + (pad 1 smd rect (at 0.75184 0) (size 0.89916 1.00076) + (layers B.Cu B.Paste B.Mask) + (net 19 /PPM_IN) + ) + (pad 2 smd rect (at -0.75184 0) (size 0.89916 1.00076) + (layers B.Cu B.Paste B.Mask) + (net 34 N-0000022) + ) + (model smd/capacitors/c_0603.wrl + (at (xyz 0 0 0)) + (scale (xyz 1 1 1)) + (rotate (xyz 0 0 0)) + ) + ) + + (module c_0603 (layer B.Cu) (tedit 56B5247E) (tstamp 56B4F26B) + (at 165.862 114.3) + (descr "SMT capacitor, 0603") + (path /53FE5896) + (fp_text reference JP4 (at 0 0.635) (layer B.SilkS) + (effects (font (size 0.20066 0.20066) (thickness 0.04064)) (justify mirror)) + ) + (fp_text value JUMPER (at 0 -0.635) (layer B.SilkS) hide + (effects (font (size 0.20066 0.20066) (thickness 0.04064)) (justify mirror)) + ) + (fp_line (start 0.5588 -0.4064) (end 0.5588 0.4064) (layer B.SilkS) (width 0.127)) + (fp_line (start -0.5588 0.381) (end -0.5588 -0.4064) (layer B.SilkS) (width 0.127)) + (fp_line (start -0.8128 0.4064) (end 0.8128 0.4064) (layer B.SilkS) (width 0.127)) + (fp_line (start 0.8128 0.4064) (end 0.8128 -0.4064) (layer B.SilkS) (width 0.127)) + (fp_line (start 0.8128 -0.4064) (end -0.8128 -0.4064) (layer B.SilkS) (width 0.127)) + (fp_line (start -0.8128 -0.4064) (end -0.8128 0.4064) (layer B.SilkS) (width 0.127)) + (pad 1 smd rect (at 0.75184 0) (size 0.89916 1.00076) + (layers B.Cu B.Paste B.Mask) + (net 36 N-0000025) + ) + (pad 2 smd rect (at -0.75184 0) (size 0.89916 1.00076) + (layers B.Cu B.Paste B.Mask) + (net 33 N-0000021) + ) + (model smd/capacitors/c_0603.wrl + (at (xyz 0 0 0)) + (scale (xyz 1 1 1)) + (rotate (xyz 0 0 0)) + ) + ) + + (module 2_3d_jumper_table (layer B.Cu) (tedit 56B53DE2) (tstamp 56B54E4C) + (at 153.797 92.583 180) + (fp_text reference 2_3d_jumper_table (at 0 -11.43 180) (layer B.SilkS) hide + (effects (font (size 1 1) (thickness 0.15)) (justify mirror)) + ) + (fp_text value VAL** (at 0 -9.525 180) (layer B.SilkS) hide + (effects (font (size 1 1) (thickness 0.15)) (justify mirror)) + ) + (fp_text user "JUMPER PADS" (at 0 10.16 180) (layer B.SilkS) + (effects (font (size 1.5 1.5) (thickness 0.2)) (justify mirror)) + ) + (fp_line (start 8.89 -7.62) (end -8.89 -7.62) (layer B.SilkS) (width 0.15)) + (fp_line (start 8.89 -3.81) (end -8.89 -3.81) (layer B.SilkS) (width 0.15)) + (fp_line (start 8.89 0) (end -8.89 0) (layer B.SilkS) (width 0.15)) + (fp_line (start 8.89 3.81) (end -8.89 3.81) (layer B.SilkS) (width 0.15)) + (fp_text user MOD (at -3.81 -5.715 180) (layer B.SilkS) + (effects (font (size 1 1) (thickness 0.15)) (justify mirror)) + ) + (fp_text user "PPM V/V" (at -5.08 5.715 180) (layer B.SilkS) + (effects (font (size 1 1) (thickness 0.15)) (justify mirror)) + ) + (fp_text user TELEM (at -5.08 -1.905 180) (layer B.SilkS) + (effects (font (size 1 1) (thickness 0.15)) (justify mirror)) + ) + (fp_text user J-4 (at 6.35 -5.715 180) (layer B.SilkS) + (effects (font (size 1 1) (thickness 0.15)) (justify mirror)) + ) + (fp_text user J-3 (at 6.35 -1.905 180) (layer B.SilkS) + (effects (font (size 1 1) (thickness 0.15)) (justify mirror)) + ) + (fp_text user J-2 (at 6.35 1.905 180) (layer B.SilkS) + (effects (font (size 1 1) (thickness 0.15)) (justify mirror)) + ) + (fp_text user J-1 (at 6.35 5.715 180) (layer B.SilkS) + (effects (font (size 1 1) (thickness 0.15)) (justify mirror)) + ) + (fp_text user PPM\RX (at -5.08 1.905 180) (layer B.SilkS) + (effects (font (size 1 1) (thickness 0.15)) (justify mirror)) + ) + (fp_line (start 2.54 -4.445) (end 2.54 -6.985) (layer B.SilkS) (width 0.15)) + (fp_line (start 2.54 -6.985) (end 3.81 -6.985) (layer B.SilkS) (width 0.15)) + (fp_line (start 3.81 -6.985) (end 3.81 -4.445) (layer B.SilkS) (width 0.15)) + (fp_line (start 3.81 -4.445) (end 2.54 -4.445) (layer B.SilkS) (width 0.15)) + (fp_line (start -1.27 -4.445) (end -1.27 -6.985) (layer B.SilkS) (width 0.15)) + (fp_line (start -1.27 -6.985) (end 0 -6.985) (layer B.SilkS) (width 0.15)) + (fp_line (start 0 -6.985) (end 0 -4.445) (layer B.SilkS) (width 0.15)) + (fp_line (start 0 -4.445) (end -1.27 -4.445) (layer B.SilkS) (width 0.15)) + (fp_line (start 2.54 -0.635) (end 2.54 -3.175) (layer B.SilkS) (width 0.15)) + (fp_line (start 2.54 -3.175) (end 3.81 -3.175) (layer B.SilkS) (width 0.15)) + (fp_line (start 3.81 -3.175) (end 3.81 -0.635) (layer B.SilkS) (width 0.15)) + (fp_line (start 3.81 -0.635) (end 2.54 -0.635) (layer B.SilkS) (width 0.15)) + (fp_line (start -1.27 -0.635) (end -1.27 -3.175) (layer B.SilkS) (width 0.15)) + (fp_line (start -1.27 -3.175) (end 0 -3.175) (layer B.SilkS) (width 0.15)) + (fp_line (start 0 -3.175) (end 0 -0.635) (layer B.SilkS) (width 0.15)) + (fp_line (start 0 -0.635) (end -1.27 -0.635) (layer B.SilkS) (width 0.15)) + (fp_line (start 2.54 3.175) (end 2.54 0.635) (layer B.SilkS) (width 0.15)) + (fp_line (start 2.54 0.635) (end 3.81 0.635) (layer B.SilkS) (width 0.15)) + (fp_line (start 3.81 0.635) (end 3.81 3.175) (layer B.SilkS) (width 0.15)) + (fp_line (start 3.81 3.175) (end 2.54 3.175) (layer B.SilkS) (width 0.15)) + (fp_line (start -1.27 3.175) (end 0 3.175) (layer B.SilkS) (width 0.15)) + (fp_line (start 0 3.175) (end 0 0.635) (layer B.SilkS) (width 0.15)) + (fp_line (start 0 0.635) (end -1.27 0.635) (layer B.SilkS) (width 0.15)) + (fp_line (start -1.27 0.635) (end -1.27 3.175) (layer B.SilkS) (width 0.15)) + (fp_line (start 0 4.445) (end 0 6.985) (layer B.SilkS) (width 0.15)) + (fp_line (start 0 6.985) (end -1.27 6.985) (layer B.SilkS) (width 0.15)) + (fp_line (start -1.27 6.985) (end -1.27 4.445) (layer B.SilkS) (width 0.15)) + (fp_line (start -1.27 4.445) (end 0 4.445) (layer B.SilkS) (width 0.15)) + (fp_line (start 2.54 6.985) (end 3.81 6.985) (layer B.SilkS) (width 0.15)) + (fp_line (start 3.81 6.985) (end 3.81 4.445) (layer B.SilkS) (width 0.15)) + (fp_line (start 3.81 4.445) (end 2.54 4.445) (layer B.SilkS) (width 0.15)) + (fp_line (start 2.54 4.445) (end 2.54 6.985) (layer B.SilkS) (width 0.15)) + (fp_line (start -8.89 8.255) (end -8.89 -7.62) (layer B.SilkS) (width 0.15)) + (fp_line (start 8.89 -7.62) (end 8.89 8.255) (layer B.SilkS) (width 0.15)) + (fp_line (start 8.89 8.255) (end -8.89 8.255) (layer B.SilkS) (width 0.15)) + ) + + (gr_circle (center 158.4 77.9) (end 158.6 77.8) (layer F.SilkS) (width 0.3)) + (gr_circle (center 157.8 75) (end 157.8 75) (layer F.SilkS) (width 0.3) (tstamp 548B1EFC)) + (gr_text "Board is designed to be\n used with XtremeLink\n2.4GHz JR Remote Module box\nNote: Tolerances may be a little\ntight and may need adjusting." (at 124.377 93.84 90) (layer Cmts.User) + (effects (font (size 1.5 1.5) (thickness 0.3))) + ) + (gr_text "DIY-Multiprotocol Ver 2.3d\nAK Design Service 02/2016\nakdesignsvc@gmail.com" (at 172.466 90.17 90) (layer B.SilkS) + (effects (font (size 1.5 0.8) (thickness 0.15)) (justify mirror)) + ) + (gr_arc (start 182.3 59.3) (end 182.3 62.3) (angle 90) (layer Edge.Cuts) (width 0.1)) + (gr_arc (start 141.2 59.3) (end 144.15 59.3) (angle 90) (layer Edge.Cuts) (width 0.1) (tstamp 5494C20B)) + (gr_line (start 182.3 62.3) (end 182.3 77.3) (angle 90) (layer Edge.Cuts) (width 0.1)) + (gr_line (start 141.2 98.15) (end 141.2 115.9) (angle 90) (layer Edge.Cuts) (width 0.1)) + (gr_line (start 141.2 98.15) (end 144 98.15) (angle 90) (layer Edge.Cuts) (width 0.1)) + (gr_line (start 144 77.3) (end 144 98.15) (angle 90) (layer Edge.Cuts) (width 0.1)) + (gr_line (start 141.2 77.3) (end 144 77.3) (angle 90) (layer Edge.Cuts) (width 0.1)) + (gr_line (start 141.2 62.3) (end 141.2 77.3) (angle 90) (layer Edge.Cuts) (width 0.1) (tstamp 5494C1E3)) + (gr_line (start 144.15 59.3) (end 179.3 59.3) (angle 90) (layer Edge.Cuts) (width 0.1) (tstamp 5494C420)) + (gr_line (start 179.5 77.3) (end 182.3 77.3) (angle 90) (layer Edge.Cuts) (width 0.1)) + (gr_line (start 179.5 77.3) (end 179.5 98.15) (angle 90) (layer Edge.Cuts) (width 0.1)) + (gr_line (start 179.5 98.15) (end 182.3 98.15) (angle 90) (layer Edge.Cuts) (width 0.1)) + (gr_line (start 182.3 98.15) (end 182.3 115.9) (angle 90) (layer Edge.Cuts) (width 0.1)) + (gr_line (start 141.2 115.9) (end 182.3 115.9) (angle 90) (layer Edge.Cuts) (width 0.1)) + + (segment (start 165.698 96) (end 162.024 96) (width 1) (layer F.Cu) (net 1)) + (segment (start 162.024 96) (end 161 94.976) (width 1) (layer F.Cu) (net 1) (tstamp 548A0010)) + (segment (start 156.302 93.714) (end 159.738 93.714) (width 1) (layer F.Cu) (net 1)) + (segment (start 159.738 93.714) (end 161 94.976) (width 1) (layer F.Cu) (net 1) (tstamp 548A0006)) + (segment (start 146 90.5) (end 147.5 92) (width 0.6) (layer B.Cu) (net 1)) + (segment (start 150 69.5) (end 151.5 68) (width 0.6) (layer B.Cu) (net 1) (tstamp 5489EC3D)) + (segment (start 151.5 68) (end 151.5 65.5) (width 0.6) (layer B.Cu) (net 1) (tstamp 5489EC48)) + (segment (start 151.5 65.5) (end 152.5 64.5) (width 0.6) (layer B.Cu) (net 1) (tstamp 5489EC4B)) + (segment (start 156.302 93.714) (end 153.214 93.714) (width 0.6) (layer F.Cu) (net 1)) + (segment (start 152.562 64.438) (end 152.562 61.7) (width 0.6) (layer F.Cu) (net 1) (tstamp 5489E1F3)) + (segment (start 152.5 64.5) (end 152.562 64.438) (width 0.6) (layer F.Cu) (net 1) (tstamp 5489E1F2)) + (via (at 152.5 64.5) (size 0.889) (layers F.Cu B.Cu) (net 1)) + (segment (start 143 71) (end 144.5 69.5) (width 0.6) (layer B.Cu) (net 1) (tstamp 5489E1DB)) + (segment (start 143 74) (end 143 71) (width 0.6) (layer B.Cu) (net 1) (tstamp 5489E1D6)) + (segment (start 146 77) (end 143 74) (width 0.6) (layer B.Cu) (net 1) (tstamp 5489E1D1)) + (segment (start 146 90.5) (end 146 77) (width 0.6) (layer B.Cu) (net 1) (tstamp 5489E1C5)) + (via (at 152.5 93) (size 0.889) (layers F.Cu B.Cu) (net 1)) + (segment (start 153.214 93.714) (end 152.5 93) (width 0.6) (layer F.Cu) (net 1) (tstamp 5489E1B7)) + (segment (start 144.5 69.5) (end 150 69.5) (width 0.6) (layer B.Cu) (net 1)) + (segment (start 151.5 92) (end 152.5 93) (width 0.6) (layer B.Cu) (net 1) (tstamp 5489ECEE)) + (segment (start 147.5 92) (end 151.5 92) (width 0.6) (layer B.Cu) (net 1) (tstamp 5489ECE3)) + (segment (start 152.562 61.7) (end 155.6 61.7) (width 0.4) (layer F.Cu) (net 1)) + (segment (start 155.6 60.9) (end 156 61.3) (width 0.254) (layer F.Cu) (net 1) (tstamp 548059AA)) + (segment (start 173.5 89.05) (end 173.505 89.05) (width 0.254) (layer B.Cu) (net 2)) + (segment (start 171.795457 87.221775) (end 173.5 88.926318) (width 0.254) (layer F.Cu) (net 2) (tstamp 5495BF3D)) + (segment (start 173.5 89.05) (end 173.5 88.926318) (width 0.254) (layer F.Cu) (net 2)) + (via (at 173.5 89.05) (size 0.889) (layers F.Cu B.Cu) (net 2)) + (segment (start 169.935575 105.675425) (end 169.926 105.664) (width 0.254) (layer B.Cu) (net 2)) + (segment (start 169.935575 105.675425) (end 170.815 104.945049) (width 0.254) (layer B.Cu) (net 2) (tstamp 54D531AA)) + (segment (start 170.815 102.235) (end 170.815 104.945049) (width 0.254) (layer B.Cu) (net 2) (tstamp 56B50E7D)) + (segment (start 174.879 98.171) (end 170.815 102.235) (width 0.254) (layer B.Cu) (net 2) (tstamp 56B50E72)) + (segment (start 174.879 94.615) (end 174.879 98.171) (width 0.254) (layer B.Cu) (net 2) (tstamp 56B50E6B)) + (segment (start 174.117 93.853) (end 174.879 94.615) (width 0.254) (layer B.Cu) (net 2) (tstamp 56B50E63)) + (segment (start 174.117 89.662) (end 174.117 93.853) (width 0.254) (layer B.Cu) (net 2) (tstamp 56B50E58)) + (segment (start 173.505 89.05) (end 174.117 89.662) (width 0.254) (layer B.Cu) (net 2) (tstamp 56B50E4F)) + (segment (start 150.41 107.16) (end 151.102 107.16) (width 0.254) (layer F.Cu) (net 2)) + (segment (start 151.102 107.16) (end 151.765 107.823) (width 0.254) (layer F.Cu) (net 2) (tstamp 56B4F878)) + (segment (start 151.765 107.823) (end 160.782 107.823) (width 0.254) (layer F.Cu) (net 2) (tstamp 56B4F881)) + (segment (start 160.782 107.823) (end 161.798 106.807) (width 0.254) (layer F.Cu) (net 2) (tstamp 56B4F88D)) + (segment (start 161.798 106.807) (end 163.449 106.807) (width 0.254) (layer F.Cu) (net 2) (tstamp 56B4F890)) + (segment (start 163.449 106.807) (end 164.592 105.664) (width 0.254) (layer F.Cu) (net 2) (tstamp 56B4F89D)) + (segment (start 164.592 105.664) (end 169.926 105.664) (width 0.254) (layer F.Cu) (net 2) (tstamp 56B4F8A2)) + (via (at 169.926 105.664) (size 0.889) (layers F.Cu B.Cu) (net 2)) + (segment (start 169.926 105.664) (end 169.926 105.664) (width 0.254) (layer B.Cu) (net 2) (tstamp 5495BEE7)) + (segment (start 150.41 107.16) (end 150.96 107.16) (width 0.254) (layer F.Cu) (net 2)) + (segment (start 171.795457 87.295457) (end 171.795457 87.221775) (width 0.254) (layer F.Cu) (net 2) (tstamp 5481AEBF)) + (segment (start 171.795457 87.221775) (end 171.795457 87.295457) (width 0.254) (layer F.Cu) (net 2)) + (segment (start 166.670835 74.4) (end 168.35 74.4) (width 0.254) (layer B.Cu) (net 3)) + (segment (start 159.4 71.7) (end 159.7 71.4) (width 0.254) (layer B.Cu) (net 3) (tstamp 5480C5CA)) + (segment (start 159.7 71.4) (end 163.420835 71.4) (width 0.254) (layer B.Cu) (net 3) (tstamp 5480C5CD)) + (segment (start 163.420835 71.4) (end 166.670835 74.4) (width 0.254) (layer B.Cu) (net 3) (tstamp 5480C5D1)) + (segment (start 159.4 72.7) (end 159.4 71.7) (width 0.254) (layer B.Cu) (net 3)) + (via (at 168.35 74.4) (size 0.889) (layers F.Cu B.Cu) (net 3)) + (segment (start 168.415288 74.515288) (end 168.415288 79.890294) (width 0.254) (layer F.Cu) (net 3)) + (segment (start 174.29 108.5) (end 172.7 108.5) (width 1) (layer F.Cu) (net 4)) + (segment (start 170.9 101.5) (end 169.524 101.5) (width 1) (layer F.Cu) (net 4) (tstamp 5495E865)) + (segment (start 171.8 102.4) (end 170.9 101.5) (width 1) (layer F.Cu) (net 4) (tstamp 5495E864)) + (segment (start 171.8 107.6) (end 171.8 102.4) (width 1) (layer F.Cu) (net 4) (tstamp 5495E863)) + (segment (start 172.7 108.5) (end 171.8 107.6) (width 1) (layer F.Cu) (net 4) (tstamp 5495E862)) + (segment (start 165.698 98.286) (end 167.786 98.286) (width 1) (layer F.Cu) (net 4)) + (segment (start 169.524 100.024) (end 169.524 101.5) (width 1) (layer F.Cu) (net 4) (tstamp 5489E132)) + (segment (start 167.786 98.286) (end 169.524 100.024) (width 1) (layer F.Cu) (net 4) (tstamp 5489E12C)) + (segment (start 159.2 66.9) (end 159.2 68.7) (width 0.254) (layer B.Cu) (net 5)) + (segment (start 161.775791 88.8) (end 162.761319 87.814472) (width 0.254) (layer F.Cu) (net 5) (tstamp 548068E8)) + (segment (start 158.15 88.8) (end 161.775791 88.8) (width 0.254) (layer F.Cu) (net 5) (tstamp 548068DC)) + (segment (start 152.85 83.5) (end 158.15 88.8) (width 0.254) (layer F.Cu) (net 5) (tstamp 548068D1)) + (segment (start 152.85 76.15) (end 152.85 83.5) (width 0.254) (layer F.Cu) (net 5) (tstamp 548068CE)) + (segment (start 150.7 74) (end 152.85 76.15) (width 0.254) (layer F.Cu) (net 5) (tstamp 548068CB)) + (segment (start 144.75 74) (end 150.7 74) (width 0.254) (layer F.Cu) (net 5) (tstamp 548068BF)) + (segment (start 144.05 73.3) (end 144.75 74) (width 0.254) (layer F.Cu) (net 5) (tstamp 548068BC)) + (segment (start 144.05 71.7) (end 144.05 73.3) (width 0.254) (layer F.Cu) (net 5) (tstamp 548068AE)) + (segment (start 145 70.75) (end 144.05 71.7) (width 0.254) (layer F.Cu) (net 5) (tstamp 548068A8)) + (segment (start 154.25 70.75) (end 145 70.75) (width 0.254) (layer F.Cu) (net 5) (tstamp 548068A7)) + (via (at 154.25 70.75) (size 0.889) (layers F.Cu B.Cu) (net 5)) + (segment (start 157.25 70.75) (end 154.25 70.75) (width 0.254) (layer B.Cu) (net 5) (tstamp 5480689E)) + (segment (start 159.2 68.7) (end 157.25 70.75) (width 0.254) (layer B.Cu) (net 5) (tstamp 54806898)) + (segment (start 165.2 66.9) (end 165.2 67.9) (width 0.254) (layer F.Cu) (net 6)) + (segment (start 155.2 67.9) (end 155.2 66.9) (width 0.254) (layer F.Cu) (net 6) (tstamp 547F88F2)) + (segment (start 156.2 68.9) (end 155.2 67.9) (width 0.254) (layer F.Cu) (net 6) (tstamp 547F88E4)) + (segment (start 164.2 68.9) (end 156.2 68.9) (width 0.254) (layer F.Cu) (net 6) (tstamp 547F88DF)) + (segment (start 165.2 67.9) (end 164.2 68.9) (width 0.254) (layer F.Cu) (net 6) (tstamp 547F88D8)) + (segment (start 161.2 66.9) (end 161.2 67.5) (width 0.254) (layer F.Cu) (net 7)) + (segment (start 157.2 67.5) (end 157.2 66.9) (width 0.254) (layer F.Cu) (net 7) (tstamp 547F8908)) + (segment (start 157.8 68.1) (end 157.2 67.5) (width 0.254) (layer F.Cu) (net 7) (tstamp 547F8901)) + (segment (start 160.6 68.1) (end 157.8 68.1) (width 0.254) (layer F.Cu) (net 7) (tstamp 547F88FC)) + (segment (start 161.2 67.5) (end 160.6 68.1) (width 0.254) (layer F.Cu) (net 7) (tstamp 547F88F9)) + (segment (start 156 63.3) (end 155.8 63.3) (width 0.254) (layer F.Cu) (net 8)) + (segment (start 162.902894 89.9) (end 163.874871 88.928023) (width 0.254) (layer F.Cu) (net 8) (tstamp 54806955)) + (segment (start 158.4 89.9) (end 162.902894 89.9) (width 0.254) (layer F.Cu) (net 8) (tstamp 54806950)) + (segment (start 152.3 83.8) (end 158.4 89.9) (width 0.254) (layer F.Cu) (net 8) (tstamp 54806945)) + (segment (start 152.3 76.441307) (end 152.3 83.8) (width 0.254) (layer F.Cu) (net 8) (tstamp 5480693D)) + (segment (start 150.487498 74.55) (end 152.3 76.441307) (width 0.254) (layer F.Cu) (net 8) (tstamp 54806938)) + (segment (start 144.503846 74.55) (end 150.487498 74.55) (width 0.254) (layer F.Cu) (net 8) (tstamp 54806934)) + (segment (start 143.5 73.506) (end 144.503846 74.55) (width 0.254) (layer F.Cu) (net 8) (tstamp 5480692E)) + (segment (start 143.5 71.55) (end 143.5 73.506) (width 0.254) (layer F.Cu) (net 8) (tstamp 5480692C)) + (segment (start 144.639062 70.2) (end 143.5 71.55) (width 0.254) (layer F.Cu) (net 8) (tstamp 54806927)) + (segment (start 151.8 70.2) (end 144.639062 70.2) (width 0.254) (layer F.Cu) (net 8) (tstamp 54806922)) + (segment (start 153.25 68.75) (end 151.8 70.2) (width 0.254) (layer F.Cu) (net 8) (tstamp 5480691C)) + (segment (start 153.25 65.85) (end 153.25 68.75) (width 0.254) (layer F.Cu) (net 8) (tstamp 54806915)) + (segment (start 155.8 63.3) (end 153.25 65.85) (width 0.254) (layer F.Cu) (net 8) (tstamp 5480690B)) + (segment (start 164 61.3) (end 167.4 61.3) (width 0.254) (layer F.Cu) (net 9)) + (segment (start 176.2 76.631631) (end 170.678313 82.153318) (width 0.254) (layer F.Cu) (net 9) (tstamp 5480B51F)) + (segment (start 176.2 72.1) (end 176.2 76.631631) (width 0.254) (layer F.Cu) (net 9) (tstamp 5480B51A)) + (segment (start 177.25 71.05) (end 176.2 72.1) (width 0.254) (layer F.Cu) (net 9) (tstamp 5480B515)) + (segment (start 177.25 68.1) (end 177.25 71.05) (width 0.254) (layer F.Cu) (net 9) (tstamp 5480B501)) + (segment (start 174.85 65.7) (end 177.25 68.1) (width 0.254) (layer F.Cu) (net 9) (tstamp 5480B4FA)) + (segment (start 171.8 65.7) (end 174.85 65.7) (width 0.254) (layer F.Cu) (net 9) (tstamp 5480B4F5)) + (segment (start 167.4 61.3) (end 171.8 65.7) (width 0.254) (layer F.Cu) (net 9) (tstamp 5480B4DF)) + (segment (start 144.951559 94.145724) (end 144.937197 106.162803) (width 0.254) (layer F.Cu) (net 10)) + (segment (start 144.951559 94.145724) (end 147.920535 91.15) (width 0.254) (layer F.Cu) (net 10) (tstamp 54807187)) + (segment (start 147.920535 91.15) (end 162.802367 91.15) (width 0.254) (layer F.Cu) (net 10) (tstamp 54807198)) + (segment (start 164.449607 89.50276) (end 162.802367 91.15) (width 0.254) (layer F.Cu) (net 10) (tstamp 5480719C)) + (segment (start 143.94 107.16) (end 142.79 107.16) (width 0.254) (layer F.Cu) (net 10) (tstamp 5481B740)) + (segment (start 144.937197 106.162803) (end 143.94 107.16) (width 0.254) (layer F.Cu) (net 10) (tstamp 5481B73A)) + (segment (start 176.5 72.1) (end 176.4 72.1) (width 0.254) (layer B.Cu) (net 11)) + (segment (start 171.2 76.25) (end 170.8 76.65) (width 0.254) (layer B.Cu) (net 11) (tstamp 54849775)) + (segment (start 172.25 76.25) (end 171.2 76.25) (width 0.254) (layer B.Cu) (net 11) (tstamp 54849767)) + (segment (start 176.4 72.1) (end 172.25 76.25) (width 0.254) (layer B.Cu) (net 11) (tstamp 54849758)) + (segment (start 153.26 112.24) (end 156.972 108.528) (width 0.254) (layer B.Cu) (net 11) (tstamp 5480AC29)) + (segment (start 156.972 108.528) (end 156.972 99.695) (width 0.254) (layer B.Cu) (net 11) (tstamp 5480AC2E)) + (segment (start 150.41 112.24) (end 153.26 112.24) (width 0.254) (layer B.Cu) (net 11)) + (segment (start 165.862 90.805) (end 165.862 85.344) (width 0.254) (layer B.Cu) (net 11) (tstamp 5480C28B)) + (segment (start 156.972 99.695) (end 165.862 90.805) (width 0.254) (layer B.Cu) (net 11) (tstamp 5480C280)) + (segment (start 177.8 72.1) (end 176.5 72.1) (width 0.254) (layer B.Cu) (net 11)) + (segment (start 176.5 72.1) (end 176.35 72.1) (width 0.254) (layer B.Cu) (net 11) (tstamp 54849756)) + (segment (start 170.8 76.65) (end 169.65 76.65) (width 0.254) (layer B.Cu) (net 11) (tstamp 5484978F)) + (segment (start 165.8 80.5) (end 165.862 85.344) (width 0.254) (layer B.Cu) (net 11) (tstamp 5480B3E2)) + (segment (start 169.65 76.65) (end 165.8 80.5) (width 0.254) (layer B.Cu) (net 11) (tstamp 5480B3DF)) + (segment (start 165.862 85.344) (end 165.862 85.344) (width 0.254) (layer B.Cu) (net 11) (tstamp 5480B3EE)) + (segment (start 175.4 65.4) (end 177.8 67.8) (width 0.254) (layer F.Cu) (net 11) (tstamp 54806520)) + (segment (start 177.8 67.8) (end 177.8 72.1) (width 0.254) (layer F.Cu) (net 11) (tstamp 54806530)) + (via (at 177.8 72.1) (size 0.889) (layers F.Cu B.Cu) (net 11)) + (segment (start 175.4 65.4) (end 175.4 63.37) (width 0.254) (layer F.Cu) (net 11)) + (segment (start 165.862 85.344) (end 165.8 89.3) (width 0.254) (layer F.Cu) (net 11)) + (via (at 165.862 85.344) (size 0.889) (layers F.Cu B.Cu) (net 11)) + (segment (start 165.8 89.3) (end 165.024344 90.075656) (width 0.254) (layer F.Cu) (net 11) (tstamp 54806E64)) + (segment (start 165.024344 90.075656) (end 165.024344 90.077496) (width 0.254) (layer F.Cu) (net 11) (tstamp 54806E68)) + (segment (start 165.024344 90.075656) (end 165.024344 90.077496) (width 0.254) (layer F.Cu) (net 11) (tstamp 5480655E)) + (segment (start 177.94 60.83) (end 178.53 60.83) (width 0.254) (layer B.Cu) (net 12)) + (via (at 168.35 86.65) (size 0.889) (layers F.Cu B.Cu) (net 12)) + (segment (start 168.35 86.65) (end 166.6 88.5) (width 0.254) (layer F.Cu) (net 12) (tstamp 54806F35)) + (segment (start 166.6 88.5) (end 166.6 89.651313) (width 0.254) (layer F.Cu) (net 12) (tstamp 54806F36)) + (segment (start 166.6 89.651313) (end 165.59908 90.652233) (width 0.254) (layer F.Cu) (net 12) (tstamp 54806F3B)) + (segment (start 168.35 86.65) (end 168.35 86.65) (width 0.254) (layer B.Cu) (net 12) (tstamp 5480B90C)) + (segment (start 179.85 75.248723) (end 168.35 86.65) (width 0.254) (layer B.Cu) (net 12) (tstamp 5480B906)) + (segment (start 179.85 62.15) (end 179.85 75.248723) (width 0.254) (layer B.Cu) (net 12) (tstamp 5480B8FD)) + (segment (start 178.53 60.83) (end 179.85 62.15) (width 0.254) (layer B.Cu) (net 12) (tstamp 5480B8F6)) + (segment (start 142.79 112.24) (end 144.36 112.24) (width 0.254) (layer F.Cu) (net 12)) + (segment (start 164.551313 91.7) (end 165.59908 90.652233) (width 0.254) (layer F.Cu) (net 12) (tstamp 548071C6)) + (segment (start 148.45 91.7) (end 164.551313 91.7) (width 0.254) (layer F.Cu) (net 12) (tstamp 548071BC)) + (segment (start 145.5 94.65) (end 148.45 91.7) (width 0.254) (layer F.Cu) (net 12) (tstamp 548071B2)) + (segment (start 145.5 111.1) (end 145.5 94.65) (width 0.254) (layer F.Cu) (net 12) (tstamp 548071AA)) + (segment (start 144.36 112.24) (end 145.5 111.1) (width 0.254) (layer F.Cu) (net 12) (tstamp 548071A3)) + (segment (start 165.647767 90.652233) (end 165.59908 90.652233) (width 0.254) (layer F.Cu) (net 12) (tstamp 54806497)) + (segment (start 175.768 95.631) (end 175.768 94.615) (width 0.254) (layer B.Cu) (net 13)) + (segment (start 172.93 85.3) (end 174.733 87.103) (width 0.254) (layer B.Cu) (net 13) (tstamp 5480C7C7)) + (segment (start 174.733 87.103) (end 174.733 93.58) (width 0.254) (layer B.Cu) (net 13) (tstamp 5480C7CD)) + (segment (start 165.597478 79.897478) (end 165.591896 79.897478) (width 0.254) (layer F.Cu) (net 13) (tstamp 5480B124)) + (segment (start 171 85.3) (end 165.597478 79.897478) (width 0.254) (layer F.Cu) (net 13) (tstamp 5480B123)) + (via (at 171 85.3) (size 0.889) (layers F.Cu B.Cu) (net 13)) + (segment (start 171 85.3) (end 172.93 85.3) (width 0.254) (layer B.Cu) (net 13)) + (segment (start 175.768 94.615) (end 174.733 93.58) (width 0.254) (layer B.Cu) (net 13) (tstamp 56B4FAD6)) + (segment (start 165.11016 108.966) (end 165.11016 107.83316) (width 0.254) (layer B.Cu) (net 13)) + (segment (start 175.768 95.631) (end 175.768 96.901) (width 0.254) (layer F.Cu) (net 13) (tstamp 56B4FA77)) + (via (at 175.768 95.631) (size 0.889) (layers F.Cu B.Cu) (net 13)) + (segment (start 175.768 98.298) (end 175.768 95.631) (width 0.254) (layer B.Cu) (net 13) (tstamp 56B4FA70)) + (segment (start 171.45 102.616) (end 175.768 98.298) (width 0.254) (layer B.Cu) (net 13) (tstamp 56B4FA67)) + (segment (start 171.45 105.9688) (end 171.45 102.616) (width 0.254) (layer B.Cu) (net 13) (tstamp 56B4FA5F)) + (segment (start 170.561 106.68) (end 171.45 105.9688) (width 0.254) (layer B.Cu) (net 13) (tstamp 56B4FA5E)) + (via (at 170.561 106.68) (size 0.889) (layers F.Cu B.Cu) (net 13)) + (segment (start 165.481 106.68) (end 170.561 106.68) (width 0.254) (layer F.Cu) (net 13) (tstamp 56B4FA52)) + (segment (start 165.1 107.061) (end 165.481 106.68) (width 0.254) (layer F.Cu) (net 13) (tstamp 56B4FA4F)) + (segment (start 165.1 107.823) (end 165.1 107.061) (width 0.254) (layer F.Cu) (net 13) (tstamp 56B4FA4E)) + (via (at 165.1 107.823) (size 0.889) (layers F.Cu B.Cu) (net 13)) + (segment (start 165.11016 107.83316) (end 165.1 107.823) (width 0.254) (layer B.Cu) (net 13) (tstamp 56B4FA46)) + (segment (start 165.5 70.537164) (end 165.5 76.85) (width 0.254) (layer F.Cu) (net 14)) + (segment (start 166.25904 69.89096) (end 165.5 70.537164) (width 0.254) (layer F.Cu) (net 14) (tstamp 5480BE2C)) + (via (at 165.5 76.75) (size 0.889) (layers F.Cu B.Cu) (net 14)) + (segment (start 165.5 76.75) (end 163.4 78.85) (width 0.254) (layer B.Cu) (net 14) (tstamp 5480BE52)) + (segment (start 163.4 78.85) (end 163.4 85.3) (width 0.254) (layer B.Cu) (net 14) (tstamp 5480BE53)) + (via (at 163.4 85.3) (size 0.889) (layers F.Cu B.Cu) (net 14)) + (segment (start 163.4 85.3) (end 163.4 86.1) (width 0.254) (layer F.Cu) (net 14) (tstamp 5480BE5E)) + (segment (start 163.4 86.1) (end 162.260265 87.239735) (width 0.254) (layer F.Cu) (net 14) (tstamp 5480BE5F)) + (segment (start 162.186583 87.239735) (end 162.260265 87.239735) (width 0.254) (layer F.Cu) (net 14) (tstamp 5480BE61)) + (segment (start 166.25904 69.89096) (end 166.74682 69.89096) (width 0.254) (layer F.Cu) (net 14)) + (segment (start 167.2 66.9) (end 167.2 65.1) (width 0.254) (layer B.Cu) (net 14)) + (segment (start 165.4 63.3) (end 164 63.3) (width 0.254) (layer B.Cu) (net 14) (tstamp 547F89D7)) + (segment (start 167.2 65.1) (end 165.4 63.3) (width 0.254) (layer B.Cu) (net 14) (tstamp 547F89C8)) + (segment (start 167.2 66.9) (end 167.2 69.43778) (width 0.254) (layer F.Cu) (net 14)) + (segment (start 167.2 69.43778) (end 166.74682 69.89096) (width 0.254) (layer F.Cu) (net 14) (tstamp 547F87E6)) + (segment (start 153 66.1) (end 154.2 64.9) (width 0.254) (layer B.Cu) (net 15) (tstamp 54805C94)) + (segment (start 154.2 64.9) (end 160.4 64.9) (width 0.254) (layer B.Cu) (net 15) (tstamp 54805C9C)) + (segment (start 162 63.3) (end 160.4 64.9) (width 0.254) (layer B.Cu) (net 15) (tstamp 54805CA1)) + (segment (start 153 72) (end 153 66.1) (width 0.254) (layer B.Cu) (net 15)) + (segment (start 153 72) (end 153.4 72.7) (width 0.254) (layer B.Cu) (net 15) (tstamp 54852A88)) + (segment (start 158.001639 87.75) (end 160.5 87.75) (width 0.254) (layer F.Cu) (net 15)) + (segment (start 153.4 83.222582) (end 158.001639 87.75) (width 0.254) (layer F.Cu) (net 15) (tstamp 54805FA1)) + (segment (start 153.4 72.7) (end 153.4 83.222582) (width 0.254) (layer F.Cu) (net 15)) + (segment (start 160.5 87.75) (end 161.629807 86.682959) (width 0.254) (layer F.Cu) (net 15) (tstamp 5480701A)) + (segment (start 171.2 66.9) (end 171.2 65.95) (width 0.254) (layer F.Cu) (net 15)) + (segment (start 163.85 65.15) (end 162 63.3) (width 0.254) (layer F.Cu) (net 15) (tstamp 547F87A3)) + (segment (start 170.4 65.15) (end 163.85 65.15) (width 0.254) (layer F.Cu) (net 15) (tstamp 547F8791)) + (segment (start 171.2 65.95) (end 170.4 65.15) (width 0.254) (layer F.Cu) (net 15) (tstamp 547F8782)) + (segment (start 170.6 67.5) (end 171.2 66.9) (width 0.254) (layer F.Cu) (net 15) (tstamp 547F876F)) + (segment (start 170.6 71.3) (end 170.6 67.5) (width 0.254) (layer F.Cu) (net 15) (tstamp 547F876A)) + (segment (start 169.28682 72.43096) (end 169.46904 72.43096) (width 0.254) (layer F.Cu) (net 15)) + (segment (start 169.46904 72.43096) (end 170.6 71.3) (width 0.254) (layer F.Cu) (net 15) (tstamp 547F8767)) + (segment (start 173.038 71.338) (end 173.038 74.5) (width 0.254) (layer F.Cu) (net 16) (tstamp 548055D5)) + (segment (start 171.82682 69.89096) (end 171.82682 70.12682) (width 0.254) (layer F.Cu) (net 16)) + (segment (start 171.82682 70.12682) (end 173.038 71.338) (width 0.254) (layer F.Cu) (net 16) (tstamp 548055CD)) + (segment (start 164.8 87) (end 164.689343 87) (width 0.254) (layer F.Cu) (net 17)) + (via (at 164.8 87) (size 0.889) (layers F.Cu B.Cu) (net 17)) + (segment (start 164.689343 87) (end 163.318095 88.371248) (width 0.254) (layer F.Cu) (net 17) (tstamp 54947F03)) + (segment (start 171.8 75.3) (end 171.2 75.3) (width 0.254) (layer B.Cu) (net 17)) + (segment (start 163.318095 88.371248) (end 163.318095 88.181905) (width 0.254) (layer F.Cu) (net 17) (tstamp 5480668D)) + (segment (start 171.82682 75.27318) (end 171.8 75.3) (width 0.254) (layer F.Cu) (net 17) (tstamp 5480665F)) + (via (at 171.8 75.3) (size 0.889) (layers F.Cu B.Cu) (net 17)) + (segment (start 171.82682 75.27318) (end 171.82682 72.43096) (width 0.254) (layer F.Cu) (net 17)) + (segment (start 164.8 87) (end 164.8 87) (width 0.254) (layer B.Cu) (net 17) (tstamp 5480B253)) + (segment (start 164.8 80.528229) (end 164.8 87) (width 0.254) (layer B.Cu) (net 17) (tstamp 5480B247)) + (segment (start 169.439098 76.1) (end 164.8 80.528229) (width 0.254) (layer B.Cu) (net 17) (tstamp 5480B242)) + (segment (start 170.4 76.1) (end 169.439098 76.1) (width 0.254) (layer B.Cu) (net 17) (tstamp 5480B23E)) + (segment (start 171.2 75.3) (end 170.4 76.1) (width 0.254) (layer B.Cu) (net 17) (tstamp 5480B22E)) + (segment (start 161.29 105.791) (end 160.02 105.791) (width 0.254) (layer B.Cu) (net 18)) + (segment (start 157.607 100.33) (end 165.837 92.1) (width 0.254) (layer B.Cu) (net 18) (tstamp 56B4F100)) + (segment (start 167.315728 90.634272) (end 165.85 92.1) (width 0.254) (layer F.Cu) (net 18) (tstamp 5495BB96)) + (segment (start 165.85 92.1) (end 165.837 92.1) (width 0.254) (layer B.Cu) (net 18)) + (via (at 165.85 92.1) (size 0.889) (layers F.Cu B.Cu) (net 18)) + (segment (start 168.382959 90.634272) (end 167.315728 90.634272) (width 0.254) (layer F.Cu) (net 18)) + (via (at 161.29 105.791) (size 0.889) (layers F.Cu B.Cu) (net 18)) + (segment (start 157.607 104.648) (end 157.607 100.33) (width 0.254) (layer B.Cu) (net 18) (tstamp 56B4F0ED)) + (segment (start 161.29 105.791) (end 162.687 105.791) (width 0.254) (layer F.Cu) (net 18)) + (segment (start 158.242 105.283) (end 157.607 104.648) (width 0.254) (layer B.Cu) (net 18) (tstamp 56B50CEE)) + (segment (start 159.512 105.283) (end 158.242 105.283) (width 0.254) (layer B.Cu) (net 18) (tstamp 56B50CEC)) + (segment (start 160.02 105.791) (end 159.512 105.283) (width 0.254) (layer B.Cu) (net 18) (tstamp 56B50CE1)) + (segment (start 178.75 67.9) (end 178.75 72.5) (width 0.254) (layer F.Cu) (net 18)) + (segment (start 175.4 61.3) (end 176.6 62.5) (width 0.254) (layer F.Cu) (net 18) (tstamp 54806BDC)) + (segment (start 176.6 62.5) (end 176.6 65.75) (width 0.254) (layer F.Cu) (net 18) (tstamp 54806BE2)) + (segment (start 176.6 65.75) (end 178.75 67.9) (width 0.254) (layer F.Cu) (net 18) (tstamp 54806BE9)) + (segment (start 175.4 60.83) (end 175.4 61.3) (width 0.254) (layer F.Cu) (net 18)) + (segment (start 176.95 74.3) (end 176.95 89.65) (width 0.254) (layer F.Cu) (net 18) (tstamp 548529BC)) + (segment (start 178.75 72.5) (end 176.95 74.3) (width 0.254) (layer F.Cu) (net 18) (tstamp 548529AA)) + (segment (start 176.95 89.65) (end 174.5 92.1) (width 0.254) (layer F.Cu) (net 18) (tstamp 548529CF)) + (segment (start 174.5 92.1) (end 165.898687 92.1) (width 0.254) (layer F.Cu) (net 18) (tstamp 54806C0E)) + (segment (start 175.4 60.83) (end 175.4 60.9) (width 0.254) (layer F.Cu) (net 18)) + (segment (start 174.29 103.42) (end 174.29 101.173) (width 0.254) (layer F.Cu) (net 19)) + (segment (start 175.768 99.695) (end 175.768 98.425) (width 0.254) (layer F.Cu) (net 19) (tstamp 56B4F730)) + (segment (start 174.29 101.173) (end 175.768 99.695) (width 0.254) (layer F.Cu) (net 19) (tstamp 56B4F729)) + (segment (start 166.61384 110.744) (end 170.942 110.744) (width 0.254) (layer B.Cu) (net 19)) + (segment (start 173.186 103.42) (end 174.29 103.42) (width 0.254) (layer B.Cu) (net 19) (tstamp 56B4F6D2)) + (segment (start 172.72 103.886) (end 173.186 103.42) (width 0.254) (layer B.Cu) (net 19) (tstamp 56B4F6D0)) + (segment (start 172.72 108.966) (end 172.72 103.886) (width 0.254) (layer B.Cu) (net 19) (tstamp 56B4F6CD)) + (segment (start 170.942 110.744) (end 172.72 108.966) (width 0.254) (layer B.Cu) (net 19) (tstamp 56B4F6B7)) + (segment (start 173 78.5) (end 175.7 78.5) (width 0.254) (layer B.Cu) (net 20)) + (segment (start 172.93 60.83) (end 172.86 60.83) (width 0.254) (layer B.Cu) (net 20)) + (via (at 173 78.5) (size 0.889) (layers F.Cu B.Cu) (net 20)) + (segment (start 179.3 62.9) (end 179.3 74.9) (width 0.254) (layer B.Cu) (net 20) (tstamp 54806C39)) + (segment (start 178.5 62.1) (end 179.3 62.9) (width 0.254) (layer B.Cu) (net 20) (tstamp 54806C32)) + (segment (start 174.2 62.1) (end 178.5 62.1) (width 0.254) (layer B.Cu) (net 20) (tstamp 54806C2C)) + (segment (start 172.93 60.83) (end 174.2 62.1) (width 0.254) (layer B.Cu) (net 20) (tstamp 54806C28)) + (segment (start 175.7 78.5) (end 179.3 74.9) (width 0.254) (layer B.Cu) (net 20) (tstamp 5488AF2A)) + (segment (start 149.7 64.65) (end 143.5 64.65) (width 0.254) (layer F.Cu) (net 20)) + (segment (start 173 78.5) (end 173.038 78.5) (width 0.254) (layer F.Cu) (net 20) (tstamp 54806C64)) + (segment (start 173.038 78.5) (end 173 78.5) (width 0.254) (layer F.Cu) (net 20) (tstamp 54806C65)) + (segment (start 173 78.5) (end 173.038 78.5) (width 0.254) (layer F.Cu) (net 20) (tstamp 54806C6B)) + (segment (start 172.86 60.83) (end 170.93 60.83) (width 0.254) (layer F.Cu) (net 20)) + (segment (start 143.5 62.7) (end 143.5 64.65) (width 0.254) (layer F.Cu) (net 20) (tstamp 548063F5)) + (segment (start 146.4 59.8) (end 143.5 62.7) (width 0.254) (layer F.Cu) (net 20) (tstamp 548063F4)) + (segment (start 169.9 59.8) (end 146.4 59.8) (width 0.254) (layer F.Cu) (net 20) (tstamp 548063F2)) + (segment (start 170.93 60.83) (end 169.9 59.8) (width 0.254) (layer F.Cu) (net 20) (tstamp 548063F1)) + (segment (start 173.038 76.5) (end 173.038 78.5) (width 0.254) (layer F.Cu) (net 20)) + (segment (start 173.038 78.5) (end 173.038 78.658527) (width 0.254) (layer F.Cu) (net 20) (tstamp 54806C6C)) + (segment (start 173.038 78.658527) (end 170.110761 81.585766) (width 0.254) (layer F.Cu) (net 20) (tstamp 548060CC)) + (segment (start 166.624 110.744) (end 168.148 110.744) (width 0.254) (layer F.Cu) (net 21)) + (segment (start 169.546801 80.897199) (end 169.546801 81.021806) (width 0.254) (layer F.Cu) (net 21) (tstamp 56B501E2)) + (segment (start 171.069 79.375) (end 169.546801 80.897199) (width 0.254) (layer F.Cu) (net 21) (tstamp 56B501E1)) + (via (at 171.069 79.375) (size 0.889) (layers F.Cu B.Cu) (net 21)) + (segment (start 167.513 82.931) (end 171.069 79.375) (width 0.254) (layer B.Cu) (net 21) (tstamp 56B501D0)) + (segment (start 167.513 87.376) (end 167.513 82.931) (width 0.254) (layer B.Cu) (net 21) (tstamp 56B501BB)) + (segment (start 168.91 88.773) (end 167.513 87.376) (width 0.254) (layer B.Cu) (net 21) (tstamp 56B501B3)) + (segment (start 168.91 109.728) (end 168.91 88.773) (width 0.254) (layer B.Cu) (net 21) (tstamp 56B50156)) + (segment (start 169.037 109.855) (end 168.91 109.728) (width 0.254) (layer B.Cu) (net 21) (tstamp 56B50155)) + (via (at 169.037 109.855) (size 0.889) (layers F.Cu B.Cu) (net 21)) + (segment (start 168.148 110.744) (end 169.037 109.855) (width 0.254) (layer F.Cu) (net 21) (tstamp 56B5014C)) + (segment (start 169.2 69.80414) (end 169.28682 69.89096) (width 0.254) (layer F.Cu) (net 22) (tstamp 547F87DF)) + (segment (start 155.4 72.7) (end 155.4 72.9) (width 0.254) (layer F.Cu) (net 22)) + (segment (start 164.2 79.637094) (end 165.02614 80.463234) (width 0.254) (layer F.Cu) (net 22) (tstamp 54805F94)) + (segment (start 164.2 76.1) (end 164.2 79.637094) (width 0.254) (layer F.Cu) (net 22) (tstamp 54805F8E)) + (segment (start 162.6 74.5) (end 164.2 76.1) (width 0.254) (layer F.Cu) (net 22) (tstamp 54805F85)) + (segment (start 157 74.5) (end 162.6 74.5) (width 0.254) (layer F.Cu) (net 22) (tstamp 54805F77)) + (segment (start 155.4 72.9) (end 157 74.5) (width 0.254) (layer F.Cu) (net 22) (tstamp 54805F65)) + (segment (start 155.4 72.7) (end 155.4 69.3) (width 0.254) (layer F.Cu) (net 22)) + (segment (start 156 65.3) (end 158 63.3) (width 0.254) (layer F.Cu) (net 22) (tstamp 547F895A)) + (segment (start 154.6 65.3) (end 156 65.3) (width 0.254) (layer F.Cu) (net 22) (tstamp 547F8953)) + (segment (start 153.8 66.1) (end 154.6 65.3) (width 0.254) (layer F.Cu) (net 22) (tstamp 547F8950)) + (segment (start 153.8 67.7) (end 153.8 66.1) (width 0.254) (layer F.Cu) (net 22) (tstamp 547F894B)) + (segment (start 155.4 69.3) (end 153.8 67.7) (width 0.254) (layer F.Cu) (net 22) (tstamp 547F893C)) + (segment (start 169.2 66.9) (end 169.2 66.7) (width 0.254) (layer F.Cu) (net 22)) + (segment (start 158 64.7) (end 158 63.3) (width 0.254) (layer F.Cu) (net 22) (tstamp 547F8849)) + (segment (start 159 65.7) (end 158 64.7) (width 0.254) (layer F.Cu) (net 22) (tstamp 547F8846)) + (segment (start 168.2 65.7) (end 159 65.7) (width 0.254) (layer F.Cu) (net 22) (tstamp 547F883A)) + (segment (start 169.2 66.7) (end 168.2 65.7) (width 0.254) (layer F.Cu) (net 22) (tstamp 547F8834)) + (segment (start 169.2 66.9) (end 169.2 69.80414) (width 0.254) (layer F.Cu) (net 22)) + (segment (start 168.021 108.712) (end 169.291 108.712) (width 0.254) (layer F.Cu) (net 23)) + (segment (start 167.894 112.522) (end 170.1165 110.2995) (width 0.254) (layer F.Cu) (net 23) (tstamp 56B4F69A)) + (segment (start 168.021 108.712) (end 168.021 108.712) (width 0.254) (layer B.Cu) (net 23) (tstamp 56B4F61E)) + (via (at 168.021 108.712) (size 0.889) (layers F.Cu B.Cu) (net 23)) + (segment (start 166.624 112.522) (end 167.894 112.522) (width 0.254) (layer F.Cu) (net 23)) + (segment (start 170.1165 109.5375) (end 170.1165 110.2995) (width 0.254) (layer F.Cu) (net 23) (tstamp 56B4FBB7)) + (segment (start 169.291 108.712) (end 170.1165 109.5375) (width 0.254) (layer F.Cu) (net 23) (tstamp 56B4FBAF)) + (segment (start 169.6 77.75) (end 170.2 77.75) (width 0.254) (layer B.Cu) (net 23) (tstamp 5495BBD2)) + (segment (start 169.6 77.75) (end 166.9 80.45) (width 0.254) (layer B.Cu) (net 23) (tstamp 5495BBF2)) + (segment (start 166.9 80.45) (end 166.9 87.778265) (width 0.254) (layer B.Cu) (net 23) (tstamp 5495BBF5)) + (segment (start 168.979248 80.454254) (end 168.995746 80.454254) (width 0.254) (layer F.Cu) (net 23)) + (segment (start 170.2 77.75) (end 170.2 77.75) (width 0.254) (layer B.Cu) (net 23) (tstamp 5495BBD1)) + (via (at 170.2 77.75) (size 0.889) (layers F.Cu B.Cu) (net 23)) + (segment (start 170.2 79.25) (end 170.2 77.75) (width 0.254) (layer F.Cu) (net 23) (tstamp 5495BBC7)) + (segment (start 168.995746 80.454254) (end 170.2 79.25) (width 0.254) (layer F.Cu) (net 23) (tstamp 5495BBB4)) + (segment (start 168.275 89.163078) (end 166.9 87.778265) (width 0.254) (layer B.Cu) (net 23) (tstamp 54BD421B)) + (segment (start 168.275 108.745) (end 168.275 89.163078) (width 0.254) (layer B.Cu) (net 23)) + (segment (start 161.05 82.144656) (end 162.197359 83.292015) (width 0.254) (layer F.Cu) (net 24) (tstamp 54BBDA56)) + (segment (start 161.05 80.3) (end 161.05 82.144656) (width 0.254) (layer F.Cu) (net 24) (tstamp 54BBDA4E)) + (segment (start 159.7 78.95) (end 161.05 80.3) (width 0.254) (layer F.Cu) (net 24) (tstamp 54BBDA48)) + (segment (start 158.9 78.95) (end 159.7 78.95) (width 0.254) (layer F.Cu) (net 24) (tstamp 54BBDA45)) + (segment (start 157.031631 78.218369) (end 157.031631 78.275996) (width 0.254) (layer F.Cu) (net 24)) + (segment (start 157.031631 78.275996) (end 158.312132 79.556497) (width 0.254) (layer F.Cu) (net 24) (tstamp 54BBDA72)) + (segment (start 158.312132 79.556497) (end 158.312132 79.537868) (width 0.254) (layer F.Cu) (net 24)) + (segment (start 158.312132 79.537868) (end 158.9 78.95) (width 0.254) (layer F.Cu) (net 24) (tstamp 54BBDA3F)) + (segment (start 156.481631 83.631631) (end 156.49974 83.631631) (width 0.254) (layer F.Cu) (net 25)) + (segment (start 156.49974 83.631631) (end 157.887868 82.243503) (width 0.254) (layer F.Cu) (net 25) (tstamp 54BBDA69)) + (segment (start 160.017335 82.243503) (end 161.631603 83.857771) (width 0.254) (layer F.Cu) (net 25) (tstamp 54BD75B1)) + (segment (start 161.473832 83.7) (end 161.631603 83.857771) (width 0.254) (layer F.Cu) (net 25) (tstamp 54805DFB)) + (segment (start 157.887868 82.243503) (end 160.017335 82.243503) (width 0.254) (layer F.Cu) (net 25)) + (segment (start 161.4 72.7) (end 161.4 74) (width 0.6) (layer B.Cu) (net 26)) + (via (at 154 97) (size 0.889) (layers F.Cu B.Cu) (net 26)) + (segment (start 161.818369 81.781513) (end 162.763115 82.726259) (width 0.254) (layer F.Cu) (net 26) (tstamp 54BBDDC6)) + (segment (start 161.35 72.7) (end 163.35 72.7) (width 0.6) (layer B.Cu) (net 26)) + (segment (start 172.74778 74.05) (end 174.36682 72.43096) (width 0.6) (layer B.Cu) (net 26) (tstamp 54BBD7D7)) + (segment (start 170.3 74.05) (end 172.74778 74.05) (width 0.6) (layer B.Cu) (net 26) (tstamp 54BBD7D1)) + (segment (start 168.8 75.55) (end 170.3 74.05) (width 0.6) (layer B.Cu) (net 26) (tstamp 54BBD7CE)) + (segment (start 166.2 75.55) (end 168.8 75.55) (width 0.6) (layer B.Cu) (net 26) (tstamp 54BBD7C4)) + (segment (start 163.35 72.7) (end 166.2 75.55) (width 0.6) (layer B.Cu) (net 26) (tstamp 54BBD7C0)) + (segment (start 162.763115 82.726259) (end 162.763115 82.763115) (width 0.254) (layer F.Cu) (net 26)) + (segment (start 164.9 83.2) (end 164.9 82.55) (width 0.254) (layer F.Cu) (net 26) (tstamp 548A05F3)) + (segment (start 164.3 83.8) (end 164.9 83.2) (width 0.254) (layer F.Cu) (net 26) (tstamp 548A05F0)) + (segment (start 163.8 83.8) (end 164.3 83.8) (width 0.254) (layer F.Cu) (net 26) (tstamp 548A05EE)) + (segment (start 162.763115 82.763115) (end 163.8 83.8) (width 0.254) (layer F.Cu) (net 26) (tstamp 548A05E8)) + (segment (start 151.024 99.976) (end 151.024 101.5) (width 0.6) (layer F.Cu) (net 26)) + (segment (start 154 97) (end 151.024 99.976) (width 0.6) (layer F.Cu) (net 26) (tstamp 5489E24A)) + (segment (start 151.024 101.5) (end 150.524 102) (width 0.6) (layer F.Cu) (net 26) (tstamp 5489E486)) + (segment (start 156.302 96) (end 155 96) (width 0.6) (layer F.Cu) (net 26)) + (segment (start 155 96) (end 154 97) (width 0.6) (layer F.Cu) (net 26) (tstamp 5489E169)) + (segment (start 168.187989 89.3) (end 168.187989 89.30184) (width 0.254) (layer F.Cu) (net 26)) + (segment (start 164.9 82.55) (end 167.7 85.35) (width 0.254) (layer F.Cu) (net 26) (tstamp 548A05F8)) + (segment (start 167.7 85.35) (end 168.425 85.35) (width 0.254) (layer F.Cu) (net 26) (tstamp 5480C3A8)) + (segment (start 168.425 85.35) (end 169.24231 86.330773) (width 0.254) (layer F.Cu) (net 26) (tstamp 5480C3AC)) + (segment (start 169.24231 86.330773) (end 169.200848 87.182555) (width 0.254) (layer F.Cu) (net 26) (tstamp 5480C3AF)) + (segment (start 169.200848 87.182555) (end 168.202429 88.097773) (width 0.254) (layer F.Cu) (net 26) (tstamp 5480C3B2)) + (segment (start 168.202429 88.097773) (end 168.187989 89.3) (width 0.254) (layer F.Cu) (net 26) (tstamp 5480C3B9)) + (segment (start 168.187989 89.30184) (end 168.957696 90.059536) (width 0.254) (layer F.Cu) (net 26) (tstamp 5481BA89)) + (segment (start 163.894627 81.594746) (end 163.894627 81.544627) (width 0.254) (layer F.Cu) (net 26)) + (segment (start 163.894627 81.544627) (end 164.9 82.55) (width 0.254) (layer F.Cu) (net 26) (tstamp 5480C399)) + (segment (start 177.94 63.37) (end 177.94 64.36) (width 0.6) (layer B.Cu) (net 26)) + (segment (start 177.94 64.36) (end 175.4 66.9) (width 0.6) (layer B.Cu) (net 26) (tstamp 548065C6)) + (segment (start 175.4 66.9) (end 173.2 66.9) (width 0.6) (layer B.Cu) (net 26) (tstamp 548065D0)) + (segment (start 174.562 74.5) (end 174.562 76.5) (width 0.254) (layer F.Cu) (net 26)) + (segment (start 174.36682 72.43096) (end 174.36682 74.30482) (width 0.254) (layer F.Cu) (net 26)) + (segment (start 174.36682 74.30482) (end 174.562 74.5) (width 0.254) (layer F.Cu) (net 26) (tstamp 548055C3)) + (segment (start 173.2 66.9) (end 174.9 66.9) (width 0.6) (layer F.Cu) (net 26)) + (segment (start 176.45 70.59778) (end 174.61682 72.43096) (width 0.6) (layer F.Cu) (net 26) (tstamp 547F8804)) + (segment (start 176.45 68.45) (end 176.45 70.59778) (width 0.6) (layer F.Cu) (net 26) (tstamp 547F87FF)) + (segment (start 174.9 66.9) (end 176.45 68.45) (width 0.6) (layer F.Cu) (net 26) (tstamp 547F87F7)) + (segment (start 159.3 75.95) (end 159.45 75.95) (width 0.6) (layer B.Cu) (net 26) (tstamp 54BBDFA7)) + (segment (start 160.2 76.85) (end 159.3 75.95) (width 0.6) (layer B.Cu) (net 26) (tstamp 54BBDFA3)) + (segment (start 161.4 74) (end 159.45 75.95) (width 0.6) (layer B.Cu) (net 26) (tstamp 54BBDF2D)) + (segment (start 151.95 89.8) (end 151.95 78.85) (width 0.6) (layer B.Cu) (net 26) (tstamp 54BBD6FD)) + (segment (start 159.45 75.95) (end 158.1 75.95) (width 0.6) (layer B.Cu) (net 26) (tstamp 54BBDF41)) + (segment (start 154.65 92.5) (end 151.95 89.8) (width 0.6) (layer B.Cu) (net 26)) + (segment (start 154.65 96.35) (end 154 97) (width 0.6) (layer B.Cu) (net 26) (tstamp 5489E258)) + (segment (start 154.65 96.35) (end 154.65 92.5) (width 0.6) (layer B.Cu) (net 26) (tstamp 5489E259)) + (segment (start 154.85 75.95) (end 158.1 75.95) (width 0.6) (layer B.Cu) (net 26) (tstamp 54BBD714)) + (segment (start 151.95 78.85) (end 154.85 75.95) (width 0.6) (layer B.Cu) (net 26) (tstamp 54BBD707)) + (segment (start 158.25 76.1) (end 158.1 76.1) (width 0.254) (layer B.Cu) (net 26) (tstamp 54BBDDF1)) + (segment (start 160.2 78.1) (end 160.2 76.85) (width 0.6) (layer B.Cu) (net 26)) + (via (at 160.2 78.1) (size 0.889) (layers F.Cu B.Cu) (net 26)) + (segment (start 161.681631 79.531631) (end 160.2 78.1) (width 0.254) (layer F.Cu) (net 26) (tstamp 54BBDDDC)) + (segment (start 161.818369 79.531631) (end 161.681631 79.531631) (width 0.254) (layer F.Cu) (net 26)) + (segment (start 161.818369 79.531631) (end 161.818369 81.781513) (width 0.254) (layer F.Cu) (net 26)) + (segment (start 171.069 92.964) (end 171.577 92.964) (width 0.254) (layer F.Cu) (net 27)) + (via (at 171.831 93.218) (size 0.889) (layers F.Cu B.Cu) (net 27)) + (segment (start 171.577 92.964) (end 171.831 93.218) (width 0.254) (layer F.Cu) (net 27) (tstamp 56B50F32)) + (segment (start 165.698 93.714) (end 169.049 93.714) (width 0.254) (layer F.Cu) (net 27)) + (segment (start 175.8 90.71) (end 175.8 88.1) (width 0.254) (layer B.Cu) (net 27) (tstamp 56B502E7)) + (segment (start 176.911 91.821) (end 175.8 90.71) (width 0.254) (layer B.Cu) (net 27) (tstamp 56B502E6)) + (via (at 176.911 91.821) (size 0.889) (layers F.Cu B.Cu) (net 27)) + (segment (start 175.768 92.964) (end 176.911 91.821) (width 0.254) (layer F.Cu) (net 27) (tstamp 56B502E0)) + (segment (start 169.799 92.964) (end 171.069 92.964) (width 0.254) (layer F.Cu) (net 27) (tstamp 56B502DA)) + (segment (start 171.069 92.964) (end 175.768 92.964) (width 0.254) (layer F.Cu) (net 27) (tstamp 56B50F30)) + (segment (start 169.049 93.714) (end 169.799 92.964) (width 0.254) (layer F.Cu) (net 27) (tstamp 56B502D7)) + (segment (start 156.756497 81.112132) (end 156.787868 81.112132) (width 0.254) (layer F.Cu) (net 27) (tstamp 54BD67AA)) + (segment (start 156.8 81.1) (end 156.787868 81.112132) (width 0.254) (layer F.Cu) (net 27) (tstamp 54BD67A9)) + (via (at 156.8 81.1) (size 0.381) (drill 0.254) (layers F.Cu B.Cu) (net 27)) + (segment (start 159.031371 81.1) (end 156.8 81.1) (width 0.254) (layer B.Cu) (net 27) (tstamp 54BD679E)) + (segment (start 159.031371 81.1) (end 159.443503 80.687868) (width 0.254) (layer B.Cu) (net 27) (tstamp 54BD679D)) + (segment (start 162.844815 78.455185) (end 162.910185 78.455185) (width 0.254) (layer F.Cu) (net 27)) + (segment (start 163.4 78.945) (end 163.4 80.1) (width 0.254) (layer F.Cu) (net 27) (tstamp 56B4CA1B)) + (segment (start 162.910185 78.455185) (end 163.4 78.945) (width 0.254) (layer F.Cu) (net 27) (tstamp 56B4CA00)) + (segment (start 153 106.55) (end 159 106.55) (width 0.4) (layer F.Cu) (net 27)) + (segment (start 169.75 104.3) (end 168.7493 104.3) (width 0.4) (layer F.Cu) (net 27)) + (segment (start 164.460384 81.02899) (end 164.52899 81.02899) (width 0.254) (layer F.Cu) (net 27)) + (segment (start 168.6 84.3) (end 168.6 84.1) (width 0.254) (layer B.Cu) (net 27) (tstamp 54BD6B2F)) + (segment (start 168.2 84.7) (end 168.6 84.3) (width 0.254) (layer B.Cu) (net 27) (tstamp 54BD6B2E)) + (via (at 168.2 84.7) (size 0.381) (drill 0.254) (layers F.Cu B.Cu) (net 27)) + (segment (start 164.52899 81.02899) (end 168.2 84.7) (width 0.254) (layer F.Cu) (net 27) (tstamp 54BD6B1D)) + (segment (start 154.6 74.5) (end 152.9 74.5) (width 0.254) (layer B.Cu) (net 27)) + (segment (start 157.4 72.9) (end 155.8 74.5) (width 0.4) (layer B.Cu) (net 27) (tstamp 5481AB53)) + (segment (start 155.8 74.5) (end 154.6 74.5) (width 0.4) (layer B.Cu) (net 27) (tstamp 5481AB66)) + (via (at 154.6 74.5) (size 0.889) (layers F.Cu B.Cu) (net 27)) + (segment (start 157.4 72.7) (end 157.4 72.9) (width 0.4) (layer B.Cu) (net 27)) + (segment (start 149.8 85.2) (end 149.8 87.4) (width 0.254) (layer B.Cu) (net 27) (tstamp 54947DE4)) + (via (at 149.8 85.2) (size 0.889) (layers F.Cu B.Cu) (net 27)) + (segment (start 149.8 77.6) (end 149.8 85.2) (width 0.254) (layer F.Cu) (net 27) (tstamp 54947DDA)) + (via (at 149.8 77.6) (size 0.889) (layers F.Cu B.Cu) (net 27)) + (segment (start 152.9 74.5) (end 149.8 77.6) (width 0.254) (layer B.Cu) (net 27) (tstamp 54947DCE)) + (segment (start 170.663944 88.353287) (end 170.853287 88.353287) (width 0.254) (layer F.Cu) (net 27)) + (segment (start 176.2 88.5) (end 176.2 89.3) (width 0.254) (layer B.Cu) (net 27) (tstamp 5481ADA8)) + (segment (start 175.8 88.1) (end 176.2 88.5) (width 0.254) (layer B.Cu) (net 27) (tstamp 5481ADA7)) + (via (at 175.8 88.1) (size 0.889) (layers F.Cu B.Cu) (net 27)) + (segment (start 175.8 88.5) (end 175.8 88.1) (width 0.254) (layer F.Cu) (net 27) (tstamp 5481ADA2)) + (segment (start 174.4 89.9) (end 175.8 88.5) (width 0.254) (layer F.Cu) (net 27) (tstamp 5481AD9E)) + (segment (start 172.2 89.9) (end 174.4 89.9) (width 0.254) (layer F.Cu) (net 27) (tstamp 5481AD99)) + (segment (start 170.653287 88.353287) (end 172.2 89.9) (width 0.254) (layer F.Cu) (net 27) (tstamp 5481AD92)) + (segment (start 164.460384 81.02899) (end 164.32899 81.02899) (width 0.254) (layer F.Cu) (net 27)) + (segment (start 164.32899 81.02899) (end 163.4 80.1) (width 0.254) (layer F.Cu) (net 27) (tstamp 5480ADE7)) + (segment (start 163.4 80.1) (end 163 80.1) (width 0.254) (layer F.Cu) (net 27) (tstamp 5480ADEE)) + (segment (start 162.334185 81.165816) (end 163.328871 82.160502) (width 0.254) (layer F.Cu) (net 27) (tstamp 5480AE03)) + (segment (start 163 80.1) (end 162.4 80.7) (width 0.254) (layer F.Cu) (net 27) (tstamp 5480ADF5)) + (segment (start 162.4 80.7) (end 162.334185 81.165816) (width 0.254) (layer F.Cu) (net 27) (tstamp 5480ADFE)) + (via (at 159.443503 80.687868) (size 0.381) (drill 0.254) (layers F.Cu B.Cu) (net 27)) + (segment (start 147.4 72.7) (end 149.4 72.7) (width 0.254) (layer F.Cu) (net 28)) + (segment (start 145.4 72.7) (end 145.4 72.5) (width 0.254) (layer F.Cu) (net 29)) + (segment (start 150 71.3) (end 151.4 72.7) (width 0.254) (layer F.Cu) (net 29) (tstamp 547F8A96)) + (segment (start 146.6 71.3) (end 150 71.3) (width 0.254) (layer F.Cu) (net 29) (tstamp 547F8A90)) + (segment (start 145.4 72.5) (end 146.6 71.3) (width 0.254) (layer F.Cu) (net 29) (tstamp 547F8A8A)) + (segment (start 165.1 112.522) (end 164.465 112.522) (width 0.254) (layer F.Cu) (net 30)) + (via (at 163.703 111.76) (size 0.889) (layers F.Cu B.Cu) (net 30)) + (segment (start 164.465 112.522) (end 163.703 111.76) (width 0.254) (layer F.Cu) (net 30) (tstamp 56B4F390)) + (segment (start 162.052 110.617) (end 162.56 110.617) (width 0.254) (layer B.Cu) (net 30)) + (segment (start 164.465 112.522) (end 165.11016 112.522) (width 0.254) (layer B.Cu) (net 30) (tstamp 56B4F2EF)) + (segment (start 162.56 110.617) (end 163.703 111.76) (width 0.254) (layer B.Cu) (net 30) (tstamp 56B4F2EB)) + (segment (start 163.703 111.76) (end 164.465 112.522) (width 0.254) (layer B.Cu) (net 30) (tstamp 56B4F39D)) + (segment (start 148.2 61.7) (end 151.038 61.7) (width 0.254) (layer F.Cu) (net 31)) + (segment (start 174.29 113.58) (end 168.825 113.58) (width 0.254) (layer B.Cu) (net 32)) + (segment (start 167.767 112.522) (end 166.61384 112.522) (width 0.254) (layer B.Cu) (net 32) (tstamp 56B4F4E1)) + (segment (start 168.825 113.58) (end 167.767 112.522) (width 0.254) (layer B.Cu) (net 32) (tstamp 56B4F4DD)) + (segment (start 162.052 113.157) (end 162.433 113.157) (width 0.254) (layer B.Cu) (net 33)) + (segment (start 163.576 114.3) (end 165.11016 114.3) (width 0.254) (layer B.Cu) (net 33) (tstamp 56B4F2FB)) + (segment (start 162.433 113.157) (end 163.576 114.3) (width 0.254) (layer B.Cu) (net 33) (tstamp 56B4F2F6)) + (segment (start 165.11016 110.744) (end 163.957 110.744) (width 0.254) (layer B.Cu) (net 34)) + (segment (start 163.957 110.744) (end 165.1 110.744) (width 0.254) (layer F.Cu) (net 34) (tstamp 56B5249A)) + (segment (start 163.703 110.49) (end 163.957 110.744) (width 0.254) (layer F.Cu) (net 34) (tstamp 56B52499)) + (via (at 163.703 110.49) (size 0.889) (layers F.Cu B.Cu) (net 34)) + (segment (start 163.957 110.744) (end 163.703 110.49) (width 0.254) (layer B.Cu) (net 34) (tstamp 56B5248D)) + (segment (start 177.927 99.695) (end 177.927 98.425) (width 0.254) (layer F.Cu) (net 35)) + (segment (start 169.926 107.696) (end 171.449884 107.711382) (width 0.254) (layer B.Cu) (net 35)) + (segment (start 166.61384 107.83316) (end 166.624 107.823) (width 0.254) (layer B.Cu) (net 35) (tstamp 56B4F8C7)) + (via (at 166.624 107.823) (size 0.889) (layers F.Cu B.Cu) (net 35)) + (segment (start 166.624 107.823) (end 166.751 107.696) (width 0.254) (layer F.Cu) (net 35) (tstamp 56B4F8D2)) + (segment (start 166.751 107.696) (end 169.926 107.696) (width 0.254) (layer F.Cu) (net 35) (tstamp 56B4F8D3)) + (via (at 169.926 107.696) (size 0.889) (layers F.Cu B.Cu) (net 35)) + (segment (start 166.61384 108.966) (end 166.61384 107.83316) (width 0.254) (layer B.Cu) (net 35)) + (segment (start 177.927 99.695) (end 177.997 99.765) (width 0.254) (layer F.Cu) (net 35) (tstamp 56B4F902)) + (via (at 177.927 99.695) (size 0.889) (layers F.Cu B.Cu) (net 35)) + (segment (start 175.26 99.695) (end 177.927 99.695) (width 0.254) (layer B.Cu) (net 35) (tstamp 56B4F8F6)) + (segment (start 172.085 102.87) (end 175.26 99.695) (width 0.254) (layer B.Cu) (net 35) (tstamp 56B4F8F0)) + (segment (start 172.085 107.092) (end 172.085 102.87) (width 0.254) (layer B.Cu) (net 35) (tstamp 56B4F8EA)) + (segment (start 171.4655 107.7115) (end 172.085 107.092) (width 0.254) (layer B.Cu) (net 35) (tstamp 56B4F8E9)) + (segment (start 174.29 105.96) (end 174.667 105.96) (width 0.254) (layer B.Cu) (net 36)) + (segment (start 167.894 114.3) (end 166.61384 114.3) (width 0.254) (layer B.Cu) (net 36) (tstamp 56B4F50E)) + (segment (start 168.656 115.062) (end 167.894 114.3) (width 0.254) (layer B.Cu) (net 36) (tstamp 56B4F50D)) + (segment (start 175.133 115.062) (end 168.656 115.062) (width 0.254) (layer B.Cu) (net 36) (tstamp 56B4F508)) + (segment (start 176.149 114.046) (end 175.133 115.062) (width 0.254) (layer B.Cu) (net 36) (tstamp 56B4F504)) + (segment (start 176.149 107.442) (end 176.149 114.046) (width 0.254) (layer B.Cu) (net 36) (tstamp 56B4F4FE)) + (segment (start 174.667 105.96) (end 176.149 107.442) (width 0.254) (layer B.Cu) (net 36) (tstamp 56B4F4FB)) + (segment (start 162.738 104.3) (end 167.386 104.267) (width 0.254) (layer F.Cu) (net 37)) + (segment (start 162.738 102.938) (end 162.738 104.3) (width 0.254) (layer F.Cu) (net 37) (tstamp 54BBF142)) + (segment (start 161.85 102.05) (end 162.738 102.938) (width 0.254) (layer F.Cu) (net 37) (tstamp 54BBF12C)) + (segment (start 153 102.05) (end 159 102.05) (width 0.4) (layer F.Cu) (net 37)) + (segment (start 159 102.05) (end 161.85 102.05) (width 0.254) (layer F.Cu) (net 37)) + (segment (start 171.69816 90.49816) (end 171.69816 91.15) (width 0.254) (layer F.Cu) (net 38) (tstamp 54BBE602)) + (segment (start 170.089208 88.928023) (end 170.128023 88.928023) (width 0.254) (layer F.Cu) (net 38)) + (segment (start 170.128023 88.928023) (end 171.69816 90.49816) (width 0.254) (layer F.Cu) (net 38) (tstamp 54BBE5FA)) + + (zone (net 27) (net_name GND) (layer B.Cu) (tstamp 53CC4087) (hatch edge 0.508) + (connect_pads (clearance 0.25)) + (min_thickness 0.254) + (fill (arc_segments 16) (thermal_gap 0.508) (thermal_bridge_width 0.508)) + (polygon + (pts + (xy 183.2 116.7) (xy 140.2 116.7) (xy 140.2 97.5) (xy 143.2 97.5) (xy 143.2 77.9) + (xy 140.4 77.8) (xy 140.4 58.7) (xy 183.2 58.5) (xy 183.2 78.1) (xy 180 78.1) + (xy 180 97.3) (xy 183.2 97.3) + ) + ) + (filled_polygon + (pts + (xy 174.371 97.960579) (xy 170.45579 101.87579) (xy 170.345669 102.040597) (xy 170.307 102.235) (xy 170.307 104.706806) + (xy 170.129105 104.854497) (xy 170.090923 104.838643) (xy 169.762518 104.838357) (xy 169.459002 104.963767) (xy 169.418 105.004697) + (xy 169.418 88.773) (xy 169.385746 88.610849) (xy 169.379331 88.578597) (xy 169.379331 88.578596) (xy 169.26921 88.41379) + (xy 168.330903 87.475483) (xy 168.513482 87.475643) (xy 168.816998 87.350233) (xy 169.049417 87.118219) (xy 169.175357 86.814923) + (xy 169.175591 86.546078) (xy 170.200953 85.527849) (xy 170.299767 85.766998) (xy 170.531781 85.999417) (xy 170.835077 86.125357) + (xy 171.163482 86.125643) (xy 171.466998 86.000233) (xy 171.659566 85.808) (xy 172.71958 85.808) (xy 174.225 87.31342) + (xy 174.225 88.642942) (xy 174.200233 88.583002) (xy 173.968219 88.350583) (xy 173.664923 88.224643) (xy 173.336518 88.224357) + (xy 173.033002 88.349767) (xy 172.800583 88.581781) (xy 172.674643 88.885077) (xy 172.674357 89.213482) (xy 172.799767 89.516998) + (xy 173.031781 89.749417) (xy 173.335077 89.875357) (xy 173.609 89.875595) (xy 173.609 93.853) (xy 173.647669 94.047403) + (xy 173.75779 94.21221) (xy 174.371 94.82542) (xy 174.371 97.960579) + ) + ) + (filled_polygon + (pts + (xy 175.641 113.835579) (xy 175.500787 113.975791) (xy 175.559778 113.833727) (xy 175.560219 113.32849) (xy 175.367281 112.861543) + (xy 175.010336 112.503975) (xy 174.889389 112.453753) (xy 175.097532 112.367539) (xy 175.18259 112.112195) (xy 174.29 111.219605) + (xy 174.110395 111.39921) (xy 174.110395 111.04) (xy 173.217805 110.14741) (xy 172.962461 110.232468) (xy 172.754486 110.801965) + (xy 172.780278 111.4077) (xy 172.962461 111.847532) (xy 173.217805 111.93259) (xy 174.110395 111.04) (xy 174.110395 111.39921) + (xy 173.39741 112.112195) (xy 173.482468 112.367539) (xy 173.70342 112.448228) (xy 173.571543 112.502719) (xy 173.213975 112.859664) + (xy 173.125805 113.072) (xy 169.03542 113.072) (xy 168.12621 112.16279) (xy 167.961403 112.052669) (xy 167.767 112.014) + (xy 167.444486 112.014) (xy 167.444486 111.946167) (xy 167.386604 111.806083) (xy 167.279521 111.698812) (xy 167.139538 111.640686) + (xy 166.987967 111.640554) (xy 166.088807 111.640554) (xy 165.948723 111.698436) (xy 165.861942 111.785064) (xy 165.775841 111.698812) + (xy 165.635858 111.640686) (xy 165.484287 111.640554) (xy 164.585127 111.640554) (xy 164.528584 111.663917) (xy 164.528638 111.602133) + (xy 164.584462 111.625314) (xy 164.736033 111.625446) (xy 165.635193 111.625446) (xy 165.775277 111.567564) (xy 165.862057 111.480935) + (xy 165.948159 111.567188) (xy 166.088142 111.625314) (xy 166.239713 111.625446) (xy 167.138873 111.625446) (xy 167.278957 111.567564) + (xy 167.386228 111.460481) (xy 167.444354 111.320498) (xy 167.444413 111.252) (xy 170.942 111.252) (xy 171.136403 111.213331) + (xy 171.30121 111.10321) (xy 173.07921 109.325211) (xy 173.07921 109.32521) (xy 173.15279 109.21509) (xy 173.18896 109.160957) + (xy 173.212719 109.218457) (xy 173.569664 109.576025) (xy 173.69061 109.626246) (xy 173.482468 109.712461) (xy 173.39741 109.967805) + (xy 174.29 110.860395) (xy 175.18259 109.967805) (xy 175.097532 109.712461) (xy 174.876579 109.631771) (xy 175.008457 109.577281) + (xy 175.366025 109.220336) (xy 175.559778 108.753727) (xy 175.560219 108.24849) (xy 175.367281 107.781543) (xy 175.010336 107.423975) + (xy 174.543727 107.230222) (xy 174.03849 107.229781) (xy 173.571543 107.422719) (xy 173.228 107.765663) (xy 173.228 106.693764) + (xy 173.569664 107.036025) (xy 174.036273 107.229778) (xy 174.54151 107.230219) (xy 175.008457 107.037281) (xy 175.017166 107.028586) + (xy 175.641 107.65242) (xy 175.641 110.289108) (xy 175.617539 110.232468) (xy 175.362195 110.14741) (xy 174.469605 111.04) + (xy 175.362195 111.93259) (xy 175.617539 111.847532) (xy 175.641 111.783288) (xy 175.641 113.835579) + ) + ) + (filled_polygon + (pts + (xy 178.792 74.689579) (xy 175.489579 77.992) (xy 173.659302 77.992) (xy 173.468219 77.800583) (xy 173.164923 77.674643) + (xy 172.836518 77.674357) (xy 172.533002 77.799767) (xy 172.300583 78.031781) (xy 172.174643 78.335077) (xy 172.174357 78.663482) + (xy 172.299767 78.966998) (xy 172.531781 79.199417) (xy 172.835077 79.325357) (xy 173.163482 79.325643) (xy 173.466998 79.200233) + (xy 173.659566 79.008) (xy 175.324596 79.008) (xy 168.460245 85.824595) (xy 168.186518 85.824357) (xy 168.021 85.892747) + (xy 168.021 83.14142) (xy 170.962013 80.200407) (xy 171.232482 80.200643) (xy 171.535998 80.075233) (xy 171.768417 79.843219) + (xy 171.894357 79.539923) (xy 171.894643 79.211518) (xy 171.769233 78.908002) (xy 171.537219 78.675583) (xy 171.233923 78.549643) + (xy 170.905518 78.549357) (xy 170.602002 78.674767) (xy 170.369583 78.906781) (xy 170.243643 79.210077) (xy 170.243406 79.482173) + (xy 167.408 82.317579) (xy 167.408 80.66042) (xy 169.675441 78.392979) (xy 169.731781 78.449417) (xy 170.035077 78.575357) + (xy 170.363482 78.575643) (xy 170.666998 78.450233) (xy 170.899417 78.218219) (xy 171.025357 77.914923) (xy 171.025643 77.586518) + (xy 170.900233 77.283002) (xy 170.775448 77.158) (xy 170.8 77.158) (xy 170.994403 77.119331) (xy 171.15921 77.00921) + (xy 171.41042 76.758) (xy 172.25 76.758) (xy 172.444403 76.719331) (xy 172.60921 76.60921) (xy 176.61042 72.608) + (xy 177.140697 72.608) (xy 177.331781 72.799417) (xy 177.635077 72.925357) (xy 177.963482 72.925643) (xy 178.266998 72.800233) + (xy 178.499417 72.568219) (xy 178.625357 72.264923) (xy 178.625643 71.936518) (xy 178.500233 71.633002) (xy 178.268219 71.400583) + (xy 177.964923 71.274643) (xy 177.636518 71.274357) (xy 177.333002 71.399767) (xy 177.140433 71.592) (xy 176.5 71.592) + (xy 176.4 71.592) (xy 176.35 71.592) (xy 176.155597 71.630669) (xy 175.99079 71.74079) (xy 175.890105 71.891474) + (xy 175.76393 72.017649) (xy 175.76393 70.527205) (xy 175.76393 69.254715) (xy 175.763709 69.002096) (xy 175.666833 68.768792) + (xy 175.488049 68.590319) (xy 175.254575 68.49385) (xy 174.65257 68.49396) (xy 174.49382 68.65271) (xy 174.49382 69.76396) + (xy 175.60507 69.76396) (xy 175.76382 69.60521) (xy 175.76393 69.254715) (xy 175.76393 70.527205) (xy 175.76382 70.17671) + (xy 175.60507 70.01796) (xy 174.49382 70.01796) (xy 174.49382 71.12921) (xy 174.65257 71.28796) (xy 175.254575 71.28807) + (xy 175.488049 71.191601) (xy 175.666833 71.013128) (xy 175.763709 70.779824) (xy 175.76393 70.527205) (xy 175.76393 72.017649) + (xy 175.509958 72.271621) (xy 175.510017 72.204601) (xy 175.336373 71.784349) (xy 175.015122 71.462537) (xy 174.595174 71.28816) + (xy 174.23982 71.287849) (xy 174.23982 71.12921) (xy 174.23982 70.01796) (xy 174.23982 69.76396) (xy 174.23982 68.65271) + (xy 174.08107 68.49396) (xy 173.479065 68.49385) (xy 173.245591 68.590319) (xy 173.066807 68.768792) (xy 172.969931 69.002096) + (xy 172.96971 69.254715) (xy 172.96982 69.60521) (xy 173.12857 69.76396) (xy 174.23982 69.76396) (xy 174.23982 70.01796) + (xy 173.12857 70.01796) (xy 172.970017 70.176513) (xy 172.970017 69.664601) (xy 172.796373 69.244349) (xy 172.475122 68.922537) + (xy 172.055174 68.74816) (xy 171.600461 68.747763) (xy 171.180209 68.921407) (xy 170.858397 69.242658) (xy 170.68402 69.662606) + (xy 170.683623 70.117319) (xy 170.857267 70.537571) (xy 171.178518 70.859383) (xy 171.598466 71.03376) (xy 172.053179 71.034157) + (xy 172.473431 70.860513) (xy 172.795243 70.539262) (xy 172.96962 70.119314) (xy 172.970017 69.664601) (xy 172.970017 70.176513) + (xy 172.96982 70.17671) (xy 172.96971 70.527205) (xy 172.969931 70.779824) (xy 173.066807 71.013128) (xy 173.245591 71.191601) + (xy 173.479065 71.28807) (xy 174.08107 71.28796) (xy 174.23982 71.12921) (xy 174.23982 71.287849) (xy 174.140461 71.287763) + (xy 173.720209 71.461407) (xy 173.398397 71.782658) (xy 173.22402 72.202606) (xy 173.223663 72.611037) (xy 172.823507 73.011192) + (xy 172.96962 72.659314) (xy 172.970017 72.204601) (xy 172.796373 71.784349) (xy 172.475122 71.462537) (xy 172.055174 71.28816) + (xy 171.600461 71.287763) (xy 171.180209 71.461407) (xy 170.858397 71.782658) (xy 170.68402 72.202606) (xy 170.683623 72.657319) + (xy 170.857267 73.077571) (xy 171.148187 73.369) (xy 170.430017 73.369) (xy 170.430017 72.204601) (xy 170.430017 69.664601) + (xy 170.256373 69.244349) (xy 169.935122 68.922537) (xy 169.515174 68.74816) (xy 169.060461 68.747763) (xy 168.640209 68.921407) + (xy 168.318397 69.242658) (xy 168.14402 69.662606) (xy 168.143623 70.117319) (xy 168.317267 70.537571) (xy 168.638518 70.859383) + (xy 169.058466 71.03376) (xy 169.513179 71.034157) (xy 169.933431 70.860513) (xy 170.255243 70.539262) (xy 170.42962 70.119314) + (xy 170.430017 69.664601) (xy 170.430017 72.204601) (xy 170.256373 71.784349) (xy 169.935122 71.462537) (xy 169.515174 71.28816) + (xy 169.060461 71.287763) (xy 168.640209 71.461407) (xy 168.318397 71.782658) (xy 168.14402 72.202606) (xy 168.143623 72.657319) + (xy 168.317267 73.077571) (xy 168.638518 73.399383) (xy 169.058466 73.57376) (xy 169.513179 73.574157) (xy 169.933431 73.400513) + (xy 170.255243 73.079262) (xy 170.42962 72.659314) (xy 170.430017 72.204601) (xy 170.430017 73.369) (xy 170.3 73.369) + (xy 170.039393 73.420838) (xy 169.81846 73.56846) (xy 169.818457 73.568463) (xy 169.168263 74.218657) (xy 169.050233 73.933002) + (xy 168.818219 73.700583) (xy 168.514923 73.574643) (xy 168.186518 73.574357) (xy 167.883002 73.699767) (xy 167.690433 73.892) + (xy 166.870475 73.892) (xy 166.525609 73.573766) (xy 166.973179 73.574157) (xy 167.393431 73.400513) (xy 167.715243 73.079262) + (xy 167.88962 72.659314) (xy 167.890017 72.204601) (xy 167.890017 69.664601) (xy 167.716373 69.244349) (xy 167.395122 68.922537) + (xy 166.975174 68.74816) (xy 166.520461 68.747763) (xy 166.100209 68.921407) (xy 165.778397 69.242658) (xy 165.60402 69.662606) + (xy 165.603623 70.117319) (xy 165.777267 70.537571) (xy 166.098518 70.859383) (xy 166.518466 71.03376) (xy 166.973179 71.034157) + (xy 167.393431 70.860513) (xy 167.715243 70.539262) (xy 167.88962 70.119314) (xy 167.890017 69.664601) (xy 167.890017 72.204601) + (xy 167.716373 71.784349) (xy 167.395122 71.462537) (xy 166.975174 71.28816) (xy 166.520461 71.287763) (xy 166.100209 71.461407) + (xy 165.778397 71.782658) (xy 165.60402 72.202606) (xy 165.603623 72.657319) (xy 165.647473 72.763446) (xy 163.991912 71.235737) + (xy 163.991912 67.871517) (xy 163.2 67.079605) (xy 162.408088 67.871517) (xy 162.476078 68.112458) (xy 162.99517 68.297198) + (xy 163.545446 68.269228) (xy 163.923922 68.112458) (xy 163.991912 67.871517) (xy 163.991912 71.235737) (xy 163.76534 71.026663) + (xy 163.689321 70.98017) (xy 163.615238 70.930669) (xy 163.60508 70.928648) (xy 163.596247 70.923246) (xy 163.508242 70.909386) + (xy 163.420835 70.892) (xy 159.7 70.892) (xy 159.505596 70.930669) (xy 159.34079 71.04079) (xy 159.04079 71.34079) + (xy 158.930669 71.505597) (xy 158.897813 71.670772) (xy 158.753389 71.730447) (xy 158.53863 71.944831) (xy 158.380212 71.899393) + (xy 158.200607 72.078998) (xy 158.200607 71.719788) (xy 158.131142 71.477604) (xy 157.607696 71.290857) (xy 157.052631 71.31864) + (xy 156.668858 71.477604) (xy 156.599393 71.719788) (xy 157.4 72.520395) (xy 158.200607 71.719788) (xy 158.200607 72.078998) + (xy 157.579605 72.7) (xy 158.380212 73.500607) (xy 158.538773 73.455127) (xy 158.751698 73.668423) (xy 159.171646 73.8428) + (xy 159.626359 73.843197) (xy 160.046611 73.669553) (xy 160.256934 73.459596) (xy 160.256934 73.537453) (xy 160.314816 73.677537) + (xy 160.421899 73.784808) (xy 160.561882 73.842934) (xy 160.593958 73.842961) (xy 159.16792 75.269) (xy 158.200607 75.269) + (xy 158.200607 73.680212) (xy 157.4 72.879605) (xy 156.599393 73.680212) (xy 156.668858 73.922396) (xy 157.192304 74.109143) + (xy 157.747369 74.08136) (xy 158.131142 73.922396) (xy 158.200607 73.680212) (xy 158.200607 75.269) (xy 158.1 75.269) + (xy 154.85 75.269) (xy 154.589393 75.320838) (xy 154.36846 75.46846) (xy 154.368457 75.468463) (xy 151.46846 78.36846) + (xy 151.320838 78.589392) (xy 151.269 78.85) (xy 151.269 89.8) (xy 151.320838 90.060608) (xy 151.46846 90.28154) + (xy 153.969 92.782079) (xy 153.969 96.06792) (xy 153.86254 96.174379) (xy 153.836518 96.174357) (xy 153.533002 96.299767) + (xy 153.325643 96.506764) (xy 153.325643 92.836518) (xy 153.200233 92.533002) (xy 152.968219 92.300583) (xy 152.664923 92.174643) + (xy 152.637698 92.174619) (xy 151.98154 91.51846) (xy 151.760608 91.370838) (xy 151.5 91.319) (xy 147.782079 91.319) + (xy 146.681 90.21792) (xy 146.681 77) (xy 146.629162 76.739393) (xy 146.629161 76.739392) (xy 146.48154 76.51846) + (xy 146.481536 76.518457) (xy 143.681 73.71792) (xy 143.681 71.282079) (xy 144.782079 70.181) (xy 150 70.181) + (xy 150.260607 70.129162) (xy 150.260608 70.129162) (xy 150.48154 69.98154) (xy 151.981536 68.481542) (xy 151.981539 68.48154) + (xy 151.98154 68.48154) (xy 152.129161 68.260608) (xy 152.129162 68.260607) (xy 152.181 68) (xy 152.181 65.782079) + (xy 152.637459 65.32562) (xy 152.663482 65.325643) (xy 152.966998 65.200233) (xy 153.199417 64.968219) (xy 153.325357 64.664923) + (xy 153.325643 64.336518) (xy 153.200233 64.033002) (xy 152.968219 63.800583) (xy 152.664923 63.674643) (xy 152.336518 63.674357) + (xy 152.033002 63.799767) (xy 151.800583 64.031781) (xy 151.674643 64.335077) (xy 151.674619 64.362301) (xy 151.01846 65.01846) + (xy 150.870838 65.239392) (xy 150.819 65.5) (xy 150.819 67.71792) (xy 149.71792 68.819) (xy 144.5 68.819) + (xy 144.239393 68.870838) (xy 144.01846 69.01846) (xy 144.018457 69.018463) (xy 142.51846 70.51846) (xy 142.370838 70.739392) + (xy 142.319 71) (xy 142.319 74) (xy 142.370838 74.260608) (xy 142.51846 74.48154) (xy 145.319 77.282079) + (xy 145.319 90.5) (xy 145.370838 90.760608) (xy 145.51846 90.98154) (xy 147.018457 92.481536) (xy 147.01846 92.48154) + (xy 147.239392 92.629161) (xy 147.239393 92.629162) (xy 147.5 92.681) (xy 151.21792 92.681) (xy 151.674379 93.137459) + (xy 151.674357 93.163482) (xy 151.799767 93.466998) (xy 152.031781 93.699417) (xy 152.335077 93.825357) (xy 152.663482 93.825643) + (xy 152.966998 93.700233) (xy 153.199417 93.468219) (xy 153.325357 93.164923) (xy 153.325643 92.836518) (xy 153.325643 96.506764) + (xy 153.300583 96.531781) (xy 153.174643 96.835077) (xy 153.174357 97.163482) (xy 153.299767 97.466998) (xy 153.531781 97.699417) + (xy 153.835077 97.825357) (xy 154.163482 97.825643) (xy 154.466998 97.700233) (xy 154.699417 97.468219) (xy 154.825357 97.164923) + (xy 154.82538 97.137698) (xy 155.131536 96.831542) (xy 155.131539 96.83154) (xy 155.13154 96.83154) (xy 155.279161 96.610608) + (xy 155.279162 96.610607) (xy 155.320688 96.401839) (xy 155.331 96.350001) (xy 155.330999 96.35) (xy 155.331 96.35) + (xy 155.331 92.5) (xy 155.279162 92.239393) (xy 155.279161 92.239392) (xy 155.13154 92.01846) (xy 155.131536 92.018457) + (xy 152.631 89.51792) (xy 152.631 79.132079) (xy 155.132079 76.631) (xy 158.1 76.631) (xy 159.01792 76.631) + (xy 159.519 77.13208) (xy 159.519 77.613396) (xy 159.500583 77.631781) (xy 159.374643 77.935077) (xy 159.374357 78.263482) + (xy 159.499767 78.566998) (xy 159.731781 78.799417) (xy 160.035077 78.925357) (xy 160.363482 78.925643) (xy 160.666998 78.800233) + (xy 160.899417 78.568219) (xy 161.025357 78.264923) (xy 161.025643 77.936518) (xy 160.900233 77.633002) (xy 160.881 77.613735) + (xy 160.881 76.85) (xy 160.829162 76.589393) (xy 160.829162 76.589392) (xy 160.68154 76.36846) (xy 160.338079 76.024999) + (xy 161.881536 74.481542) (xy 161.881539 74.48154) (xy 161.88154 74.48154) (xy 162.029161 74.260608) (xy 162.029162 74.260607) + (xy 162.081 74) (xy 162.081 73.843066) (xy 162.237453 73.843066) (xy 162.377537 73.785184) (xy 162.484808 73.678101) + (xy 162.542934 73.538118) (xy 162.543066 73.386547) (xy 162.543066 73.381) (xy 163.06792 73.381) (xy 165.611517 75.924596) + (xy 165.336518 75.924357) (xy 165.033002 76.049767) (xy 164.800583 76.281781) (xy 164.674643 76.585077) (xy 164.674406 76.857173) + (xy 163.04079 78.49079) (xy 162.930669 78.655597) (xy 162.892 78.85) (xy 162.892 84.640697) (xy 162.700583 84.831781) + (xy 162.574643 85.135077) (xy 162.574357 85.463482) (xy 162.699767 85.766998) (xy 162.931781 85.999417) (xy 163.235077 86.125357) + (xy 163.563482 86.125643) (xy 163.866998 86.000233) (xy 164.099417 85.768219) (xy 164.225357 85.464923) (xy 164.225643 85.136518) + (xy 164.100233 84.833002) (xy 163.908 84.640433) (xy 163.908 79.06042) (xy 165.393013 77.575407) (xy 165.663482 77.575643) + (xy 165.966998 77.450233) (xy 166.199417 77.218219) (xy 166.325357 76.914923) (xy 166.325643 76.586518) (xy 166.200233 76.283002) + (xy 166.135517 76.218173) (xy 166.2 76.231) (xy 168.561502 76.231) (xy 164.449032 80.160962) (xy 164.445664 80.165761) + (xy 164.44079 80.169019) (xy 164.388874 80.246716) (xy 164.3352 80.323228) (xy 164.333925 80.328951) (xy 164.330669 80.333826) + (xy 164.312437 80.425483) (xy 164.292131 80.516704) (xy 164.293143 80.522478) (xy 164.292 80.528229) (xy 164.292 86.340697) + (xy 164.100583 86.531781) (xy 163.974643 86.835077) (xy 163.974357 87.163482) (xy 164.099767 87.466998) (xy 164.331781 87.699417) + (xy 164.635077 87.825357) (xy 164.963482 87.825643) (xy 165.266998 87.700233) (xy 165.354 87.613382) (xy 165.354 90.594579) + (xy 156.61279 99.33579) (xy 156.502669 99.500597) (xy 156.464 99.695) (xy 156.464 108.317579) (xy 154.496348 110.285231) + (xy 154.496348 106.778632) (xy 154.469939 106.188601) (xy 154.294952 105.766144) (xy 154.230843 105.745673) (xy 154.230843 101.806287) + (xy 154.043885 101.353815) (xy 153.698006 101.007331) (xy 153.245861 100.819585) (xy 152.756287 100.819157) (xy 152.303815 101.006115) + (xy 151.957331 101.351994) (xy 151.769585 101.804139) (xy 151.769157 102.293713) (xy 151.956115 102.746185) (xy 152.301994 103.092669) + (xy 152.754139 103.280415) (xy 153.243713 103.280843) (xy 153.696185 103.093885) (xy 154.042669 102.748006) (xy 154.230415 102.295861) + (xy 154.230843 101.806287) (xy 154.230843 105.745673) (xy 154.04369 105.685916) (xy 153.864084 105.865521) (xy 153.864084 105.50631) + (xy 153.783856 105.255048) (xy 153.228632 105.053652) (xy 152.638601 105.080061) (xy 152.216144 105.255048) (xy 152.135916 105.50631) + (xy 153 106.370395) (xy 153.864084 105.50631) (xy 153.864084 105.865521) (xy 153.179605 106.55) (xy 154.04369 107.414084) + (xy 154.294952 107.333856) (xy 154.496348 106.778632) (xy 154.496348 110.285231) (xy 153.864084 110.917495) (xy 153.864084 107.59369) + (xy 153 106.729605) (xy 152.820395 106.90921) (xy 152.820395 106.55) (xy 151.95631 105.685916) (xy 151.705048 105.766144) + (xy 151.503652 106.321368) (xy 151.516799 106.61511) (xy 151.454199 106.463606) (xy 151.108216 106.117018) (xy 150.655935 105.929215) + (xy 150.166213 105.928787) (xy 149.713606 106.115801) (xy 149.367018 106.461784) (xy 149.179215 106.914065) (xy 149.178787 107.403787) + (xy 149.365801 107.856394) (xy 149.711784 108.202982) (xy 149.91215 108.286181) (xy 149.62592 108.404742) (xy 149.545648 108.656043) + (xy 150.41 109.520395) (xy 151.274352 108.656043) (xy 151.19408 108.404742) (xy 150.888937 108.29405) (xy 151.106394 108.204199) + (xy 151.452982 107.858216) (xy 151.640785 107.405935) (xy 151.640983 107.179189) (xy 151.705048 107.333856) (xy 151.95631 107.414084) + (xy 152.820395 106.55) (xy 152.820395 106.90921) (xy 152.135916 107.59369) (xy 152.216144 107.844952) (xy 152.771368 108.046348) + (xy 153.361399 108.019939) (xy 153.783856 107.844952) (xy 153.864084 107.59369) (xy 153.864084 110.917495) (xy 153.049579 111.732) + (xy 151.906717 111.732) (xy 151.906717 109.928721) (xy 151.880314 109.338543) (xy 151.705258 108.91592) (xy 151.453957 108.835648) + (xy 150.589605 109.7) (xy 151.453957 110.564352) (xy 151.705258 110.48408) (xy 151.906717 109.928721) (xy 151.906717 111.732) + (xy 151.532042 111.732) (xy 151.454199 111.543606) (xy 151.108216 111.197018) (xy 150.907849 111.113818) (xy 151.19408 110.995258) + (xy 151.274352 110.743957) (xy 150.41 109.879605) (xy 150.230395 110.05921) (xy 150.230395 109.7) (xy 149.366043 108.835648) + (xy 149.114742 108.91592) (xy 148.913283 109.471279) (xy 148.939686 110.061457) (xy 149.114742 110.48408) (xy 149.366043 110.564352) + (xy 150.230395 109.7) (xy 150.230395 110.05921) (xy 149.545648 110.743957) (xy 149.62592 110.995258) (xy 149.931062 111.105949) + (xy 149.713606 111.195801) (xy 149.367018 111.541784) (xy 149.179215 111.994065) (xy 149.178787 112.483787) (xy 149.365801 112.936394) + (xy 149.711784 113.282982) (xy 150.164065 113.470785) (xy 150.653787 113.471213) (xy 151.106394 113.284199) (xy 151.452982 112.938216) + (xy 151.531966 112.748) (xy 153.26 112.748) (xy 153.454403 112.709331) (xy 153.61921 112.59921) (xy 157.33121 108.887211) + (xy 157.33121 108.88721) (xy 157.40479 108.77709) (xy 157.44133 108.722404) (xy 157.441331 108.722403) (xy 157.479999 108.528001) + (xy 157.48 108.528) (xy 157.48 105.23942) (xy 157.882789 105.64221) (xy 157.88279 105.64221) (xy 157.950822 105.687668) + (xy 157.705048 105.766144) (xy 157.503652 106.321368) (xy 157.530061 106.911399) (xy 157.705048 107.333856) (xy 157.95631 107.414084) + (xy 158.820395 106.55) (xy 158.806252 106.535857) (xy 158.985857 106.356252) (xy 159 106.370395) (xy 159.014142 106.356252) + (xy 159.193747 106.535857) (xy 159.179605 106.55) (xy 160.04369 107.414084) (xy 160.294952 107.333856) (xy 160.496348 106.778632) + (xy 160.47488 106.299) (xy 160.630697 106.299) (xy 160.821781 106.490417) (xy 161.125077 106.616357) (xy 161.453482 106.616643) + (xy 161.756998 106.491233) (xy 161.989417 106.259219) (xy 162.115357 105.955923) (xy 162.115643 105.627518) (xy 161.990233 105.324002) + (xy 161.758219 105.091583) (xy 161.454923 104.965643) (xy 161.126518 104.965357) (xy 160.823002 105.090767) (xy 160.630433 105.283) + (xy 160.23042 105.283) (xy 159.87121 104.92379) (xy 159.706403 104.813669) (xy 159.512 104.775) (xy 158.45242 104.775) + (xy 158.115 104.437579) (xy 158.115 102.905347) (xy 158.301994 103.092669) (xy 158.754139 103.280415) (xy 159.243713 103.280843) + (xy 159.696185 103.093885) (xy 160.042669 102.748006) (xy 160.230415 102.295861) (xy 160.230843 101.806287) (xy 160.043885 101.353815) + (xy 159.698006 101.007331) (xy 159.245861 100.819585) (xy 158.756287 100.819157) (xy 158.303815 101.006115) (xy 158.115 101.1946) + (xy 158.115 100.54042) (xy 165.730024 92.925396) (xy 166.013482 92.925643) (xy 166.316998 92.800233) (xy 166.549417 92.568219) + (xy 166.675357 92.264923) (xy 166.675643 91.936518) (xy 166.550233 91.633002) (xy 166.318219 91.400583) (xy 166.082653 91.302767) + (xy 166.22121 91.164211) (xy 166.22121 91.16421) (xy 166.29479 91.05409) (xy 166.33133 90.999404) (xy 166.331331 90.999403) + (xy 166.369999 90.805) (xy 166.37 90.805) (xy 166.37 88.011) (xy 166.456281 88.011) (xy 166.485185 88.054257) + (xy 166.539538 88.136219) (xy 167.767 89.37228) (xy 167.767 107.923758) (xy 167.554002 108.011767) (xy 167.358359 108.207068) + (xy 167.449357 107.987923) (xy 167.449643 107.659518) (xy 167.324233 107.356002) (xy 167.092219 107.123583) (xy 166.788923 106.997643) + (xy 166.460518 106.997357) (xy 166.157002 107.122767) (xy 165.924583 107.354781) (xy 165.862001 107.505493) (xy 165.800233 107.356002) + (xy 165.568219 107.123583) (xy 165.264923 106.997643) (xy 164.936518 106.997357) (xy 164.633002 107.122767) (xy 164.400583 107.354781) + (xy 164.274643 107.658077) (xy 164.274357 107.986482) (xy 164.369821 108.217525) (xy 164.337772 108.249519) (xy 164.279646 108.389502) + (xy 164.279514 108.541073) (xy 164.279514 109.541833) (xy 164.337396 109.681917) (xy 164.444479 109.789188) (xy 164.584462 109.847314) + (xy 164.736033 109.847446) (xy 165.635193 109.847446) (xy 165.775277 109.789564) (xy 165.862057 109.702935) (xy 165.948159 109.789188) + (xy 166.088142 109.847314) (xy 166.239713 109.847446) (xy 167.138873 109.847446) (xy 167.278957 109.789564) (xy 167.386228 109.682481) + (xy 167.444354 109.542498) (xy 167.444486 109.390927) (xy 167.444486 109.302932) (xy 167.552781 109.411417) (xy 167.856077 109.537357) + (xy 168.184482 109.537643) (xy 168.293673 109.492526) (xy 168.211643 109.690077) (xy 168.211357 110.018482) (xy 168.301233 110.236) + (xy 167.444486 110.236) (xy 167.444486 110.168167) (xy 167.386604 110.028083) (xy 167.279521 109.920812) (xy 167.139538 109.862686) + (xy 166.987967 109.862554) (xy 166.088807 109.862554) (xy 165.948723 109.920436) (xy 165.861942 110.007064) (xy 165.775841 109.920812) + (xy 165.635858 109.862686) (xy 165.484287 109.862554) (xy 164.585127 109.862554) (xy 164.445043 109.920436) (xy 164.372818 109.992534) + (xy 164.171219 109.790583) (xy 163.867923 109.664643) (xy 163.539518 109.664357) (xy 163.236002 109.789767) (xy 163.031339 109.994073) + (xy 163.021553 109.970389) (xy 162.700302 109.648577) (xy 162.280354 109.4742) (xy 161.825641 109.473803) (xy 161.405389 109.647447) + (xy 161.083577 109.968698) (xy 160.9092 110.388646) (xy 160.908803 110.843359) (xy 161.082447 111.263611) (xy 161.403698 111.585423) + (xy 161.823646 111.7598) (xy 162.278359 111.760197) (xy 162.698611 111.586553) (xy 162.754921 111.530341) (xy 162.877592 111.653012) + (xy 162.877357 111.923482) (xy 162.919894 112.02643) (xy 162.890118 112.014066) (xy 162.738547 112.013934) (xy 161.214547 112.013934) + (xy 161.074463 112.071816) (xy 160.967192 112.178899) (xy 160.909066 112.318882) (xy 160.908934 112.470453) (xy 160.908934 113.994453) + (xy 160.966816 114.134537) (xy 161.073899 114.241808) (xy 161.213882 114.299934) (xy 161.365453 114.300066) (xy 162.857646 114.300066) + (xy 163.21679 114.65921) (xy 163.381596 114.769331) (xy 163.381597 114.769331) (xy 163.576 114.808) (xy 164.279514 114.808) + (xy 164.279514 114.875833) (xy 164.337396 115.015917) (xy 164.444479 115.123188) (xy 164.584462 115.181314) (xy 164.736033 115.181446) + (xy 165.635193 115.181446) (xy 165.775277 115.123564) (xy 165.862057 115.036935) (xy 165.948159 115.123188) (xy 166.088142 115.181314) + (xy 166.239713 115.181446) (xy 167.138873 115.181446) (xy 167.278957 115.123564) (xy 167.386228 115.016481) (xy 167.444354 114.876498) + (xy 167.444413 114.808) (xy 167.683579 114.808) (xy 168.296789 115.42121) (xy 168.29679 115.42121) (xy 168.374298 115.473) + (xy 159.864084 115.473) (xy 159.864084 107.59369) (xy 159 106.729605) (xy 158.135916 107.59369) (xy 158.216144 107.844952) + (xy 158.771368 108.046348) (xy 159.361399 108.019939) (xy 159.783856 107.844952) (xy 159.864084 107.59369) (xy 159.864084 115.473) + (xy 159.563412 115.473) (xy 159.563412 111.944468) (xy 159.20169 111.069034) (xy 158.532489 110.398664) (xy 157.657688 110.035415) + (xy 156.710468 110.034588) (xy 155.835034 110.39631) (xy 155.164664 111.065511) (xy 154.801415 111.940312) (xy 154.800588 112.887532) + (xy 155.16231 113.762966) (xy 155.831511 114.433336) (xy 156.706312 114.796585) (xy 157.653532 114.797412) (xy 158.528966 114.43569) + (xy 159.199336 113.766489) (xy 159.562585 112.891688) (xy 159.563412 111.944468) (xy 159.563412 115.473) (xy 144.286717 115.473) + (xy 144.286717 109.928721) (xy 144.260314 109.338543) (xy 144.085258 108.91592) (xy 143.833957 108.835648) (xy 142.969605 109.7) + (xy 143.833957 110.564352) (xy 144.085258 110.48408) (xy 144.286717 109.928721) (xy 144.286717 115.473) (xy 141.627 115.473) + (xy 141.627 112.648874) (xy 141.745801 112.936394) (xy 142.091784 113.282982) (xy 142.544065 113.470785) (xy 143.033787 113.471213) + (xy 143.486394 113.284199) (xy 143.832982 112.938216) (xy 144.020785 112.485935) (xy 144.021213 111.996213) (xy 143.834199 111.543606) + (xy 143.488216 111.197018) (xy 143.287849 111.113818) (xy 143.57408 110.995258) (xy 143.654352 110.743957) (xy 142.79 109.879605) + (xy 141.925648 110.743957) (xy 142.00592 110.995258) (xy 142.311062 111.105949) (xy 142.093606 111.195801) (xy 141.747018 111.541784) + (xy 141.627 111.83082) (xy 141.627 110.526326) (xy 141.746043 110.564352) (xy 142.610395 109.7) (xy 141.746043 108.835648) + (xy 141.627 108.873673) (xy 141.627 108.235738) (xy 141.723899 108.332808) (xy 141.863882 108.390934) (xy 142.015453 108.391066) + (xy 142.038936 108.391066) (xy 142.00592 108.404742) (xy 141.925648 108.656043) (xy 142.79 109.520395) (xy 143.654352 108.656043) + (xy 143.57408 108.404742) (xy 143.536379 108.391066) (xy 143.715453 108.391066) (xy 143.855537 108.333184) (xy 143.962808 108.226101) + (xy 144.020934 108.086118) (xy 144.021066 107.934547) (xy 144.021066 106.234547) (xy 143.963184 106.094463) (xy 143.856101 105.987192) + (xy 143.716118 105.929066) (xy 143.564547 105.928934) (xy 141.864547 105.928934) (xy 141.724463 105.986816) (xy 141.627 106.084108) + (xy 141.627 98.577) (xy 144 98.577) (xy 144.163406 98.544497) (xy 144.301935 98.451935) (xy 144.394497 98.313406) + (xy 144.427 98.15) (xy 144.427 77.3) (xy 144.394497 77.136594) (xy 144.301935 76.998065) (xy 144.163406 76.905503) + (xy 144 76.873) (xy 141.627 76.873) (xy 141.627 62.600741) (xy 142.412049 62.445298) (xy 142.56603 62.381675) + (xy 142.569424 62.378286) (xy 143.518169 61.743158) (xy 143.522884 61.74121) (xy 143.640795 61.623503) (xy 144.28111 60.667013) + (xy 144.345003 60.513144) (xy 144.345007 60.508348) (xy 144.499718 59.727) (xy 172.536356 59.727) (xy 172.213389 59.860447) + (xy 171.891577 60.181698) (xy 171.7172 60.601646) (xy 171.716803 61.056359) (xy 171.890447 61.476611) (xy 172.211698 61.798423) + (xy 172.631646 61.9728) (xy 172.825706 61.972969) (xy 172.512631 61.98864) (xy 172.128858 62.147604) (xy 172.059393 62.389788) + (xy 172.86 63.190395) (xy 172.874142 63.176252) (xy 173.053747 63.355857) (xy 173.039605 63.37) (xy 173.840212 64.170607) + (xy 174.082396 64.101142) (xy 174.259852 63.603738) (xy 174.430447 64.016611) (xy 174.751698 64.338423) (xy 175.171646 64.5128) + (xy 175.626359 64.513197) (xy 176.046611 64.339553) (xy 176.368423 64.018302) (xy 176.5428 63.598354) (xy 176.543197 63.143641) + (xy 176.369553 62.723389) (xy 176.254365 62.608) (xy 177.085473 62.608) (xy 176.971577 62.721698) (xy 176.7972 63.141646) + (xy 176.796803 63.596359) (xy 176.970447 64.016611) (xy 177.145225 64.191695) (xy 175.11792 66.219) (xy 174.331066 66.219) + (xy 174.331066 66.074547) (xy 174.273184 65.934463) (xy 174.166101 65.827192) (xy 174.026118 65.769066) (xy 173.874547 65.768934) + (xy 173.660607 65.768934) (xy 173.660607 64.350212) (xy 172.86 63.549605) (xy 172.680395 63.72921) (xy 172.680395 63.37) + (xy 171.879788 62.569393) (xy 171.637604 62.638858) (xy 171.450857 63.162304) (xy 171.47864 63.717369) (xy 171.637604 64.101142) + (xy 171.879788 64.170607) (xy 172.680395 63.37) (xy 172.680395 63.72921) (xy 172.059393 64.350212) (xy 172.128858 64.592396) + (xy 172.652304 64.779143) (xy 173.207369 64.75136) (xy 173.591142 64.592396) (xy 173.660607 64.350212) (xy 173.660607 65.768934) + (xy 172.374547 65.768934) (xy 172.234463 65.826816) (xy 172.127192 65.933899) (xy 172.069066 66.073882) (xy 172.068982 66.169627) + (xy 171.841496 65.941744) (xy 171.425957 65.769197) (xy 170.976017 65.768805) (xy 170.560177 65.940626) (xy 170.241744 66.258504) + (xy 170.20011 66.358767) (xy 170.159374 66.260177) (xy 169.841496 65.941744) (xy 169.425957 65.769197) (xy 168.976017 65.768805) + (xy 168.560177 65.940626) (xy 168.241744 66.258504) (xy 168.20011 66.358767) (xy 168.159374 66.260177) (xy 167.841496 65.941744) + (xy 167.708 65.886311) (xy 167.708 65.1) (xy 167.675746 64.937849) (xy 167.669331 64.905597) (xy 167.669331 64.905596) + (xy 167.55921 64.74079) (xy 167.55921 64.740789) (xy 165.75921 62.94079) (xy 165.594403 62.830669) (xy 165.4 62.792) + (xy 165.013841 62.792) (xy 164.959374 62.660177) (xy 164.641496 62.341744) (xy 164.541232 62.30011) (xy 164.639823 62.259374) + (xy 164.958256 61.941496) (xy 165.130803 61.525957) (xy 165.131195 61.076017) (xy 164.959374 60.660177) (xy 164.641496 60.341744) + (xy 164.225957 60.169197) (xy 163.776017 60.168805) (xy 163.360177 60.340626) (xy 163.041744 60.658504) (xy 163.00011 60.758767) + (xy 162.959374 60.660177) (xy 162.641496 60.341744) (xy 162.225957 60.169197) (xy 161.776017 60.168805) (xy 161.360177 60.340626) + (xy 161.143739 60.556686) (xy 160.971517 60.508088) (xy 160.791912 60.687693) (xy 160.791912 60.328483) (xy 160.723922 60.087542) + (xy 160.20483 59.902802) (xy 159.654554 59.930772) (xy 159.276078 60.087542) (xy 159.208088 60.328483) (xy 160 61.120395) + (xy 160.791912 60.328483) (xy 160.791912 60.687693) (xy 160.179605 61.3) (xy 160.971517 62.091912) (xy 161.143892 62.04327) + (xy 161.358504 62.258256) (xy 161.458767 62.299889) (xy 161.360177 62.340626) (xy 161.143739 62.556686) (xy 160.971517 62.508088) + (xy 160.791912 62.687693) (xy 160.791912 62.328483) (xy 160.783874 62.3) (xy 160.791912 62.271517) (xy 160.769517 62.249122) + (xy 160.723922 62.087542) (xy 160.543851 62.023456) (xy 160 61.479605) (xy 159.474076 62.005528) (xy 159.276078 62.087542) + (xy 159.230482 62.249122) (xy 159.208088 62.271517) (xy 159.216125 62.3) (xy 159.208088 62.328483) (xy 159.230482 62.350877) + (xy 159.276078 62.512458) (xy 159.456148 62.576543) (xy 160 63.120395) (xy 160.525923 62.594471) (xy 160.723922 62.512458) + (xy 160.769517 62.350877) (xy 160.791912 62.328483) (xy 160.791912 62.687693) (xy 160.179605 63.3) (xy 160.193747 63.314142) + (xy 160.014142 63.493747) (xy 160 63.479605) (xy 159.208088 64.271517) (xy 159.242086 64.392) (xy 158.318842 64.392) + (xy 158.639823 64.259374) (xy 158.85626 64.043313) (xy 159.028483 64.091912) (xy 159.820395 63.3) (xy 159.028483 62.508088) + (xy 158.856107 62.556729) (xy 158.641496 62.341744) (xy 158.541232 62.30011) (xy 158.639823 62.259374) (xy 158.85626 62.043313) + (xy 159.028483 62.091912) (xy 159.820395 61.3) (xy 159.028483 60.508088) (xy 158.856107 60.556729) (xy 158.641496 60.341744) + (xy 158.225957 60.169197) (xy 157.776017 60.168805) (xy 157.360177 60.340626) (xy 157.131066 60.569337) (xy 157.131066 60.474547) + (xy 157.073184 60.334463) (xy 156.966101 60.227192) (xy 156.826118 60.169066) (xy 156.674547 60.168934) (xy 155.174547 60.168934) + (xy 155.034463 60.226816) (xy 154.927192 60.333899) (xy 154.869066 60.473882) (xy 154.868934 60.625453) (xy 154.868934 62.125453) + (xy 154.926816 62.265537) (xy 155.033899 62.372808) (xy 155.173882 62.430934) (xy 155.269627 62.431017) (xy 155.041744 62.658504) + (xy 154.869197 63.074043) (xy 154.868805 63.523983) (xy 155.040626 63.939823) (xy 155.358504 64.258256) (xy 155.680595 64.392) + (xy 154.2 64.392) (xy 154.037849 64.424253) (xy 154.005596 64.430669) (xy 153.84079 64.54079) (xy 152.64079 65.74079) + (xy 152.530669 65.905597) (xy 152.492 66.1) (xy 152.492 71.99138) (xy 152.431577 72.051698) (xy 152.400138 72.127411) + (xy 152.369553 72.053389) (xy 152.048302 71.731577) (xy 151.628354 71.5572) (xy 151.173641 71.556803) (xy 150.753389 71.730447) + (xy 150.431577 72.051698) (xy 150.400138 72.127411) (xy 150.369553 72.053389) (xy 150.048302 71.731577) (xy 149.628354 71.5572) + (xy 149.173641 71.556803) (xy 148.753389 71.730447) (xy 148.431577 72.051698) (xy 148.400138 72.127411) (xy 148.369553 72.053389) + (xy 148.048302 71.731577) (xy 147.628354 71.5572) (xy 147.173641 71.556803) (xy 146.753389 71.730447) (xy 146.431577 72.051698) + (xy 146.400138 72.127411) (xy 146.369553 72.053389) (xy 146.048302 71.731577) (xy 145.628354 71.5572) (xy 145.173641 71.556803) + (xy 144.753389 71.730447) (xy 144.431577 72.051698) (xy 144.2572 72.471646) (xy 144.256803 72.926359) (xy 144.430447 73.346611) + (xy 144.751698 73.668423) (xy 145.171646 73.8428) (xy 145.626359 73.843197) (xy 146.046611 73.669553) (xy 146.368423 73.348302) + (xy 146.399861 73.272588) (xy 146.430447 73.346611) (xy 146.751698 73.668423) (xy 147.171646 73.8428) (xy 147.626359 73.843197) + (xy 148.046611 73.669553) (xy 148.368423 73.348302) (xy 148.399861 73.272588) (xy 148.430447 73.346611) (xy 148.751698 73.668423) + (xy 149.171646 73.8428) (xy 149.626359 73.843197) (xy 150.046611 73.669553) (xy 150.368423 73.348302) (xy 150.399861 73.272588) + (xy 150.430447 73.346611) (xy 150.751698 73.668423) (xy 151.171646 73.8428) (xy 151.626359 73.843197) (xy 152.046611 73.669553) + (xy 152.368423 73.348302) (xy 152.399861 73.272588) (xy 152.430447 73.346611) (xy 152.751698 73.668423) (xy 153.171646 73.8428) + (xy 153.626359 73.843197) (xy 154.046611 73.669553) (xy 154.368423 73.348302) (xy 154.399861 73.272588) (xy 154.430447 73.346611) + (xy 154.751698 73.668423) (xy 155.171646 73.8428) (xy 155.626359 73.843197) (xy 156.046611 73.669553) (xy 156.261369 73.455168) + (xy 156.419788 73.500607) (xy 157.220395 72.7) (xy 156.419788 71.899393) (xy 156.261226 71.944872) (xy 156.048302 71.731577) + (xy 155.628354 71.5572) (xy 155.173641 71.556803) (xy 154.753389 71.730447) (xy 154.431577 72.051698) (xy 154.400138 72.127411) + (xy 154.369553 72.053389) (xy 154.048302 71.731577) (xy 153.628354 71.5572) (xy 153.508 71.557094) (xy 153.508 71.115913) + (xy 153.549767 71.216998) (xy 153.781781 71.449417) (xy 154.085077 71.575357) (xy 154.413482 71.575643) (xy 154.716998 71.450233) + (xy 154.909566 71.258) (xy 157.25 71.258) (xy 157.256192 71.256768) (xy 157.262412 71.257848) (xy 157.353163 71.237479) + (xy 157.444403 71.219331) (xy 157.449652 71.215823) (xy 157.455812 71.214441) (xy 157.531874 71.160884) (xy 157.60921 71.10921) + (xy 157.612716 71.103961) (xy 157.617879 71.100327) (xy 159.569027 69.05142) (xy 159.653004 68.918837) (xy 159.669331 68.894403) + (xy 159.66972 68.892446) (xy 159.675088 68.883972) (xy 159.700369 68.738361) (xy 159.708 68.7) (xy 159.708 68.694412) + (xy 159.708995 68.688682) (xy 159.708 68.684248) (xy 159.708 67.913841) (xy 159.839823 67.859374) (xy 160.158256 67.541496) + (xy 160.199889 67.441232) (xy 160.240626 67.539823) (xy 160.558504 67.858256) (xy 160.974043 68.030803) (xy 161.423983 68.031195) + (xy 161.839823 67.859374) (xy 162.05626 67.643313) (xy 162.228483 67.691912) (xy 163.020395 66.9) (xy 162.228483 66.108088) + (xy 162.056107 66.156729) (xy 161.841496 65.941744) (xy 161.425957 65.769197) (xy 160.976017 65.768805) (xy 160.560177 65.940626) + (xy 160.241744 66.258504) (xy 160.20011 66.358767) (xy 160.159374 66.260177) (xy 159.841496 65.941744) (xy 159.425957 65.769197) + (xy 158.976017 65.768805) (xy 158.560177 65.940626) (xy 158.241744 66.258504) (xy 158.20011 66.358767) (xy 158.159374 66.260177) + (xy 157.841496 65.941744) (xy 157.425957 65.769197) (xy 156.976017 65.768805) (xy 156.560177 65.940626) (xy 156.241744 66.258504) + (xy 156.20011 66.358767) (xy 156.159374 66.260177) (xy 155.841496 65.941744) (xy 155.425957 65.769197) (xy 154.976017 65.768805) + (xy 154.560177 65.940626) (xy 154.241744 66.258504) (xy 154.069197 66.674043) (xy 154.068805 67.123983) (xy 154.240626 67.539823) + (xy 154.558504 67.858256) (xy 154.974043 68.030803) (xy 155.423983 68.031195) (xy 155.839823 67.859374) (xy 156.158256 67.541496) + (xy 156.199889 67.441232) (xy 156.240626 67.539823) (xy 156.558504 67.858256) (xy 156.974043 68.030803) (xy 157.423983 68.031195) + (xy 157.839823 67.859374) (xy 158.158256 67.541496) (xy 158.199889 67.441232) (xy 158.240626 67.539823) (xy 158.558504 67.858256) + (xy 158.692 67.913688) (xy 158.692 68.499112) (xy 157.03227 70.242) (xy 154.909302 70.242) (xy 154.718219 70.050583) + (xy 154.414923 69.924643) (xy 154.086518 69.924357) (xy 153.783002 70.049767) (xy 153.550583 70.281781) (xy 153.508 70.384331) + (xy 153.508 66.31042) (xy 154.41042 65.408) (xy 160.4 65.408) (xy 160.594403 65.369331) (xy 160.75921 65.25921) + (xy 161.642315 64.376104) (xy 161.774043 64.430803) (xy 162.223983 64.431195) (xy 162.639823 64.259374) (xy 162.958256 63.941496) + (xy 162.999889 63.841232) (xy 163.040626 63.939823) (xy 163.358504 64.258256) (xy 163.774043 64.430803) (xy 164.223983 64.431195) + (xy 164.639823 64.259374) (xy 164.958256 63.941496) (xy 165.013688 63.808) (xy 165.189579 63.808) (xy 166.692 65.31042) + (xy 166.692 65.886158) (xy 166.560177 65.940626) (xy 166.241744 66.258504) (xy 166.20011 66.358767) (xy 166.159374 66.260177) + (xy 165.841496 65.941744) (xy 165.425957 65.769197) (xy 164.976017 65.768805) (xy 164.560177 65.940626) (xy 164.343739 66.156686) + (xy 164.171517 66.108088) (xy 163.991912 66.287693) (xy 163.991912 65.928483) (xy 163.923922 65.687542) (xy 163.40483 65.502802) + (xy 162.854554 65.530772) (xy 162.476078 65.687542) (xy 162.408088 65.928483) (xy 163.2 66.720395) (xy 163.991912 65.928483) + (xy 163.991912 66.287693) (xy 163.379605 66.9) (xy 164.171517 67.691912) (xy 164.343892 67.64327) (xy 164.558504 67.858256) + (xy 164.974043 68.030803) (xy 165.423983 68.031195) (xy 165.839823 67.859374) (xy 166.158256 67.541496) (xy 166.199889 67.441232) + (xy 166.240626 67.539823) (xy 166.558504 67.858256) (xy 166.974043 68.030803) (xy 167.423983 68.031195) (xy 167.839823 67.859374) + (xy 168.158256 67.541496) (xy 168.199889 67.441232) (xy 168.240626 67.539823) (xy 168.558504 67.858256) (xy 168.974043 68.030803) + (xy 169.423983 68.031195) (xy 169.839823 67.859374) (xy 170.158256 67.541496) (xy 170.199889 67.441232) (xy 170.240626 67.539823) + (xy 170.558504 67.858256) (xy 170.974043 68.030803) (xy 171.423983 68.031195) (xy 171.839823 67.859374) (xy 172.068934 67.630662) + (xy 172.068934 67.725453) (xy 172.126816 67.865537) (xy 172.233899 67.972808) (xy 172.373882 68.030934) (xy 172.525453 68.031066) + (xy 174.025453 68.031066) (xy 174.165537 67.973184) (xy 174.272808 67.866101) (xy 174.330934 67.726118) (xy 174.33106 67.581) + (xy 175.4 67.581) (xy 175.660607 67.529162) (xy 175.660608 67.529162) (xy 175.88154 67.38154) (xy 178.421536 64.841542) + (xy 178.421539 64.84154) (xy 178.42154 64.84154) (xy 178.569161 64.620608) (xy 178.569162 64.620607) (xy 178.621 64.36) + (xy 178.621 64.305223) (xy 178.792 64.134522) (xy 178.792 74.689579) + ) + ) + (filled_polygon + (pts + (xy 181.873 115.473) (xy 179.370219 115.473) (xy 179.370219 113.32849) (xy 179.370219 110.78849) (xy 179.370219 108.24849) + (xy 179.370219 105.70849) (xy 179.370219 103.16849) (xy 179.177281 102.701543) (xy 178.820336 102.343975) (xy 178.353727 102.150222) + (xy 177.84849 102.149781) (xy 177.381543 102.342719) (xy 177.023975 102.699664) (xy 176.830222 103.166273) (xy 176.829781 103.67151) + (xy 177.022719 104.138457) (xy 177.379664 104.496025) (xy 177.846273 104.689778) (xy 178.35151 104.690219) (xy 178.818457 104.497281) + (xy 179.176025 104.140336) (xy 179.369778 103.673727) (xy 179.370219 103.16849) (xy 179.370219 105.70849) (xy 179.177281 105.241543) + (xy 178.820336 104.883975) (xy 178.353727 104.690222) (xy 177.84849 104.689781) (xy 177.381543 104.882719) (xy 177.023975 105.239664) + (xy 176.830222 105.706273) (xy 176.829781 106.21151) (xy 177.022719 106.678457) (xy 177.379664 107.036025) (xy 177.846273 107.229778) + (xy 178.35151 107.230219) (xy 178.818457 107.037281) (xy 179.176025 106.680336) (xy 179.369778 106.213727) (xy 179.370219 105.70849) + (xy 179.370219 108.24849) (xy 179.177281 107.781543) (xy 178.820336 107.423975) (xy 178.353727 107.230222) (xy 177.84849 107.229781) + (xy 177.381543 107.422719) (xy 177.023975 107.779664) (xy 176.830222 108.246273) (xy 176.829781 108.75151) (xy 177.022719 109.218457) + (xy 177.379664 109.576025) (xy 177.846273 109.769778) (xy 178.35151 109.770219) (xy 178.818457 109.577281) (xy 179.176025 109.220336) + (xy 179.369778 108.753727) (xy 179.370219 108.24849) (xy 179.370219 110.78849) (xy 179.177281 110.321543) (xy 178.820336 109.963975) + (xy 178.353727 109.770222) (xy 177.84849 109.769781) (xy 177.381543 109.962719) (xy 177.023975 110.319664) (xy 176.830222 110.786273) + (xy 176.829781 111.29151) (xy 177.022719 111.758457) (xy 177.379664 112.116025) (xy 177.846273 112.309778) (xy 178.35151 112.310219) + (xy 178.818457 112.117281) (xy 179.176025 111.760336) (xy 179.369778 111.293727) (xy 179.370219 110.78849) (xy 179.370219 113.32849) + (xy 179.177281 112.861543) (xy 178.820336 112.503975) (xy 178.353727 112.310222) (xy 177.84849 112.309781) (xy 177.381543 112.502719) + (xy 177.023975 112.859664) (xy 176.830222 113.326273) (xy 176.829781 113.83151) (xy 177.022719 114.298457) (xy 177.379664 114.656025) + (xy 177.846273 114.849778) (xy 178.35151 114.850219) (xy 178.818457 114.657281) (xy 179.176025 114.300336) (xy 179.369778 113.833727) + (xy 179.370219 113.32849) (xy 179.370219 115.473) (xy 175.414701 115.473) (xy 175.49221 115.42121) (xy 176.50821 114.405211) + (xy 176.50821 114.40521) (xy 176.58179 114.29509) (xy 176.61833 114.240404) (xy 176.618331 114.240403) (xy 176.656999 114.046001) + (xy 176.657 114.046) (xy 176.657 107.442) (xy 176.618331 107.247597) (xy 176.61833 107.247596) (xy 176.58179 107.19291) + (xy 176.50821 107.08279) (xy 176.50821 107.082789) (xy 175.559847 106.134426) (xy 175.560219 105.70849) (xy 175.367281 105.241543) + (xy 175.010336 104.883975) (xy 174.543727 104.690222) (xy 174.365003 104.690066) (xy 175.254453 104.690066) (xy 175.394537 104.632184) + (xy 175.501808 104.525101) (xy 175.559934 104.385118) (xy 175.560066 104.233547) (xy 175.560066 102.455547) (xy 175.502184 102.315463) + (xy 175.395101 102.208192) (xy 175.255118 102.150066) (xy 175.103547 102.149934) (xy 173.523486 102.149934) (xy 175.47042 100.203) + (xy 177.267697 100.203) (xy 177.458781 100.394417) (xy 177.762077 100.520357) (xy 178.090482 100.520643) (xy 178.393998 100.395233) + (xy 178.626417 100.163219) (xy 178.752357 99.859923) (xy 178.752643 99.531518) (xy 178.627233 99.228002) (xy 178.395219 98.995583) + (xy 178.091923 98.869643) (xy 177.763518 98.869357) (xy 177.460002 98.994767) (xy 177.267433 99.187) (xy 175.59742 99.187) + (xy 176.12721 98.65721) (xy 176.237331 98.492404) (xy 176.237331 98.492403) (xy 176.276 98.298) (xy 176.276 96.290302) + (xy 176.467417 96.099219) (xy 176.593357 95.795923) (xy 176.593643 95.467518) (xy 176.468233 95.164002) (xy 176.276 94.971433) + (xy 176.276 94.615) (xy 176.237331 94.420597) (xy 176.12721 94.25579) (xy 175.241 93.36958) (xy 175.241 87.103) + (xy 175.202331 86.908597) (xy 175.09221 86.74379) (xy 173.28921 84.94079) (xy 173.124403 84.830669) (xy 172.93 84.792) + (xy 171.659302 84.792) (xy 171.468219 84.600583) (xy 171.23305 84.502932) (xy 180.151609 75.64642) (xy 180.20921 75.607933) + (xy 180.319331 75.443126) (xy 180.358 75.248723) (xy 180.358 62.15) (xy 180.357999 62.149999) (xy 180.336249 62.040651) + (xy 180.913844 62.427318) (xy 181.067713 62.49121) (xy 181.072583 62.491214) (xy 181.873 62.6497) (xy 181.873 76.873) + (xy 179.5 76.873) (xy 179.336594 76.905503) (xy 179.198065 76.998065) (xy 179.105503 77.136594) (xy 179.073 77.3) + (xy 179.073 98.15) (xy 179.105503 98.313406) (xy 179.198065 98.451935) (xy 179.336594 98.544497) (xy 179.5 98.577) + (xy 181.873 98.577) (xy 181.873 115.473) + ) + ) + ) + (zone (net 27) (net_name GND) (layer F.Cu) (tstamp 53CC4087) (hatch edge 0.508) + (connect_pads (clearance 0.25)) + (min_thickness 0.254) + (fill (arc_segments 16) (thermal_gap 0.508) (thermal_bridge_width 0.508)) + (polygon + (pts + (xy 183.2 116.7) (xy 140.2 116.7) (xy 140.2 97.5) (xy 143.2 97.5) (xy 143.2 77.9) + (xy 140.4 77.9) (xy 140.4 58.7) (xy 183.2 58.7) (xy 183.2 78.1) (xy 180 78.1) + (xy 180 97.3) (xy 183.2 97.3) + ) + ) + (filled_polygon + (pts + (xy 144.992 110.889579) (xy 144.286717 111.594862) (xy 144.286717 109.928721) (xy 144.260314 109.338543) (xy 144.085258 108.91592) + (xy 143.833957 108.835648) (xy 142.969605 109.7) (xy 143.833957 110.564352) (xy 144.085258 110.48408) (xy 144.286717 109.928721) + (xy 144.286717 111.594862) (xy 144.149579 111.732) (xy 143.912042 111.732) (xy 143.834199 111.543606) (xy 143.488216 111.197018) + (xy 143.287849 111.113818) (xy 143.57408 110.995258) (xy 143.654352 110.743957) (xy 142.79 109.879605) (xy 141.925648 110.743957) + (xy 142.00592 110.995258) (xy 142.311062 111.105949) (xy 142.093606 111.195801) (xy 141.747018 111.541784) (xy 141.627 111.83082) + (xy 141.627 110.526326) (xy 141.746043 110.564352) (xy 142.610395 109.7) (xy 141.746043 108.835648) (xy 141.627 108.873673) + (xy 141.627 108.235738) (xy 141.723899 108.332808) (xy 141.863882 108.390934) (xy 142.015453 108.391066) (xy 142.038936 108.391066) + (xy 142.00592 108.404742) (xy 141.925648 108.656043) (xy 142.79 109.520395) (xy 143.654352 108.656043) (xy 143.57408 108.404742) + (xy 143.536379 108.391066) (xy 143.715453 108.391066) (xy 143.855537 108.333184) (xy 143.962808 108.226101) (xy 144.020934 108.086118) + (xy 144.021066 107.934547) (xy 144.021066 107.651875) (xy 144.134403 107.629331) (xy 144.29921 107.51921) (xy 144.992 106.82642) + (xy 144.992 110.889579) + ) + ) + (filled_polygon + (pts + (xy 160.542 82.049747) (xy 160.376545 81.884293) (xy 160.211738 81.774172) (xy 160.114724 81.754874) (xy 160.114724 81.538694) + (xy 159.443503 80.867473) (xy 159.42936 80.881615) (xy 159.249755 80.70201) (xy 159.263898 80.687868) (xy 159.249755 80.673725) + (xy 159.42936 80.49412) (xy 159.443503 80.508263) (xy 159.457645 80.49412) (xy 159.63725 80.673725) (xy 159.623108 80.687868) + (xy 160.294329 81.359089) (xy 160.518836 81.359089) (xy 160.542 81.335934) (xy 160.542 82.049747) + ) + ) + (filled_polygon + (pts + (xy 162.825946 90.408) (xy 162.591947 90.642) (xy 147.927112 90.642) (xy 147.915622 90.639777) (xy 147.721424 90.679463) + (xy 147.557196 90.790445) (xy 144.590473 93.788399) (xy 144.481217 93.953781) (xy 144.443566 94.148384) (xy 144.450109 94.180405) + (xy 144.429564 105.952014) (xy 144.021066 106.360513) (xy 144.021066 106.234547) (xy 143.963184 106.094463) (xy 143.856101 105.987192) + (xy 143.716118 105.929066) (xy 143.564547 105.928934) (xy 141.864547 105.928934) (xy 141.724463 105.986816) (xy 141.627 106.084108) + (xy 141.627 98.577) (xy 144 98.577) (xy 144.163406 98.544497) (xy 144.301935 98.451935) (xy 144.394497 98.313406) + (xy 144.427 98.15) (xy 144.427 77.3) (xy 144.394497 77.136594) (xy 144.301935 76.998065) (xy 144.163406 76.905503) + (xy 144 76.873) (xy 141.627 76.873) (xy 141.627 62.600741) (xy 142.412049 62.445298) (xy 142.56603 62.381675) + (xy 142.569424 62.378286) (xy 143.518169 61.743158) (xy 143.522884 61.74121) (xy 143.640795 61.623503) (xy 144.28111 60.667013) + (xy 144.345003 60.513144) (xy 144.345007 60.508348) (xy 144.499718 59.727) (xy 145.75458 59.727) (xy 143.14079 62.34079) + (xy 143.030669 62.505597) (xy 142.992 62.7) (xy 142.992 63.718934) (xy 142.524547 63.718934) (xy 142.384463 63.776816) + (xy 142.277192 63.883899) (xy 142.219066 64.023882) (xy 142.218934 64.175453) (xy 142.218934 65.275453) (xy 142.276816 65.415537) + (xy 142.383899 65.522808) (xy 142.523882 65.580934) (xy 142.675453 65.581066) (xy 144.475453 65.581066) (xy 144.615537 65.523184) + (xy 144.722808 65.416101) (xy 144.780934 65.276118) (xy 144.781036 65.158) (xy 148.418934 65.158) (xy 148.418934 65.275453) + (xy 148.476816 65.415537) (xy 148.583899 65.522808) (xy 148.723882 65.580934) (xy 148.875453 65.581066) (xy 150.675453 65.581066) + (xy 150.815537 65.523184) (xy 150.922808 65.416101) (xy 150.980934 65.276118) (xy 150.981066 65.124547) (xy 150.981066 64.024547) + (xy 150.923184 63.884463) (xy 150.816101 63.777192) (xy 150.676118 63.719066) (xy 150.524547 63.718934) (xy 148.724547 63.718934) + (xy 148.584463 63.776816) (xy 148.477192 63.883899) (xy 148.419066 64.023882) (xy 148.418963 64.142) (xy 146.5237 64.142) + (xy 146.5237 62.57503) (xy 146.5237 61.827) (xy 145.77567 61.827) (xy 145.61692 61.98575) (xy 145.61681 61.973025) + (xy 145.617031 62.225644) (xy 145.713907 62.458948) (xy 145.892691 62.637421) (xy 146.126165 62.73389) (xy 146.36495 62.73378) + (xy 146.5237 62.57503) (xy 146.5237 64.142) (xy 144.781066 64.142) (xy 144.781066 64.024547) (xy 144.723184 63.884463) + (xy 144.616101 63.777192) (xy 144.476118 63.719066) (xy 144.324547 63.718934) (xy 144.008 63.718934) (xy 144.008 62.91042) + (xy 145.616919 61.3015) (xy 145.61681 61.426975) (xy 145.61692 61.41425) (xy 145.77567 61.573) (xy 146.5237 61.573) + (xy 146.5237 60.82497) (xy 146.36495 60.66622) (xy 146.252251 60.666168) (xy 146.61042 60.308) (xy 154.953136 60.308) + (xy 154.927192 60.333899) (xy 154.869066 60.473882) (xy 154.868934 60.625453) (xy 154.868934 61.119) (xy 153.260566 61.119) + (xy 153.260566 61.053047) (xy 153.202684 60.912963) (xy 153.095601 60.805692) (xy 152.955618 60.747566) (xy 152.804047 60.747434) + (xy 152.169047 60.747434) (xy 152.028963 60.805316) (xy 151.921692 60.912399) (xy 151.863566 61.052382) (xy 151.863434 61.203953) + (xy 151.863434 62.346953) (xy 151.881 62.389465) (xy 151.881 63.951504) (xy 151.800583 64.031781) (xy 151.736566 64.18595) + (xy 151.736566 62.196047) (xy 151.736566 61.053047) (xy 151.678684 60.912963) (xy 151.571601 60.805692) (xy 151.431618 60.747566) + (xy 151.280047 60.747434) (xy 150.645047 60.747434) (xy 150.504963 60.805316) (xy 150.397692 60.912399) (xy 150.339566 61.052382) + (xy 150.339444 61.192) (xy 148.915193 61.192) (xy 148.871264 61.085683) (xy 148.764181 60.978412) (xy 148.624198 60.920286) + (xy 148.472627 60.920154) (xy 147.675067 60.920154) (xy 147.592911 60.9541) (xy 147.587493 60.941052) (xy 147.408709 60.762579) + (xy 147.175235 60.66611) (xy 146.93645 60.66622) (xy 146.7777 60.82497) (xy 146.7777 61.573) (xy 146.7977 61.573) + (xy 146.7977 61.827) (xy 146.7777 61.827) (xy 146.7777 62.57503) (xy 146.93645 62.73378) (xy 147.175235 62.73389) + (xy 147.408709 62.637421) (xy 147.587493 62.458948) (xy 147.592919 62.445879) (xy 147.674402 62.479714) (xy 147.825973 62.479846) + (xy 148.623533 62.479846) (xy 148.763617 62.421964) (xy 148.870888 62.314881) (xy 148.915268 62.208) (xy 150.339434 62.208) + (xy 150.339434 62.346953) (xy 150.397316 62.487037) (xy 150.504399 62.594308) (xy 150.644382 62.652434) (xy 150.795953 62.652566) + (xy 151.430953 62.652566) (xy 151.571037 62.594684) (xy 151.678308 62.487601) (xy 151.736434 62.347618) (xy 151.736566 62.196047) + (xy 151.736566 64.18595) (xy 151.674643 64.335077) (xy 151.674357 64.663482) (xy 151.799767 64.966998) (xy 152.031781 65.199417) + (xy 152.335077 65.325357) (xy 152.663482 65.325643) (xy 152.966998 65.200233) (xy 153.199417 64.968219) (xy 153.325357 64.664923) + (xy 153.325643 64.336518) (xy 153.243 64.136506) (xy 153.243 62.389603) (xy 153.260434 62.347618) (xy 153.260492 62.281) + (xy 154.942251 62.281) (xy 155.033899 62.372808) (xy 155.173882 62.430934) (xy 155.269627 62.431017) (xy 155.041744 62.658504) + (xy 154.869197 63.074043) (xy 154.868814 63.512764) (xy 152.89079 65.49079) (xy 152.780669 65.655597) (xy 152.742 65.85) + (xy 152.742 68.539579) (xy 151.589579 69.692) (xy 151.23511 69.692) (xy 151.23511 68.774245) (xy 151.23511 67.925755) + (xy 151.234889 67.673136) (xy 151.138013 67.439832) (xy 150.959229 67.261359) (xy 150.725755 67.16489) (xy 149.98575 67.165) + (xy 149.827 67.32375) (xy 149.827 68.223) (xy 151.07625 68.223) (xy 151.235 68.06425) (xy 151.23511 67.925755) + (xy 151.23511 68.774245) (xy 151.235 68.63575) (xy 151.07625 68.477) (xy 149.827 68.477) (xy 149.827 69.37625) + (xy 149.98575 69.535) (xy 150.725755 69.53511) (xy 150.959229 69.438641) (xy 151.138013 69.260168) (xy 151.234889 69.026864) + (xy 151.23511 68.774245) (xy 151.23511 69.692) (xy 149.573 69.692) (xy 149.573 69.37625) (xy 149.573 68.477) + (xy 149.573 68.223) (xy 149.573 67.32375) (xy 149.41425 67.165) (xy 148.674245 67.16489) (xy 148.440771 67.261359) + (xy 148.261987 67.439832) (xy 148.165111 67.673136) (xy 148.16489 67.925755) (xy 148.165 68.06425) (xy 148.32375 68.223) + (xy 149.573 68.223) (xy 149.573 68.477) (xy 148.32375 68.477) (xy 148.165 68.63575) (xy 148.16489 68.774245) + (xy 148.165111 69.026864) (xy 148.261987 69.260168) (xy 148.440771 69.438641) (xy 148.674245 69.53511) (xy 149.41425 69.535) + (xy 149.573 69.37625) (xy 149.573 69.692) (xy 145.03511 69.692) (xy 145.03511 68.774245) (xy 145.03511 67.925755) + (xy 145.034889 67.673136) (xy 144.938013 67.439832) (xy 144.759229 67.261359) (xy 144.525755 67.16489) (xy 143.78575 67.165) + (xy 143.627 67.32375) (xy 143.627 68.223) (xy 144.87625 68.223) (xy 145.035 68.06425) (xy 145.03511 67.925755) + (xy 145.03511 68.774245) (xy 145.035 68.63575) (xy 144.87625 68.477) (xy 143.627 68.477) (xy 143.627 69.37625) + (xy 143.78575 69.535) (xy 144.525755 69.53511) (xy 144.759229 69.438641) (xy 144.938013 69.260168) (xy 145.034889 69.026864) + (xy 145.03511 68.774245) (xy 145.03511 69.692) (xy 144.639062 69.692) (xy 144.615512 69.696684) (xy 144.59759 69.694658) + (xy 144.534606 69.712777) (xy 144.444659 69.730669) (xy 144.423673 69.744691) (xy 144.407104 69.749458) (xy 144.35811 69.788499) + (xy 144.279852 69.84079) (xy 144.26546 69.862328) (xy 144.25209 69.872983) (xy 143.373 70.913245) (xy 143.373 69.37625) + (xy 143.373 68.477) (xy 143.373 68.223) (xy 143.373 67.32375) (xy 143.21425 67.165) (xy 142.474245 67.16489) + (xy 142.240771 67.261359) (xy 142.061987 67.439832) (xy 141.965111 67.673136) (xy 141.96489 67.925755) (xy 141.965 68.06425) + (xy 142.12375 68.223) (xy 143.373 68.223) (xy 143.373 68.477) (xy 142.12375 68.477) (xy 141.965 68.63575) + (xy 141.96489 68.774245) (xy 141.965111 69.026864) (xy 142.061987 69.260168) (xy 142.240771 69.438641) (xy 142.474245 69.53511) + (xy 143.21425 69.535) (xy 143.373 69.37625) (xy 143.373 70.913245) (xy 143.111992 71.222107) (xy 143.074127 71.290557) + (xy 143.030669 71.355597) (xy 143.026468 71.376712) (xy 143.016048 71.395551) (xy 143.007261 71.473277) (xy 142.992 71.55) + (xy 142.992 73.506) (xy 143.010405 73.598528) (xy 143.027024 73.691358) (xy 143.0297 73.695535) (xy 143.030669 73.700403) + (xy 143.083068 73.778824) (xy 143.13396 73.858248) (xy 144.138231 74.90184) (xy 144.140999 74.903767) (xy 144.144636 74.90921) + (xy 144.248075 74.978326) (xy 144.300893 75.015104) (xy 144.3042 75.015828) (xy 144.309443 75.019331) (xy 144.426972 75.042708) + (xy 144.494518 75.057498) (xy 144.498099 75.056856) (xy 144.503846 75.058) (xy 150.270817 75.058) (xy 151.792 76.644274) + (xy 151.792 83.8) (xy 151.830669 83.994403) (xy 151.94079 84.15921) (xy 158.040789 90.25921) (xy 158.04079 90.25921) + (xy 158.15091 90.33279) (xy 158.205596 90.36933) (xy 158.205597 90.369331) (xy 158.399999 90.407999) (xy 158.4 90.408) + (xy 162.825946 90.408) + ) + ) + (filled_polygon + (pts + (xy 163.17358 65.192) (xy 160.791912 65.192) (xy 160.791912 64.271517) (xy 160 63.479605) (xy 159.208088 64.271517) + (xy 159.276078 64.512458) (xy 159.79517 64.697198) (xy 160.345446 64.669228) (xy 160.723922 64.512458) (xy 160.791912 64.271517) + (xy 160.791912 65.192) (xy 159.21042 65.192) (xy 158.508 64.489579) (xy 158.508 64.313841) (xy 158.639823 64.259374) + (xy 158.85626 64.043313) (xy 159.028483 64.091912) (xy 159.820395 63.3) (xy 159.028483 62.508088) (xy 158.856107 62.556729) + (xy 158.641496 62.341744) (xy 158.541232 62.30011) (xy 158.639823 62.259374) (xy 158.85626 62.043313) (xy 159.028483 62.091912) + (xy 159.820395 61.3) (xy 159.806252 61.285857) (xy 159.985857 61.106252) (xy 160 61.120395) (xy 160.014142 61.106252) + (xy 160.193747 61.285857) (xy 160.179605 61.3) (xy 160.971517 62.091912) (xy 161.143892 62.04327) (xy 161.358504 62.258256) + (xy 161.458767 62.299889) (xy 161.360177 62.340626) (xy 161.143739 62.556686) (xy 160.971517 62.508088) (xy 160.791912 62.687693) + (xy 160.791912 62.328483) (xy 160.783874 62.3) (xy 160.791912 62.271517) (xy 160.769517 62.249122) (xy 160.723922 62.087542) + (xy 160.543851 62.023456) (xy 160 61.479605) (xy 159.474076 62.005528) (xy 159.276078 62.087542) (xy 159.230482 62.249122) + (xy 159.208088 62.271517) (xy 159.216125 62.3) (xy 159.208088 62.328483) (xy 159.230482 62.350877) (xy 159.276078 62.512458) + (xy 159.456148 62.576543) (xy 160 63.120395) (xy 160.525923 62.594471) (xy 160.723922 62.512458) (xy 160.769517 62.350877) + (xy 160.791912 62.328483) (xy 160.791912 62.687693) (xy 160.179605 63.3) (xy 160.971517 64.091912) (xy 161.143892 64.04327) + (xy 161.358504 64.258256) (xy 161.774043 64.430803) (xy 162.223983 64.431195) (xy 162.357575 64.375995) (xy 163.17358 65.192) + ) + ) + (filled_polygon + (pts + (xy 163.522618 82.146359) (xy 163.498149 82.170829) (xy 163.512291 82.184971) (xy 163.35334 82.343922) (xy 163.339198 82.32978) + (xy 163.314728 82.354249) (xy 163.135123 82.174644) (xy 163.159593 82.150175) (xy 163.14545 82.136032) (xy 163.304401 81.977081) + (xy 163.318544 81.991224) (xy 163.343013 81.966754) (xy 163.522618 82.146359) + ) + ) + (filled_polygon + (pts + (xy 164.540928 67.84065) (xy 163.991912 68.389666) (xy 163.991912 67.871517) (xy 163.2 67.079605) (xy 162.408088 67.871517) + (xy 162.476078 68.112458) (xy 162.99517 68.297198) (xy 163.545446 68.269228) (xy 163.923922 68.112458) (xy 163.991912 67.871517) + (xy 163.991912 68.389666) (xy 163.989579 68.392) (xy 161.02642 68.392) (xy 161.387256 68.031163) (xy 161.423983 68.031195) + (xy 161.839823 67.859374) (xy 162.05626 67.643313) (xy 162.228483 67.691912) (xy 163.020395 66.9) (xy 163.006252 66.885857) + (xy 163.185857 66.706252) (xy 163.2 66.720395) (xy 163.214142 66.706252) (xy 163.393747 66.885857) (xy 163.379605 66.9) + (xy 164.171517 67.691912) (xy 164.343892 67.64327) (xy 164.540928 67.84065) + ) + ) + (filled_polygon + (pts + (xy 166.237776 84.606197) (xy 166.026923 84.518643) (xy 165.698518 84.518357) (xy 165.395002 84.643767) (xy 165.162583 84.875781) + (xy 165.036643 85.179077) (xy 165.036357 85.507482) (xy 165.161767 85.810998) (xy 165.34388 85.993429) (xy 165.337958 86.370443) + (xy 165.268219 86.300583) (xy 164.964923 86.174643) (xy 164.636518 86.174357) (xy 164.333002 86.299767) (xy 164.100583 86.531781) + (xy 163.974643 86.835077) (xy 163.974502 86.996419) (xy 163.935004 87.035917) (xy 163.843117 86.943869) (xy 163.558834 86.659586) + (xy 163.75921 86.459211) (xy 163.75921 86.45921) (xy 163.83279 86.34909) (xy 163.86933 86.294404) (xy 163.869331 86.294403) + (xy 163.907999 86.1) (xy 163.908 86.1) (xy 163.908 85.959302) (xy 164.099417 85.768219) (xy 164.225357 85.464923) + (xy 164.225643 85.136518) (xy 164.100233 84.833002) (xy 163.868219 84.600583) (xy 163.564923 84.474643) (xy 163.236518 84.474357) + (xy 162.933002 84.599767) (xy 162.700583 84.831781) (xy 162.574643 85.135077) (xy 162.574357 85.463482) (xy 162.699767 85.766998) + (xy 162.857036 85.924542) (xy 162.831338 85.950241) (xy 162.818688 85.919626) (xy 162.711605 85.812356) (xy 162.393704 85.494455) + (xy 162.253721 85.436329) (xy 162.102149 85.436196) (xy 161.962065 85.494078) (xy 161.854795 85.601161) (xy 160.441303 87.014654) + (xy 160.383177 87.154637) (xy 160.383171 87.161308) (xy 160.297842 87.242) (xy 158.214962 87.242) (xy 153.908 83.00956) + (xy 153.908 73.726825) (xy 154.046611 73.669553) (xy 154.368423 73.348302) (xy 154.399861 73.272588) (xy 154.430447 73.346611) + (xy 154.751698 73.668423) (xy 155.171646 73.8428) (xy 155.624775 73.843195) (xy 156.640789 74.85921) (xy 156.64079 74.85921) + (xy 156.75091 74.93279) (xy 156.805596 74.96933) (xy 156.805597 74.969331) (xy 157 75.008) (xy 162.389579 75.008) + (xy 163.692 76.31042) (xy 163.692 77.983722) (xy 163.495884 77.983722) (xy 163.316278 78.163327) (xy 163.316278 77.804116) + (xy 163.316278 77.57961) (xy 163.203223 77.466399) (xy 163.024438 77.287926) (xy 162.790965 77.191457) (xy 162.538346 77.191677) + (xy 162.305042 77.288554) (xy 162.193746 77.400005) (xy 162.193746 77.624511) (xy 162.844815 78.27558) (xy 163.316278 77.804116) + (xy 163.316278 78.163327) (xy 163.02442 78.455185) (xy 163.038562 78.469327) (xy 162.858957 78.648932) (xy 162.844815 78.63479) + (xy 162.830672 78.648932) (xy 162.651067 78.469327) (xy 162.66521 78.455185) (xy 162.014141 77.804116) (xy 161.789635 77.804116) + (xy 161.678184 77.915412) (xy 161.581307 78.148716) (xy 161.581087 78.401335) (xy 161.631455 78.523235) (xy 161.512127 78.523131) + (xy 161.412211 78.564415) (xy 161.025421 78.190897) (xy 161.025643 77.936518) (xy 160.900233 77.633002) (xy 160.668219 77.400583) + (xy 160.364923 77.274643) (xy 160.036518 77.274357) (xy 159.733002 77.399767) (xy 159.500583 77.631781) (xy 159.374643 77.935077) + (xy 159.374357 78.263482) (xy 159.448118 78.442) (xy 158.9 78.442) (xy 158.755279 78.470786) (xy 158.598944 78.314451) + (xy 158.458961 78.256325) (xy 158.307389 78.256192) (xy 158.167305 78.314074) (xy 158.060035 78.421157) (xy 158.003903 78.477288) + (xy 158.012366 78.456908) (xy 158.012499 78.305337) (xy 157.954617 78.165253) (xy 157.847534 78.057982) (xy 157.039311 77.249759) + (xy 156.899328 77.191634) (xy 156.747757 77.191501) (xy 156.607672 77.249383) (xy 156.500402 77.356466) (xy 156.051389 77.805479) + (xy 155.993264 77.945462) (xy 155.993158 78.065423) (xy 155.871335 78.015087) (xy 155.618716 78.015307) (xy 155.385412 78.112184) + (xy 155.274116 78.223635) (xy 155.274116 78.448141) (xy 155.925185 79.09921) (xy 155.939327 79.085067) (xy 156.118932 79.264672) + (xy 156.10479 79.278815) (xy 156.118932 79.292957) (xy 155.939327 79.472562) (xy 155.925185 79.45842) (xy 155.74558 79.638025) + (xy 155.74558 79.278815) (xy 155.094511 78.627746) (xy 154.870005 78.627746) (xy 154.758554 78.739042) (xy 154.661677 78.972346) + (xy 154.661457 79.224965) (xy 154.757926 79.458438) (xy 154.936399 79.637223) (xy 155.04961 79.750278) (xy 155.274116 79.750278) + (xy 155.74558 79.278815) (xy 155.74558 79.638025) (xy 155.453722 79.929884) (xy 155.453722 80.15439) (xy 155.566777 80.267601) + (xy 155.740389 80.440911) (xy 155.681164 80.440911) (xy 155.299245 80.822674) (xy 155.202368 81.055979) (xy 155.202148 81.308598) + (xy 155.225164 81.364301) (xy 155.058777 81.530399) (xy 154.945722 81.64361) (xy 154.945722 81.868116) (xy 155.417185 82.33958) + (xy 156.068254 81.688511) (xy 156.068254 81.62077) (xy 156.576892 81.112132) (xy 156.562749 81.097989) (xy 156.742354 80.918384) + (xy 156.756497 80.932527) (xy 156.770639 80.918384) (xy 156.950244 81.097989) (xy 156.936102 81.112132) (xy 156.950244 81.126274) + (xy 156.770639 81.305879) (xy 156.756497 81.291737) (xy 156.014565 82.033669) (xy 156.014565 82.10141) (xy 155.59679 82.519185) + (xy 155.610932 82.533327) (xy 155.431327 82.712932) (xy 155.417185 82.69879) (xy 155.23758 82.878395) (xy 155.23758 82.519185) + (xy 154.766116 82.047722) (xy 154.54161 82.047722) (xy 154.428399 82.160777) (xy 154.249926 82.339562) (xy 154.153457 82.573035) + (xy 154.153677 82.825654) (xy 154.250554 83.058958) (xy 154.362005 83.170254) (xy 154.586511 83.170254) (xy 155.23758 82.519185) + (xy 155.23758 82.878395) (xy 154.766116 83.349859) (xy 154.766116 83.574365) (xy 154.877412 83.685816) (xy 155.110716 83.782693) + (xy 155.363335 83.782913) (xy 155.485235 83.732544) (xy 155.485131 83.851873) (xy 155.543013 83.991958) (xy 155.650096 84.099228) + (xy 156.099109 84.548241) (xy 156.239092 84.606366) (xy 156.390663 84.606499) (xy 156.530747 84.548617) (xy 156.638018 84.441534) + (xy 157.446241 83.633311) (xy 157.504366 83.493328) (xy 157.504457 83.38895) (xy 157.601056 83.485549) (xy 157.741039 83.543675) + (xy 157.892611 83.543808) (xy 158.032695 83.485926) (xy 158.139965 83.378843) (xy 158.767304 82.751503) (xy 159.806914 82.751503) + (xy 160.384889 83.329477) (xy 160.38484 83.385429) (xy 160.442722 83.525513) (xy 160.549805 83.632783) (xy 161.963298 85.046275) + (xy 162.103281 85.104401) (xy 162.254852 85.104534) (xy 162.394936 85.046652) (xy 162.502206 84.939569) (xy 162.820107 84.621668) + (xy 162.86155 84.52186) (xy 162.960692 84.480896) (xy 163.067962 84.373813) (xy 163.361677 84.080097) (xy 163.440789 84.15921) + (xy 163.44079 84.15921) (xy 163.55091 84.23279) (xy 163.605596 84.26933) (xy 163.605597 84.269331) (xy 163.799999 84.307999) + (xy 163.8 84.308) (xy 164.3 84.308) (xy 164.494403 84.269331) (xy 164.65921 84.15921) (xy 165.224999 83.59342) + (xy 166.237776 84.606197) + ) + ) + (filled_polygon + (pts + (xy 166.692 68.747912) (xy 166.520461 68.747763) (xy 166.100209 68.921407) (xy 165.778397 69.242658) (xy 165.60402 69.662606) + (xy 165.603916 69.781653) (xy 165.170755 70.150303) (xy 165.157949 70.166488) (xy 165.14079 70.177954) (xy 165.096848 70.243717) + (xy 165.047772 70.305747) (xy 165.042135 70.3256) (xy 165.030669 70.342761) (xy 165.015237 70.420341) (xy 164.993637 70.496423) + (xy 164.996026 70.51692) (xy 164.992 70.537164) (xy 164.992 76.090697) (xy 164.800583 76.281781) (xy 164.708 76.504744) + (xy 164.708 76.1) (xy 164.669331 75.905597) (xy 164.66933 75.905596) (xy 164.63279 75.85091) (xy 164.55921 75.74079) + (xy 164.55921 75.740789) (xy 162.95921 74.14079) (xy 162.794403 74.030669) (xy 162.6 73.992) (xy 162.543066 73.992) + (xy 162.543066 73.386547) (xy 162.543066 71.862547) (xy 162.485184 71.722463) (xy 162.378101 71.615192) (xy 162.238118 71.557066) + (xy 162.086547 71.556934) (xy 160.562547 71.556934) (xy 160.422463 71.614816) (xy 160.315192 71.721899) (xy 160.257066 71.861882) + (xy 160.256997 71.940636) (xy 160.048302 71.731577) (xy 159.628354 71.5572) (xy 159.173641 71.556803) (xy 158.753389 71.730447) + (xy 158.53863 71.944831) (xy 158.380212 71.899393) (xy 158.200607 72.078998) (xy 158.200607 71.719788) (xy 158.131142 71.477604) + (xy 157.607696 71.290857) (xy 157.052631 71.31864) (xy 156.668858 71.477604) (xy 156.599393 71.719788) (xy 157.4 72.520395) + (xy 158.200607 71.719788) (xy 158.200607 72.078998) (xy 157.579605 72.7) (xy 158.380212 73.500607) (xy 158.538773 73.455127) + (xy 158.751698 73.668423) (xy 159.171646 73.8428) (xy 159.626359 73.843197) (xy 160.046611 73.669553) (xy 160.256934 73.459596) + (xy 160.256934 73.537453) (xy 160.314816 73.677537) (xy 160.421899 73.784808) (xy 160.561882 73.842934) (xy 160.713453 73.843066) + (xy 162.237453 73.843066) (xy 162.377537 73.785184) (xy 162.484808 73.678101) (xy 162.542934 73.538118) (xy 162.543066 73.386547) + (xy 162.543066 73.992) (xy 157.963103 73.992) (xy 158.131142 73.922396) (xy 158.200607 73.680212) (xy 157.4 72.879605) + (xy 157.385857 72.893747) (xy 157.206252 72.714142) (xy 157.220395 72.7) (xy 156.419788 71.899393) (xy 156.261226 71.944872) + (xy 156.048302 71.731577) (xy 155.908 71.673318) (xy 155.908 69.304118) (xy 155.95091 69.33279) (xy 156.005596 69.36933) + (xy 156.005597 69.369331) (xy 156.2 69.408) (xy 164.2 69.408) (xy 164.394403 69.369331) (xy 164.55921 69.25921) + (xy 165.55921 68.259211) (xy 165.55921 68.25921) (xy 165.63279 68.14909) (xy 165.66933 68.094404) (xy 165.669331 68.094403) + (xy 165.705 67.915081) (xy 165.839823 67.859374) (xy 166.158256 67.541496) (xy 166.199889 67.441232) (xy 166.240626 67.539823) + (xy 166.558504 67.858256) (xy 166.692 67.913688) (xy 166.692 68.747912) + ) + ) + (filled_polygon + (pts + (xy 170.939408 86.125447) (xy 170.924854 86.139977) (xy 170.606953 86.457878) (xy 170.562868 86.564045) (xy 170.457387 86.60763) + (xy 170.350117 86.714713) (xy 170.212156 86.852673) (xy 169.990393 86.85248) (xy 169.75692 86.94895) (xy 169.71903 86.986772) + (xy 169.7499 86.355599) (xy 169.735826 86.260861) (xy 169.727233 86.179785) (xy 169.722485 86.171059) (xy 169.720774 86.159539) + (xy 169.671622 86.077575) (xy 169.632503 86.005676) (xy 168.815288 85.024824) (xy 168.797159 85.010169) (xy 168.78421 84.99079) + (xy 168.720621 84.948301) (xy 168.66114 84.90022) (xy 168.638784 84.893619) (xy 168.619403 84.880669) (xy 168.544388 84.865747) + (xy 168.471041 84.844091) (xy 168.447862 84.846547) (xy 168.425 84.842) (xy 167.91042 84.842) (xy 165.434662 82.366242) + (xy 165.424414 82.376477) (xy 165.424414 82.37642) (xy 165.434636 82.366216) (xy 165.424414 82.355993) (xy 165.424414 82.151971) + (xy 164.470711 81.198268) (xy 164.446241 81.222737) (xy 164.266636 81.043132) (xy 164.291106 81.018663) (xy 163.337403 80.06496) + (xy 163.112953 80.06496) (xy 163.056047 80.121966) (xy 162.959577 80.355439) (xy 162.95977 80.577201) (xy 162.877083 80.659888) + (xy 162.65532 80.659695) (xy 162.421847 80.756165) (xy 162.364841 80.813071) (xy 162.364841 81.016864) (xy 162.326369 80.978392) + (xy 162.326369 80.851476) (xy 162.243063 80.934637) (xy 162.326369 80.851437) (xy 162.326369 80.320763) (xy 162.718611 79.928521) + (xy 162.776736 79.788538) (xy 162.776841 79.668576) (xy 162.898665 79.718913) (xy 163.151284 79.718693) (xy 163.384588 79.621816) + (xy 163.495884 79.510365) (xy 163.495884 79.285862) (xy 163.608135 79.398113) (xy 163.692 79.314248) (xy 163.692 79.567367) + (xy 163.55336 79.624653) (xy 163.496354 79.681559) (xy 163.496354 79.906009) (xy 164.450057 80.859712) (xy 164.474526 80.835242) + (xy 164.654131 81.014847) (xy 164.629662 81.039317) (xy 165.583365 81.99302) (xy 165.807814 81.99302) (xy 165.864721 81.936014) + (xy 165.961191 81.702541) (xy 165.960997 81.480777) (xy 166.211677 81.230097) (xy 170.174592 85.193013) (xy 170.174357 85.463482) + (xy 170.299767 85.766998) (xy 170.531781 85.999417) (xy 170.835077 86.125357) (xy 170.939408 86.125447) + ) + ) + (filled_polygon + (pts + (xy 175.608762 62.227182) (xy 175.173641 62.226803) (xy 174.753389 62.400447) (xy 174.431577 62.721698) (xy 174.2572 63.141646) + (xy 174.25703 63.335706) (xy 174.24136 63.022631) (xy 174.082396 62.638858) (xy 173.840212 62.569393) (xy 173.039605 63.37) + (xy 173.840212 64.170607) (xy 174.082396 64.101142) (xy 174.259852 63.603738) (xy 174.430447 64.016611) (xy 174.751698 64.338423) + (xy 174.892 64.396681) (xy 174.892 65.200354) (xy 174.85 65.192) (xy 173.660607 65.192) (xy 173.660607 64.350212) + (xy 172.86 63.549605) (xy 172.680395 63.72921) (xy 172.680395 63.37) (xy 171.879788 62.569393) (xy 171.637604 62.638858) + (xy 171.450857 63.162304) (xy 171.47864 63.717369) (xy 171.637604 64.101142) (xy 171.879788 64.170607) (xy 172.680395 63.37) + (xy 172.680395 63.72921) (xy 172.059393 64.350212) (xy 172.128858 64.592396) (xy 172.652304 64.779143) (xy 173.207369 64.75136) + (xy 173.591142 64.592396) (xy 173.660607 64.350212) (xy 173.660607 65.192) (xy 172.01042 65.192) (xy 167.75921 60.94079) + (xy 167.594403 60.830669) (xy 167.4 60.792) (xy 165.013841 60.792) (xy 164.959374 60.660177) (xy 164.641496 60.341744) + (xy 164.560231 60.308) (xy 169.689579 60.308) (xy 170.570789 61.18921) (xy 170.57079 61.18921) (xy 170.68091 61.26279) + (xy 170.735596 61.29933) (xy 170.735597 61.299331) (xy 170.929999 61.337999) (xy 170.93 61.338) (xy 171.833174 61.338) + (xy 171.890447 61.476611) (xy 172.211698 61.798423) (xy 172.631646 61.9728) (xy 172.825706 61.972969) (xy 172.512631 61.98864) + (xy 172.128858 62.147604) (xy 172.059393 62.389788) (xy 172.86 63.190395) (xy 173.660607 62.389788) (xy 173.591142 62.147604) + (xy 173.093738 61.970147) (xy 173.506611 61.799553) (xy 173.828423 61.478302) (xy 174.0028 61.058354) (xy 174.003197 60.603641) + (xy 173.829553 60.183389) (xy 173.508302 59.861577) (xy 173.184203 59.727) (xy 175.076356 59.727) (xy 174.753389 59.860447) + (xy 174.431577 60.181698) (xy 174.2572 60.601646) (xy 174.256803 61.056359) (xy 174.430447 61.476611) (xy 174.751698 61.798423) + (xy 175.171646 61.9728) (xy 175.354539 61.972959) (xy 175.608762 62.227182) + ) + ) + (filled_polygon + (pts + (xy 175.769 70.3157) (xy 175.76393 70.320769) (xy 175.76393 69.254715) (xy 175.763709 69.002096) (xy 175.666833 68.768792) + (xy 175.488049 68.590319) (xy 175.254575 68.49385) (xy 174.65257 68.49396) (xy 174.49382 68.65271) (xy 174.49382 69.76396) + (xy 175.60507 69.76396) (xy 175.76382 69.60521) (xy 175.76393 69.254715) (xy 175.76393 70.320769) (xy 175.763865 70.320834) + (xy 175.76382 70.17671) (xy 175.60507 70.01796) (xy 174.49382 70.01796) (xy 174.49382 71.12921) (xy 174.65257 71.28796) + (xy 174.796713 71.287986) (xy 174.737458 71.347241) (xy 174.595174 71.28816) (xy 174.140461 71.287763) (xy 173.720209 71.461407) + (xy 173.546 71.635312) (xy 173.546 71.338) (xy 173.536066 71.288059) (xy 174.08107 71.28796) (xy 174.23982 71.12921) + (xy 174.23982 70.01796) (xy 174.23982 69.76396) (xy 174.23982 68.65271) (xy 174.08107 68.49396) (xy 173.479065 68.49385) + (xy 173.245591 68.590319) (xy 173.066807 68.768792) (xy 172.969931 69.002096) (xy 172.96971 69.254715) (xy 172.96982 69.60521) + (xy 173.12857 69.76396) (xy 174.23982 69.76396) (xy 174.23982 70.01796) (xy 173.12857 70.01796) (xy 172.96982 70.17671) + (xy 172.96971 70.527205) (xy 172.969731 70.551311) (xy 172.842903 70.424483) (xy 172.96962 70.119314) (xy 172.970017 69.664601) + (xy 172.796373 69.244349) (xy 172.475122 68.922537) (xy 172.055174 68.74816) (xy 171.600461 68.747763) (xy 171.180209 68.921407) + (xy 171.108 68.99349) (xy 171.108 68.030919) (xy 171.423983 68.031195) (xy 171.839823 67.859374) (xy 172.068934 67.630662) + (xy 172.068934 67.725453) (xy 172.126816 67.865537) (xy 172.233899 67.972808) (xy 172.373882 68.030934) (xy 172.525453 68.031066) + (xy 174.025453 68.031066) (xy 174.165537 67.973184) (xy 174.272808 67.866101) (xy 174.330934 67.726118) (xy 174.33106 67.581) + (xy 174.61792 67.581) (xy 175.769 68.73208) (xy 175.769 70.3157) + ) + ) + (filled_polygon + (pts + (xy 176.442 89.43958) (xy 174.28958 91.592) (xy 174.180533 91.592) (xy 174.18061 91.504745) (xy 174.1805 91.34475) + (xy 174.02175 91.186) (xy 173.355 91.186) (xy 173.355 91.206) (xy 173.101 91.206) (xy 173.101 91.186) + (xy 173.081 91.186) (xy 173.081 90.932) (xy 173.101 90.932) (xy 173.101 90.01125) (xy 172.94225 89.8525) + (xy 172.784745 89.85239) (xy 172.551271 89.948859) (xy 172.372487 90.127332) (xy 172.321905 90.249144) (xy 172.237601 90.164692) + (xy 172.097618 90.106566) (xy 172.024922 90.106502) (xy 171.623551 89.705131) (xy 171.627974 89.700717) (xy 171.627974 89.476268) + (xy 170.674271 88.522565) (xy 170.649801 88.547034) (xy 170.470196 88.367429) (xy 170.494666 88.34296) (xy 170.480523 88.328817) + (xy 170.639474 88.169866) (xy 170.653617 88.184009) (xy 170.678086 88.159539) (xy 170.857691 88.339144) (xy 170.833222 88.363614) + (xy 171.786925 89.317317) (xy 172.011374 89.317317) (xy 172.068281 89.260311) (xy 172.164751 89.026838) (xy 172.164557 88.805074) + (xy 172.409224 88.560408) (xy 172.411115 88.555853) (xy 172.693918 88.838657) (xy 172.674643 88.885077) (xy 172.674357 89.213482) + (xy 172.799767 89.516998) (xy 173.031781 89.749417) (xy 173.335077 89.875357) (xy 173.490757 89.875492) (xy 173.355 90.01125) + (xy 173.355 90.932) (xy 174.02175 90.932) (xy 174.1805 90.77325) (xy 174.18061 90.613255) (xy 174.180389 90.360636) + (xy 174.083513 90.127332) (xy 173.904729 89.948859) (xy 173.695506 89.86241) (xy 173.966998 89.750233) (xy 174.199417 89.518219) + (xy 174.325357 89.214923) (xy 174.325643 88.886518) (xy 174.200233 88.583002) (xy 173.968219 88.350583) (xy 173.664923 88.224643) + (xy 173.516616 88.224513) (xy 173.130787 87.838684) (xy 173.222836 87.746797) (xy 173.540737 87.428896) (xy 173.598863 87.288913) + (xy 173.598996 87.137341) (xy 173.541114 86.997257) (xy 173.434031 86.889987) (xy 172.020538 85.476495) (xy 171.880555 85.418369) + (xy 171.825397 85.41832) (xy 171.825643 85.136518) (xy 171.808683 85.095472) (xy 171.901443 85.095554) (xy 172.041527 85.037672) + (xy 172.148797 84.930589) (xy 173.562289 83.517096) (xy 173.620415 83.377113) (xy 173.620548 83.225542) (xy 173.562666 83.085458) + (xy 173.455583 82.978188) (xy 173.137682 82.660287) (xy 173.039146 82.619371) (xy 172.998706 82.521498) (xy 172.891623 82.414228) + (xy 172.573722 82.096327) (xy 172.472643 82.054355) (xy 172.431154 81.953945) (xy 172.324071 81.846675) (xy 172.013723 81.536327) + (xy 176.442 77.108051) (xy 176.442 89.43958) + ) + ) + (filled_polygon + (pts + (xy 181.873 115.473) (xy 179.370219 115.473) (xy 179.370219 113.32849) (xy 179.370219 110.78849) (xy 179.370219 108.24849) + (xy 179.370219 105.70849) (xy 179.370219 103.16849) (xy 179.177281 102.701543) (xy 178.820336 102.343975) (xy 178.353727 102.150222) + (xy 177.84849 102.149781) (xy 177.381543 102.342719) (xy 177.023975 102.699664) (xy 176.830222 103.166273) (xy 176.829781 103.67151) + (xy 177.022719 104.138457) (xy 177.379664 104.496025) (xy 177.846273 104.689778) (xy 178.35151 104.690219) (xy 178.818457 104.497281) + (xy 179.176025 104.140336) (xy 179.369778 103.673727) (xy 179.370219 103.16849) (xy 179.370219 105.70849) (xy 179.177281 105.241543) + (xy 178.820336 104.883975) (xy 178.353727 104.690222) (xy 177.84849 104.689781) (xy 177.381543 104.882719) (xy 177.023975 105.239664) + (xy 176.830222 105.706273) (xy 176.829781 106.21151) (xy 177.022719 106.678457) (xy 177.379664 107.036025) (xy 177.846273 107.229778) + (xy 178.35151 107.230219) (xy 178.818457 107.037281) (xy 179.176025 106.680336) (xy 179.369778 106.213727) (xy 179.370219 105.70849) + (xy 179.370219 108.24849) (xy 179.177281 107.781543) (xy 178.820336 107.423975) (xy 178.353727 107.230222) (xy 177.84849 107.229781) + (xy 177.381543 107.422719) (xy 177.023975 107.779664) (xy 176.830222 108.246273) (xy 176.829781 108.75151) (xy 177.022719 109.218457) + (xy 177.379664 109.576025) (xy 177.846273 109.769778) (xy 178.35151 109.770219) (xy 178.818457 109.577281) (xy 179.176025 109.220336) + (xy 179.369778 108.753727) (xy 179.370219 108.24849) (xy 179.370219 110.78849) (xy 179.177281 110.321543) (xy 178.820336 109.963975) + (xy 178.353727 109.770222) (xy 177.84849 109.769781) (xy 177.381543 109.962719) (xy 177.023975 110.319664) (xy 176.830222 110.786273) + (xy 176.829781 111.29151) (xy 177.022719 111.758457) (xy 177.379664 112.116025) (xy 177.846273 112.309778) (xy 178.35151 112.310219) + (xy 178.818457 112.117281) (xy 179.176025 111.760336) (xy 179.369778 111.293727) (xy 179.370219 110.78849) (xy 179.370219 113.32849) + (xy 179.177281 112.861543) (xy 178.820336 112.503975) (xy 178.353727 112.310222) (xy 177.84849 112.309781) (xy 177.381543 112.502719) + (xy 177.023975 112.859664) (xy 176.830222 113.326273) (xy 176.829781 113.83151) (xy 177.022719 114.298457) (xy 177.379664 114.656025) + (xy 177.846273 114.849778) (xy 178.35151 114.850219) (xy 178.818457 114.657281) (xy 179.176025 114.300336) (xy 179.369778 113.833727) + (xy 179.370219 113.32849) (xy 179.370219 115.473) (xy 176.720566 115.473) (xy 176.720566 98.667047) (xy 176.720566 98.032047) + (xy 176.662684 97.891963) (xy 176.555601 97.784692) (xy 176.415618 97.726566) (xy 176.264047 97.726434) (xy 175.121047 97.726434) + (xy 174.980963 97.784316) (xy 174.873692 97.891399) (xy 174.815566 98.031382) (xy 174.815434 98.182953) (xy 174.815434 98.817953) + (xy 174.873316 98.958037) (xy 174.980399 99.065308) (xy 175.120382 99.123434) (xy 175.26 99.123555) (xy 175.26 99.484579) + (xy 174.683066 100.061513) (xy 174.683066 97.824547) (xy 174.683066 94.024547) (xy 174.625184 93.884463) (xy 174.518101 93.777192) + (xy 174.378118 93.719066) (xy 174.226547 93.718934) (xy 170.226547 93.718934) (xy 170.086463 93.776816) (xy 169.979192 93.883899) + (xy 169.921066 94.023882) (xy 169.920934 94.175453) (xy 169.920934 97.975453) (xy 169.978816 98.115537) (xy 170.085899 98.222808) + (xy 170.225882 98.280934) (xy 170.377453 98.281066) (xy 174.377453 98.281066) (xy 174.517537 98.223184) (xy 174.624808 98.116101) + (xy 174.682934 97.976118) (xy 174.683066 97.824547) (xy 174.683066 100.061513) (xy 173.93079 100.81379) (xy 173.820669 100.978597) + (xy 173.782 101.173) (xy 173.782 102.149934) (xy 173.325547 102.149934) (xy 173.185463 102.207816) (xy 173.078192 102.314899) + (xy 173.020066 102.454882) (xy 173.019934 102.606453) (xy 173.019934 104.384453) (xy 173.077816 104.524537) (xy 173.184899 104.631808) + (xy 173.324882 104.689934) (xy 173.476453 104.690066) (xy 174.0378 104.690066) (xy 173.571543 104.882719) (xy 173.213975 105.239664) + (xy 173.020222 105.706273) (xy 173.019781 106.21151) (xy 173.212719 106.678457) (xy 173.569664 107.036025) (xy 174.036273 107.229778) + (xy 174.54151 107.230219) (xy 175.008457 107.037281) (xy 175.366025 106.680336) (xy 175.559778 106.213727) (xy 175.560219 105.70849) + (xy 175.367281 105.241543) (xy 175.010336 104.883975) (xy 174.543727 104.690222) (xy 174.365003 104.690066) (xy 175.254453 104.690066) + (xy 175.394537 104.632184) (xy 175.501808 104.525101) (xy 175.559934 104.385118) (xy 175.560066 104.233547) (xy 175.560066 102.455547) + (xy 175.502184 102.315463) (xy 175.395101 102.208192) (xy 175.255118 102.150066) (xy 175.103547 102.149934) (xy 174.798 102.149934) + (xy 174.798 101.38342) (xy 176.12721 100.054211) (xy 176.12721 100.05421) (xy 176.20079 99.94409) (xy 176.23733 99.889404) + (xy 176.237331 99.889403) (xy 176.275999 99.695) (xy 176.276 99.695) (xy 176.276 99.123566) (xy 176.414953 99.123566) + (xy 176.555037 99.065684) (xy 176.662308 98.958601) (xy 176.720434 98.818618) (xy 176.720566 98.667047) (xy 176.720566 115.473) + (xy 175.825514 115.473) (xy 175.825514 111.278035) (xy 175.799722 110.6723) (xy 175.617539 110.232468) (xy 175.560219 110.213374) + (xy 175.560219 108.24849) (xy 175.367281 107.781543) (xy 175.010336 107.423975) (xy 174.543727 107.230222) (xy 174.03849 107.229781) + (xy 173.571543 107.422719) (xy 173.374919 107.619) (xy 173.064922 107.619) (xy 172.681 107.235078) (xy 172.681 102.4) + (xy 172.613938 102.062856) (xy 172.422961 101.777039) (xy 171.522961 100.877039) (xy 171.237144 100.686062) (xy 170.9 100.619) + (xy 170.880426 100.619) (xy 170.880426 100.174867) (xy 170.822544 100.034783) (xy 170.715461 99.927512) (xy 170.575478 99.869386) + (xy 170.423907 99.869254) (xy 170.374219 99.869254) (xy 170.337938 99.686856) (xy 170.146961 99.401039) (xy 168.408961 97.663039) + (xy 168.123144 97.472062) (xy 167.786 97.405) (xy 167.072114 97.405) (xy 167.037184 97.320463) (xy 166.930101 97.213192) + (xy 166.790118 97.155066) (xy 166.638547 97.154934) (xy 164.606547 97.154934) (xy 164.466463 97.212816) (xy 164.359192 97.319899) + (xy 164.301066 97.459882) (xy 164.300934 97.611453) (xy 164.300934 99.111453) (xy 164.358816 99.251537) (xy 164.465899 99.358808) + (xy 164.605882 99.416934) (xy 164.757453 99.417066) (xy 166.789453 99.417066) (xy 166.929537 99.359184) (xy 167.036808 99.252101) + (xy 167.072145 99.167) (xy 167.421078 99.167) (xy 168.257091 100.003013) (xy 168.225832 100.034219) (xy 168.167706 100.174202) + (xy 168.167574 100.325773) (xy 168.167574 102.825133) (xy 168.225456 102.965217) (xy 168.332539 103.072488) (xy 168.472522 103.130614) + (xy 168.624093 103.130746) (xy 170.574813 103.130746) (xy 170.714897 103.072864) (xy 170.822168 102.965781) (xy 170.880294 102.825798) + (xy 170.88038 102.726302) (xy 170.919 102.764922) (xy 170.919 105.934815) (xy 170.738507 105.859868) (xy 170.751357 105.828923) + (xy 170.751643 105.500518) (xy 170.626233 105.197002) (xy 170.394219 104.964583) (xy 170.090923 104.838643) (xy 169.777684 104.83837) + (xy 169.782969 104.825644) (xy 169.78319 104.573025) (xy 169.78319 104.026975) (xy 169.782969 103.774356) (xy 169.686093 103.541052) + (xy 169.507309 103.362579) (xy 169.273835 103.26611) (xy 169.03505 103.26622) (xy 168.8763 103.42497) (xy 168.8763 104.173) + (xy 169.62433 104.173) (xy 169.78308 104.01425) (xy 169.78319 104.026975) (xy 169.78319 104.573025) (xy 169.78308 104.58575) + (xy 169.62433 104.427) (xy 168.8763 104.427) (xy 168.8763 104.447) (xy 168.6223 104.447) (xy 168.6223 104.427) + (xy 168.6023 104.427) (xy 168.6023 104.173) (xy 168.6223 104.173) (xy 168.6223 103.42497) (xy 168.46355 103.26622) + (xy 168.224765 103.26611) (xy 168.08647 103.323252) (xy 168.08647 102.623925) (xy 168.08647 100.376075) (xy 168.086249 100.123456) + (xy 167.989373 99.890152) (xy 167.810589 99.711679) (xy 167.577115 99.61521) (xy 166.76175 99.61532) (xy 166.603 99.77407) + (xy 166.603 101.373) (xy 167.92761 101.373) (xy 168.08636 101.21425) (xy 168.08647 100.376075) (xy 168.08647 102.623925) + (xy 168.08636 101.78575) (xy 167.92761 101.627) (xy 166.603 101.627) (xy 166.603 103.22593) (xy 166.76175 103.38468) + (xy 167.577115 103.38479) (xy 167.810589 103.288321) (xy 167.989373 103.109848) (xy 168.086249 102.876544) (xy 168.08647 102.623925) + (xy 168.08647 103.323252) (xy 167.991291 103.362579) (xy 167.812507 103.541052) (xy 167.80708 103.55412) (xy 167.725598 103.520286) + (xy 167.574027 103.520154) (xy 166.776467 103.520154) (xy 166.636383 103.578036) (xy 166.529112 103.685119) (xy 166.495629 103.765754) + (xy 166.349 103.766777) (xy 166.349 103.22593) (xy 166.349 101.627) (xy 166.349 101.373) (xy 166.349 99.77407) + (xy 166.19025 99.61532) (xy 165.374885 99.61521) (xy 165.141411 99.711679) (xy 164.962627 99.890152) (xy 164.865751 100.123456) + (xy 164.86553 100.376075) (xy 164.86564 101.21425) (xy 165.02439 101.373) (xy 166.349 101.373) (xy 166.349 101.627) + (xy 165.02439 101.627) (xy 164.86564 101.78575) (xy 164.86553 102.623925) (xy 164.865751 102.876544) (xy 164.962627 103.109848) + (xy 165.141411 103.288321) (xy 165.374885 103.38479) (xy 166.19025 103.38468) (xy 166.349 103.22593) (xy 166.349 103.766777) + (xy 163.603163 103.785947) (xy 163.581684 103.733963) (xy 163.474601 103.626692) (xy 163.334618 103.568566) (xy 163.246 103.568488) + (xy 163.246 102.938) (xy 163.207331 102.743597) (xy 163.20733 102.743596) (xy 163.17079 102.68891) (xy 163.09721 102.57879) + (xy 163.09721 102.578789) (xy 162.88479 102.366369) (xy 162.88479 99.125115) (xy 162.88468 98.30975) (xy 162.72593 98.151) + (xy 161.127 98.151) (xy 161.127 99.47561) (xy 161.28575 99.63436) (xy 162.123925 99.63447) (xy 162.376544 99.634249) + (xy 162.609848 99.537373) (xy 162.788321 99.358589) (xy 162.88479 99.125115) (xy 162.88479 102.366369) (xy 162.20921 101.69079) + (xy 162.044403 101.580669) (xy 161.85 101.542) (xy 160.873 101.542) (xy 160.873 99.47561) (xy 160.873 98.151) + (xy 160.873 97.897) (xy 160.873 96.57239) (xy 160.71425 96.41364) (xy 159.876075 96.41353) (xy 159.623456 96.413751) + (xy 159.390152 96.510627) (xy 159.211679 96.689411) (xy 159.11521 96.922885) (xy 159.11532 97.73825) (xy 159.27407 97.897) + (xy 160.873 97.897) (xy 160.873 98.151) (xy 159.27407 98.151) (xy 159.11532 98.30975) (xy 159.11521 99.125115) + (xy 159.211679 99.358589) (xy 159.390152 99.537373) (xy 159.623456 99.634249) (xy 159.876075 99.63447) (xy 160.71425 99.63436) + (xy 160.873 99.47561) (xy 160.873 101.542) (xy 160.121641 101.542) (xy 160.043885 101.353815) (xy 159.698006 101.007331) + (xy 159.245861 100.819585) (xy 158.756287 100.819157) (xy 158.303815 101.006115) (xy 157.957331 101.351994) (xy 157.95311 101.362159) + (xy 157.95311 99.161755) (xy 157.953 98.57175) (xy 157.79425 98.413) (xy 156.429 98.413) (xy 156.429 99.51225) + (xy 156.58775 99.671) (xy 157.192245 99.67111) (xy 157.444864 99.670889) (xy 157.678168 99.574013) (xy 157.856641 99.395229) + (xy 157.95311 99.161755) (xy 157.95311 101.362159) (xy 157.908746 101.469) (xy 156.175 101.469) (xy 156.175 99.51225) + (xy 156.175 98.413) (xy 154.80975 98.413) (xy 154.651 98.57175) (xy 154.65089 99.161755) (xy 154.747359 99.395229) + (xy 154.925832 99.574013) (xy 155.159136 99.670889) (xy 155.411755 99.67111) (xy 156.01625 99.671) (xy 156.175 99.51225) + (xy 156.175 101.469) (xy 154.091478 101.469) (xy 154.043885 101.353815) (xy 153.698006 101.007331) (xy 153.245861 100.819585) + (xy 152.756287 100.819157) (xy 152.303815 101.006115) (xy 151.957331 101.351994) (xy 151.880426 101.537202) (xy 151.880426 100.174867) + (xy 151.853464 100.109615) (xy 154.137458 97.82562) (xy 154.163482 97.825643) (xy 154.466998 97.700233) (xy 154.650909 97.516641) + (xy 154.651 98.00025) (xy 154.80975 98.159) (xy 156.175 98.159) (xy 156.175 98.139) (xy 156.429 98.139) + (xy 156.429 98.159) (xy 157.79425 98.159) (xy 157.953 98.00025) (xy 157.95311 97.410245) (xy 157.856641 97.176771) + (xy 157.678168 96.997987) (xy 157.629224 96.977664) (xy 157.640808 96.966101) (xy 157.698934 96.826118) (xy 157.699066 96.674547) + (xy 157.699066 95.174547) (xy 157.641184 95.034463) (xy 157.534101 94.927192) (xy 157.394118 94.869066) (xy 157.242547 94.868934) + (xy 155.210547 94.868934) (xy 155.070463 94.926816) (xy 154.963192 95.033899) (xy 154.905066 95.173882) (xy 154.904934 95.325453) + (xy 154.904934 95.337909) (xy 154.739393 95.370838) (xy 154.51846 95.51846) (xy 154.518457 95.518463) (xy 153.86254 96.174379) + (xy 153.836518 96.174357) (xy 153.533002 96.299767) (xy 153.300583 96.531781) (xy 153.174643 96.835077) (xy 153.174619 96.862301) + (xy 152.078949 97.95797) (xy 152.079066 97.824547) (xy 152.079066 94.024547) (xy 152.021184 93.884463) (xy 151.914101 93.777192) + (xy 151.774118 93.719066) (xy 151.622547 93.718934) (xy 147.622547 93.718934) (xy 147.482463 93.776816) (xy 147.375192 93.883899) + (xy 147.317066 94.023882) (xy 147.316934 94.175453) (xy 147.316934 97.975453) (xy 147.374816 98.115537) (xy 147.481899 98.222808) + (xy 147.621882 98.280934) (xy 147.773453 98.281066) (xy 151.755854 98.281066) (xy 150.54246 99.49446) (xy 150.394838 99.715392) + (xy 150.364233 99.869254) (xy 149.473187 99.869254) (xy 149.333103 99.927136) (xy 149.225832 100.034219) (xy 149.167706 100.174202) + (xy 149.167574 100.325773) (xy 149.167574 102.825133) (xy 149.225456 102.965217) (xy 149.332539 103.072488) (xy 149.472522 103.130614) + (xy 149.624093 103.130746) (xy 151.574813 103.130746) (xy 151.714897 103.072864) (xy 151.822168 102.965781) (xy 151.880294 102.825798) + (xy 151.880426 102.674227) (xy 151.880426 102.563004) (xy 151.956115 102.746185) (xy 152.301994 103.092669) (xy 152.754139 103.280415) + (xy 153.243713 103.280843) (xy 153.696185 103.093885) (xy 154.042669 102.748006) (xy 154.091253 102.631) (xy 157.908521 102.631) + (xy 157.956115 102.746185) (xy 158.301994 103.092669) (xy 158.754139 103.280415) (xy 159.243713 103.280843) (xy 159.696185 103.093885) + (xy 160.042669 102.748006) (xy 160.121565 102.558) (xy 161.639579 102.558) (xy 162.23 103.14842) (xy 162.23 103.568434) + (xy 162.040047 103.568434) (xy 161.899963 103.626316) (xy 161.792692 103.733399) (xy 161.734566 103.873382) (xy 161.734434 104.024953) + (xy 161.734434 104.659953) (xy 161.792316 104.800037) (xy 161.899399 104.907308) (xy 162.039382 104.965434) (xy 162.190953 104.965566) + (xy 163.333953 104.965566) (xy 163.474037 104.907684) (xy 163.57977 104.802135) (xy 166.474034 104.781929) (xy 166.528736 104.914317) + (xy 166.635819 105.021588) (xy 166.775802 105.079714) (xy 166.927373 105.079846) (xy 167.724933 105.079846) (xy 167.807088 105.045899) + (xy 167.812507 105.058948) (xy 167.909728 105.156) (xy 164.592 105.156) (xy 164.397596 105.194669) (xy 164.23279 105.30479) + (xy 163.639566 105.898014) (xy 163.639566 105.398047) (xy 163.581684 105.257963) (xy 163.474601 105.150692) (xy 163.334618 105.092566) + (xy 163.183047 105.092434) (xy 162.040047 105.092434) (xy 161.899963 105.150316) (xy 161.858333 105.191872) (xy 161.758219 105.091583) + (xy 161.454923 104.965643) (xy 161.126518 104.965357) (xy 160.823002 105.090767) (xy 160.590583 105.322781) (xy 160.464643 105.626077) + (xy 160.464357 105.954482) (xy 160.589767 106.257998) (xy 160.821781 106.490417) (xy 161.125077 106.616357) (xy 161.270095 106.616483) + (xy 160.571579 107.315) (xy 160.301791 107.315) (xy 160.496348 106.778632) (xy 160.469939 106.188601) (xy 160.294952 105.766144) + (xy 160.04369 105.685916) (xy 159.864084 105.865521) (xy 159.864084 105.50631) (xy 159.783856 105.255048) (xy 159.228632 105.053652) + (xy 158.638601 105.080061) (xy 158.216144 105.255048) (xy 158.135916 105.50631) (xy 159 106.370395) (xy 159.864084 105.50631) + (xy 159.864084 105.865521) (xy 159.179605 106.55) (xy 159.193747 106.564142) (xy 159.014142 106.743747) (xy 159 106.729605) + (xy 158.985857 106.743747) (xy 158.806252 106.564142) (xy 158.820395 106.55) (xy 157.95631 105.685916) (xy 157.705048 105.766144) + (xy 157.503652 106.321368) (xy 157.530061 106.911399) (xy 157.697237 107.315) (xy 154.301791 107.315) (xy 154.496348 106.778632) + (xy 154.469939 106.188601) (xy 154.294952 105.766144) (xy 154.04369 105.685916) (xy 153.864084 105.865521) (xy 153.864084 105.50631) + (xy 153.783856 105.255048) (xy 153.228632 105.053652) (xy 152.638601 105.080061) (xy 152.216144 105.255048) (xy 152.135916 105.50631) + (xy 153 106.370395) (xy 153.864084 105.50631) (xy 153.864084 105.865521) (xy 153.179605 106.55) (xy 153.193747 106.564142) + (xy 153.014142 106.743747) (xy 153 106.729605) (xy 152.985857 106.743747) (xy 152.806252 106.564142) (xy 152.820395 106.55) + (xy 151.95631 105.685916) (xy 151.705048 105.766144) (xy 151.503652 106.321368) (xy 151.516799 106.61511) (xy 151.454199 106.463606) + (xy 151.108216 106.117018) (xy 150.655935 105.929215) (xy 150.166213 105.928787) (xy 149.713606 106.115801) (xy 149.367018 106.461784) + (xy 149.179215 106.914065) (xy 149.178787 107.403787) (xy 149.365801 107.856394) (xy 149.711784 108.202982) (xy 149.91215 108.286181) + (xy 149.62592 108.404742) (xy 149.545648 108.656043) (xy 150.41 109.520395) (xy 151.274352 108.656043) (xy 151.19408 108.404742) + (xy 150.888937 108.29405) (xy 151.106394 108.204199) (xy 151.267226 108.043647) (xy 151.405789 108.18221) (xy 151.40579 108.18221) + (xy 151.51591 108.25579) (xy 151.570596 108.29233) (xy 151.570597 108.292331) (xy 151.765 108.331) (xy 160.782 108.331) + (xy 160.976403 108.292331) (xy 161.14121 108.18221) (xy 162.00842 107.315) (xy 163.449 107.315) (xy 163.643403 107.276331) + (xy 163.80821 107.16621) (xy 164.80242 106.172) (xy 165.481 106.172) (xy 165.318849 106.204253) (xy 165.286596 106.210669) + (xy 165.121789 106.32079) (xy 164.74079 106.70179) (xy 164.630669 106.866597) (xy 164.592 107.061) (xy 164.592 107.163697) + (xy 164.400583 107.354781) (xy 164.274643 107.658077) (xy 164.274357 107.986482) (xy 164.399767 108.289998) (xy 164.631781 108.522417) + (xy 164.935077 108.648357) (xy 165.263482 108.648643) (xy 165.566998 108.523233) (xy 165.799417 108.291219) (xy 165.861998 108.140506) + (xy 165.923767 108.289998) (xy 166.155781 108.522417) (xy 166.459077 108.648357) (xy 166.787482 108.648643) (xy 167.090998 108.523233) + (xy 167.28664 108.327931) (xy 167.195643 108.547077) (xy 167.195357 108.875482) (xy 167.320767 109.178998) (xy 167.552781 109.411417) + (xy 167.856077 109.537357) (xy 168.184482 109.537643) (xy 168.293673 109.492526) (xy 168.211643 109.690077) (xy 168.211406 109.962173) + (xy 167.937579 110.236) (xy 167.322566 110.236) (xy 167.322566 110.097047) (xy 167.264684 109.956963) (xy 167.157601 109.849692) + (xy 167.017618 109.791566) (xy 166.866047 109.791434) (xy 166.231047 109.791434) (xy 166.090963 109.849316) (xy 165.983692 109.956399) + (xy 165.925566 110.096382) (xy 165.925434 110.247953) (xy 165.925434 111.390953) (xy 165.983316 111.531037) (xy 166.085184 111.633084) + (xy 165.983692 111.734399) (xy 165.925566 111.874382) (xy 165.925434 112.025953) (xy 165.925434 113.168953) (xy 165.983316 113.309037) + (xy 166.090399 113.416308) (xy 166.230382 113.474434) (xy 166.381953 113.474566) (xy 167.016953 113.474566) (xy 167.157037 113.416684) + (xy 167.264308 113.309601) (xy 167.322434 113.169618) (xy 167.322555 113.03) (xy 167.894 113.03) (xy 168.088403 112.991331) + (xy 168.25321 112.88121) (xy 170.47571 110.658711) (xy 170.47571 110.65871) (xy 170.54929 110.54859) (xy 170.58583 110.493904) + (xy 170.585831 110.493903) (xy 170.624499 110.2995) (xy 170.6245 110.2995) (xy 170.6245 109.5375) (xy 170.592246 109.375349) + (xy 170.585831 109.343097) (xy 170.585831 109.343096) (xy 170.47571 109.17829) (xy 169.818827 108.521407) (xy 170.089482 108.521643) + (xy 170.392998 108.396233) (xy 170.625417 108.164219) (xy 170.751357 107.860923) (xy 170.751643 107.532518) (xy 170.738196 107.499976) + (xy 170.919 107.425269) (xy 170.919 107.6) (xy 170.986062 107.937144) (xy 171.177039 108.222961) (xy 172.077039 109.122961) + (xy 172.362856 109.313938) (xy 172.7 109.381) (xy 173.374978 109.381) (xy 173.569664 109.576025) (xy 173.69061 109.626246) + (xy 173.482468 109.712461) (xy 173.39741 109.967805) (xy 174.29 110.860395) (xy 175.18259 109.967805) (xy 175.097532 109.712461) + (xy 174.876579 109.631771) (xy 175.008457 109.577281) (xy 175.366025 109.220336) (xy 175.559778 108.753727) (xy 175.560219 108.24849) + (xy 175.560219 110.213374) (xy 175.362195 110.14741) (xy 174.469605 111.04) (xy 175.362195 111.93259) (xy 175.617539 111.847532) + (xy 175.825514 111.278035) (xy 175.825514 115.473) (xy 175.560219 115.473) (xy 175.560219 113.32849) (xy 175.367281 112.861543) + (xy 175.010336 112.503975) (xy 174.889389 112.453753) (xy 175.097532 112.367539) (xy 175.18259 112.112195) (xy 174.29 111.219605) + (xy 174.110395 111.39921) (xy 174.110395 111.04) (xy 173.217805 110.14741) (xy 172.962461 110.232468) (xy 172.754486 110.801965) + (xy 172.780278 111.4077) (xy 172.962461 111.847532) (xy 173.217805 111.93259) (xy 174.110395 111.04) (xy 174.110395 111.39921) + (xy 173.39741 112.112195) (xy 173.482468 112.367539) (xy 173.70342 112.448228) (xy 173.571543 112.502719) (xy 173.213975 112.859664) + (xy 173.020222 113.326273) (xy 173.019781 113.83151) (xy 173.212719 114.298457) (xy 173.569664 114.656025) (xy 174.036273 114.849778) + (xy 174.54151 114.850219) (xy 175.008457 114.657281) (xy 175.366025 114.300336) (xy 175.559778 113.833727) (xy 175.560219 113.32849) + (xy 175.560219 115.473) (xy 165.798566 115.473) (xy 165.798566 113.018047) (xy 165.798566 111.875047) (xy 165.740684 111.734963) + (xy 165.638815 111.632915) (xy 165.740308 111.531601) (xy 165.798434 111.391618) (xy 165.798566 111.240047) (xy 165.798566 110.097047) + (xy 165.740684 109.956963) (xy 165.633601 109.849692) (xy 165.493618 109.791566) (xy 165.342047 109.791434) (xy 164.707047 109.791434) + (xy 164.566963 109.849316) (xy 164.459692 109.956399) (xy 164.417598 110.05777) (xy 164.403233 110.023002) (xy 164.171219 109.790583) + (xy 163.867923 109.664643) (xy 163.539518 109.664357) (xy 163.236002 109.789767) (xy 163.031339 109.994073) (xy 163.021553 109.970389) + (xy 162.700302 109.648577) (xy 162.280354 109.4742) (xy 161.825641 109.473803) (xy 161.405389 109.647447) (xy 161.083577 109.968698) + (xy 160.9092 110.388646) (xy 160.908803 110.843359) (xy 161.082447 111.263611) (xy 161.403698 111.585423) (xy 161.823646 111.7598) + (xy 162.278359 111.760197) (xy 162.698611 111.586553) (xy 163.020423 111.265302) (xy 163.105647 111.060058) (xy 163.170565 111.125089) + (xy 163.003583 111.291781) (xy 162.877643 111.595077) (xy 162.877357 111.923482) (xy 162.919894 112.02643) (xy 162.890118 112.014066) + (xy 162.738547 112.013934) (xy 161.214547 112.013934) (xy 161.074463 112.071816) (xy 160.967192 112.178899) (xy 160.909066 112.318882) + (xy 160.908934 112.470453) (xy 160.908934 113.994453) (xy 160.966816 114.134537) (xy 161.073899 114.241808) (xy 161.213882 114.299934) + (xy 161.365453 114.300066) (xy 162.889453 114.300066) (xy 163.029537 114.242184) (xy 163.136808 114.135101) (xy 163.194934 113.995118) + (xy 163.195066 113.843547) (xy 163.195066 112.419632) (xy 163.234781 112.459417) (xy 163.538077 112.585357) (xy 163.810173 112.585593) + (xy 164.105789 112.88121) (xy 164.10579 112.88121) (xy 164.21591 112.95479) (xy 164.270596 112.99133) (xy 164.270597 112.991331) + (xy 164.401434 113.017355) (xy 164.401434 113.168953) (xy 164.459316 113.309037) (xy 164.566399 113.416308) (xy 164.706382 113.474434) + (xy 164.857953 113.474566) (xy 165.492953 113.474566) (xy 165.633037 113.416684) (xy 165.740308 113.309601) (xy 165.798434 113.169618) + (xy 165.798566 113.018047) (xy 165.798566 115.473) (xy 159.563412 115.473) (xy 159.563412 111.944468) (xy 159.20169 111.069034) + (xy 158.532489 110.398664) (xy 157.657688 110.035415) (xy 156.710468 110.034588) (xy 155.835034 110.39631) (xy 155.164664 111.065511) + (xy 154.801415 111.940312) (xy 154.800588 112.887532) (xy 155.16231 113.762966) (xy 155.831511 114.433336) (xy 156.706312 114.796585) + (xy 157.653532 114.797412) (xy 158.528966 114.43569) (xy 159.199336 113.766489) (xy 159.562585 112.891688) (xy 159.563412 111.944468) + (xy 159.563412 115.473) (xy 151.906717 115.473) (xy 151.906717 109.928721) (xy 151.880314 109.338543) (xy 151.705258 108.91592) + (xy 151.453957 108.835648) (xy 150.589605 109.7) (xy 151.453957 110.564352) (xy 151.705258 110.48408) (xy 151.906717 109.928721) + (xy 151.906717 115.473) (xy 151.641213 115.473) (xy 151.641213 111.996213) (xy 151.454199 111.543606) (xy 151.108216 111.197018) + (xy 150.907849 111.113818) (xy 151.19408 110.995258) (xy 151.274352 110.743957) (xy 150.41 109.879605) (xy 150.230395 110.05921) + (xy 150.230395 109.7) (xy 149.366043 108.835648) (xy 149.114742 108.91592) (xy 149.08647 108.993856) (xy 149.08647 102.623925) + (xy 149.08647 100.376075) (xy 149.086249 100.123456) (xy 148.989373 99.890152) (xy 148.810589 99.711679) (xy 148.577115 99.61521) + (xy 147.76175 99.61532) (xy 147.603 99.77407) (xy 147.603 101.373) (xy 148.92761 101.373) (xy 149.08636 101.21425) + (xy 149.08647 100.376075) (xy 149.08647 102.623925) (xy 149.08636 101.78575) (xy 148.92761 101.627) (xy 147.603 101.627) + (xy 147.603 103.22593) (xy 147.76175 103.38468) (xy 148.577115 103.38479) (xy 148.810589 103.288321) (xy 148.989373 103.109848) + (xy 149.086249 102.876544) (xy 149.08647 102.623925) (xy 149.08647 108.993856) (xy 148.913283 109.471279) (xy 148.939686 110.061457) + (xy 149.114742 110.48408) (xy 149.366043 110.564352) (xy 150.230395 109.7) (xy 150.230395 110.05921) (xy 149.545648 110.743957) + (xy 149.62592 110.995258) (xy 149.931062 111.105949) (xy 149.713606 111.195801) (xy 149.367018 111.541784) (xy 149.179215 111.994065) + (xy 149.178787 112.483787) (xy 149.365801 112.936394) (xy 149.711784 113.282982) (xy 150.164065 113.470785) (xy 150.653787 113.471213) + (xy 151.106394 113.284199) (xy 151.452982 112.938216) (xy 151.640785 112.485935) (xy 151.641213 111.996213) (xy 151.641213 115.473) + (xy 141.627 115.473) (xy 141.627 112.648874) (xy 141.745801 112.936394) (xy 142.091784 113.282982) (xy 142.544065 113.470785) + (xy 143.033787 113.471213) (xy 143.486394 113.284199) (xy 143.832982 112.938216) (xy 143.911966 112.748) (xy 144.36 112.748) + (xy 144.554403 112.709331) (xy 144.71921 112.59921) (xy 145.85921 111.459211) (xy 145.85921 111.45921) (xy 145.93279 111.34909) + (xy 145.96933 111.294404) (xy 145.969331 111.294403) (xy 146.007999 111.1) (xy 146.008 111.1) (xy 146.008 103.155142) + (xy 146.141411 103.288321) (xy 146.374885 103.38479) (xy 147.19025 103.38468) (xy 147.349 103.22593) (xy 147.349 101.627) + (xy 147.329 101.627) (xy 147.329 101.373) (xy 147.349 101.373) (xy 147.349 99.77407) (xy 147.19025 99.61532) + (xy 146.374885 99.61521) (xy 146.141411 99.711679) (xy 146.008 99.844857) (xy 146.008 94.86042) (xy 148.660419 92.208) + (xy 152.255095 92.208) (xy 152.033002 92.299767) (xy 151.800583 92.531781) (xy 151.674643 92.835077) (xy 151.674357 93.163482) + (xy 151.799767 93.466998) (xy 152.031781 93.699417) (xy 152.335077 93.825357) (xy 152.362301 93.82538) (xy 152.732457 94.195536) + (xy 152.73246 94.19554) (xy 152.953392 94.343161) (xy 152.953393 94.343162) (xy 153.214 94.395) (xy 154.904934 94.395) + (xy 154.904934 94.539453) (xy 154.962816 94.679537) (xy 155.069899 94.786808) (xy 155.209882 94.844934) (xy 155.361453 94.845066) + (xy 157.393453 94.845066) (xy 157.533537 94.787184) (xy 157.640808 94.680101) (xy 157.676145 94.595) (xy 159.369254 94.595) + (xy 159.369254 96.026813) (xy 159.427136 96.166897) (xy 159.534219 96.274168) (xy 159.674202 96.332294) (xy 159.825773 96.332426) + (xy 161.110503 96.332426) (xy 161.238733 96.460656) (xy 161.127 96.57239) (xy 161.127 97.897) (xy 162.72593 97.897) + (xy 162.88468 97.73825) (xy 162.88479 96.922885) (xy 162.867483 96.881) (xy 164.323885 96.881) (xy 164.358816 96.965537) + (xy 164.465899 97.072808) (xy 164.605882 97.130934) (xy 164.757453 97.131066) (xy 166.789453 97.131066) (xy 166.929537 97.073184) + (xy 167.036808 96.966101) (xy 167.094934 96.826118) (xy 167.095066 96.674547) (xy 167.095066 95.174547) (xy 167.037184 95.034463) + (xy 167.025121 95.022378) (xy 167.074168 95.002013) (xy 167.252641 94.823229) (xy 167.34911 94.589755) (xy 167.349 93.99975) + (xy 167.19025 93.841) (xy 165.825 93.841) (xy 165.825 93.861) (xy 165.571 93.861) (xy 165.571 93.841) + (xy 164.20575 93.841) (xy 164.047 93.99975) (xy 164.04689 94.589755) (xy 164.143359 94.823229) (xy 164.321832 95.002013) + (xy 164.370775 95.022335) (xy 164.359192 95.033899) (xy 164.323854 95.119) (xy 162.630746 95.119) (xy 162.630746 93.925187) + (xy 162.572864 93.785103) (xy 162.465781 93.677832) (xy 162.325798 93.619706) (xy 162.174227 93.619574) (xy 160.889496 93.619574) + (xy 160.360961 93.091039) (xy 160.075144 92.900062) (xy 159.738 92.833) (xy 157.676114 92.833) (xy 157.641184 92.748463) + (xy 157.534101 92.641192) (xy 157.394118 92.583066) (xy 157.242547 92.582934) (xy 155.210547 92.582934) (xy 155.070463 92.640816) + (xy 154.963192 92.747899) (xy 154.905066 92.887882) (xy 154.904939 93.033) (xy 153.496079 93.033) (xy 153.32562 92.86254) + (xy 153.325643 92.836518) (xy 153.200233 92.533002) (xy 152.968219 92.300583) (xy 152.745255 92.208) (xy 164.551313 92.208) + (xy 164.745716 92.169331) (xy 164.910523 92.05921) (xy 165.024634 91.945098) (xy 165.024357 92.263482) (xy 165.051401 92.328934) + (xy 164.807755 92.32889) (xy 164.555136 92.329111) (xy 164.321832 92.425987) (xy 164.143359 92.604771) (xy 164.04689 92.838245) + (xy 164.047 93.42825) (xy 164.20575 93.587) (xy 165.571 93.587) (xy 165.571 93.567) (xy 165.825 93.567) + (xy 165.825 93.587) (xy 167.19025 93.587) (xy 167.349 93.42825) (xy 167.34911 92.838245) (xy 167.253975 92.608) + (xy 174.5 92.608) (xy 174.694403 92.569331) (xy 174.85921 92.45921) (xy 177.30921 90.00921) (xy 177.419331 89.844404) + (xy 177.419331 89.844403) (xy 177.425746 89.81215) (xy 177.457999 89.65) (xy 177.458 89.65) (xy 177.458 74.51042) + (xy 179.10921 72.859211) (xy 179.10921 72.85921) (xy 179.219331 72.694404) (xy 179.219331 72.694403) (xy 179.225746 72.66215) + (xy 179.257999 72.5) (xy 179.258 72.5) (xy 179.258 67.9) (xy 179.219331 67.705597) (xy 179.219331 67.705596) + (xy 179.10921 67.54079) (xy 177.108 65.53958) (xy 177.108 64.154404) (xy 177.291698 64.338423) (xy 177.711646 64.5128) + (xy 178.166359 64.513197) (xy 178.586611 64.339553) (xy 178.908423 64.018302) (xy 179.0828 63.598354) (xy 179.083197 63.143641) + (xy 178.909553 62.723389) (xy 178.588302 62.401577) (xy 178.168354 62.2272) (xy 177.713641 62.226803) (xy 177.293389 62.400447) + (xy 177.108 62.585512) (xy 177.108 62.5) (xy 177.075746 62.337849) (xy 177.069331 62.305597) (xy 177.069331 62.305596) + (xy 176.95921 62.14079) (xy 176.332541 61.514121) (xy 176.368423 61.478302) (xy 176.5428 61.058354) (xy 176.543197 60.603641) + (xy 176.369553 60.183389) (xy 176.048302 59.861577) (xy 175.724203 59.727) (xy 177.00558 59.727) (xy 176.962463 59.744816) + (xy 176.855192 59.851899) (xy 176.797066 59.991882) (xy 176.796934 60.143453) (xy 176.796934 61.667453) (xy 176.854816 61.807537) + (xy 176.961899 61.914808) (xy 177.101882 61.972934) (xy 177.253453 61.973066) (xy 178.777453 61.973066) (xy 178.917537 61.915184) + (xy 179.024808 61.808101) (xy 179.082934 61.668118) (xy 179.083066 61.516547) (xy 179.083066 60.40278) (xy 179.108491 60.531186) + (xy 179.172114 60.685167) (xy 179.17556 60.688619) (xy 179.821453 61.653443) (xy 179.823435 61.658239) (xy 179.941142 61.77615) + (xy 180.913844 62.427318) (xy 181.067713 62.49121) (xy 181.072583 62.491214) (xy 181.873 62.6497) (xy 181.873 76.873) + (xy 179.5 76.873) (xy 179.336594 76.905503) (xy 179.198065 76.998065) (xy 179.105503 77.136594) (xy 179.073 77.3) + (xy 179.073 96.311056) (xy 179.037141 96.224271) (xy 178.858668 96.045487) (xy 178.625364 95.948611) (xy 178.372745 95.94839) + (xy 178.21275 95.9485) (xy 178.054 96.10725) (xy 178.054 96.774) (xy 178.074 96.774) (xy 178.074 97.028) + (xy 178.054 97.028) (xy 178.054 97.048) (xy 177.8 97.048) (xy 177.8 97.028) (xy 177.78 97.028) + (xy 177.78 96.774) (xy 177.8 96.774) (xy 177.8 96.10725) (xy 177.64125 95.9485) (xy 177.481255 95.94839) + (xy 177.228636 95.948611) (xy 176.995332 96.045487) (xy 176.816859 96.224271) (xy 176.72039 96.457745) (xy 176.720424 96.507705) + (xy 176.662684 96.367963) (xy 176.555601 96.260692) (xy 176.415618 96.202566) (xy 176.363934 96.20252) (xy 176.467417 96.099219) + (xy 176.593357 95.795923) (xy 176.593643 95.467518) (xy 176.468233 95.164002) (xy 176.236219 94.931583) (xy 175.932923 94.805643) + (xy 175.604518 94.805357) (xy 175.301002 94.930767) (xy 175.068583 95.162781) (xy 174.942643 95.466077) (xy 174.942357 95.794482) + (xy 175.067767 96.097998) (xy 175.172021 96.202434) (xy 175.121047 96.202434) (xy 174.980963 96.260316) (xy 174.873692 96.367399) + (xy 174.815566 96.507382) (xy 174.815434 96.658953) (xy 174.815434 97.293953) (xy 174.873316 97.434037) (xy 174.980399 97.541308) + (xy 175.120382 97.599434) (xy 175.271953 97.599566) (xy 176.414953 97.599566) (xy 176.555037 97.541684) (xy 176.662308 97.434601) + (xy 176.720424 97.29464) (xy 176.72039 97.344255) (xy 176.816859 97.577729) (xy 176.995332 97.756513) (xy 177.117144 97.807094) + (xy 177.032692 97.891399) (xy 176.974566 98.031382) (xy 176.974434 98.182953) (xy 176.974434 98.817953) (xy 177.032316 98.958037) + (xy 177.139399 99.065308) (xy 177.279382 99.123434) (xy 177.331065 99.123479) (xy 177.227583 99.226781) (xy 177.101643 99.530077) + (xy 177.101357 99.858482) (xy 177.226767 100.161998) (xy 177.458781 100.394417) (xy 177.762077 100.520357) (xy 178.090482 100.520643) + (xy 178.393998 100.395233) (xy 178.626417 100.163219) (xy 178.752357 99.859923) (xy 178.752643 99.531518) (xy 178.627233 99.228002) + (xy 178.522978 99.123566) (xy 178.573953 99.123566) (xy 178.714037 99.065684) (xy 178.821308 98.958601) (xy 178.879434 98.818618) + (xy 178.879566 98.667047) (xy 178.879566 98.032047) (xy 178.821684 97.891963) (xy 178.736931 97.807062) (xy 178.858668 97.756513) + (xy 179.037141 97.577729) (xy 179.073 97.490943) (xy 179.073 98.15) (xy 179.105503 98.313406) (xy 179.198065 98.451935) + (xy 179.336594 98.544497) (xy 179.5 98.577) (xy 181.873 98.577) (xy 181.873 115.473) + ) + ) + ) + (zone (net 0) (net_name "") (layer B.Cu) (tstamp 56B51117) (hatch edge 0.508) + (connect_pads (clearance 0.25)) + (min_thickness 0.254) + (keepout (tracks allowed) (vias allowed) (copperpour not_allowed)) + (fill (arc_segments 16) (thermal_gap 0.4) (thermal_bridge_width 0.508)) + (polygon + (pts + (xy 166.37 87.884) (xy 164.719 86.487) (xy 164.719 84.074) (xy 166.878 84.963) (xy 166.878 87.884) + ) + ) + ) +) diff --git a/PCB v2.3d/Multipro-txV2-3d.net b/PCB v2.3d/Multipro-txV2-3d.net new file mode 100644 index 0000000..3177058 --- /dev/null +++ b/PCB v2.3d/Multipro-txV2-3d.net @@ -0,0 +1,644 @@ +(export (version D) + (design + (source "C:\\Documents and Settings\\Steve\\My Documents\\Multipro-tx\\MultiproV2.3d\\Multipro-txV2-3d.sch") + (date "05/02/2016 16:35:59") + (tool "eeschema (2013-07-07 BZR 4022)-stable")) + (components + (comp (ref IC1) + (value ATMEGA328-A) + (footprint TQFP32) + (libsource (lib atmel) (part ATMEGA328-A)) + (sheetpath (names /) (tstamps /)) + (tstamp 53BC5C99)) + (comp (ref C2) + (value 0.1uF) + (libsource (lib device) (part C)) + (sheetpath (names /) (tstamps /)) + (tstamp 53BC5DA8)) + (comp (ref R1) + (value 10K) + (libsource (lib device) (part R)) + (sheetpath (names /) (tstamps /)) + (tstamp 53BC5FEA)) + (comp (ref R4) + (value 1K) + (libsource (lib device) (part R)) + (sheetpath (names /) (tstamps /)) + (tstamp 53BC6125)) + (comp (ref D1) + (value LED) + (libsource (lib device) (part LED)) + (sheetpath (names /) (tstamps /)) + (tstamp 53BC617C)) + (comp (ref X1) + (value 16MHz) + (libsource (lib device) (part CRYSTAL)) + (sheetpath (names /) (tstamps /)) + (tstamp 53BC62D3)) + (comp (ref C4) + (value 18pF) + (libsource (lib device) (part C)) + (sheetpath (names /) (tstamps /)) + (tstamp 53BC62F4)) + (comp (ref C5) + (value 18pF) + (libsource (lib device) (part C)) + (sheetpath (names /) (tstamps /)) + (tstamp 53BC631E)) + (comp (ref U1) + (value NCP1117ST50T3G) + (libsource (lib regul) (part NCP1117ST50T3G)) + (sheetpath (names /) (tstamps /)) + (tstamp 53C2ACE9)) + (comp (ref U2) + (value NCP1117ST33T3G) + (libsource (lib regul) (part NCP1117ST50T3G)) + (sheetpath (names /) (tstamps /)) + (tstamp 53C2AD08)) + (comp (ref C1) + (value 22uF) + (libsource (lib device) (part CP1)) + (sheetpath (names /) (tstamps /)) + (tstamp 53C2AE5B)) + (comp (ref C3) + (value 22uF) + (libsource (lib device) (part CP1)) + (sheetpath (names /) (tstamps /)) + (tstamp 53C2AE76)) + (comp (ref C6) + (value 22uF) + (libsource (lib device) (part CP1)) + (sheetpath (names /) (tstamps /)) + (tstamp 53C2B150)) + (comp (ref R5) + (value 2K2) + (libsource (lib device) (part R)) + (sheetpath (names /) (tstamps /)) + (tstamp 53C2B787)) + (comp (ref R2) + (value 2K2) + (libsource (lib device) (part R)) + (sheetpath (names /) (tstamps /)) + (tstamp 53C2B990)) + (comp (ref R3) + (value 1K) + (libsource (lib device) (part R)) + (sheetpath (names /) (tstamps /)) + (tstamp 53C2B99F)) + (comp (ref U3) + (value CYRF6936) + (libsource (lib device) (part CYRF6936)) + (sheetpath (names /) (tstamps /)) + (tstamp 53C2BF57)) + (comp (ref U4) + (value A7105) + (libsource (lib device) (part A7105)) + (sheetpath (names /) (tstamps /)) + (tstamp 53C2C184)) + (comp (ref U5) + (value NRF24L01) + (libsource (lib device) (part NRF24L01)) + (sheetpath (names /) (tstamps /)) + (tstamp 53C2C24E)) + (comp (ref U6) + (value CC2500) + (libsource (lib device) (part CC2500)) + (sheetpath (names /) (tstamps /)) + (tstamp 53C2C3F4)) + (comp (ref R6) + (value 1K) + (libsource (lib device) (part R)) + (sheetpath (names /) (tstamps /)) + (tstamp 53C2D8C4)) + (comp (ref D2) + (value LED) + (libsource (lib device) (part LED)) + (sheetpath (names /) (tstamps /)) + (tstamp 53C2D9F8)) + (comp (ref P1) + (value ISP) + (libsource (lib conn) (part CONN_3X2)) + (sheetpath (names /) (tstamps /)) + (tstamp 53C2DBCC)) + (comp (ref P2) + (value CONN_5) + (libsource (lib conn) (part CONN_5)) + (sheetpath (names /) (tstamps /)) + (tstamp 53FE5423)) + (comp (ref JP2) + (value JUMPER) + (libsource (lib device) (part JUMPER)) + (sheetpath (names /) (tstamps /)) + (tstamp 53FE5887)) + (comp (ref JP4) + (value JUMPER) + (libsource (lib device) (part JUMPER)) + (sheetpath (names /) (tstamps /)) + (tstamp 53FE5896)) + (comp (ref SW1) + (value HEX_DIP) + (libsource (lib device) (part HEX_DIP)) + (sheetpath (names /) (tstamps /)) + (tstamp 54394777)) + (comp (ref C7) + (value 0.1uF) + (libsource (lib device) (part C)) + (sheetpath (names /) (tstamps /)) + (tstamp 54845FE2)) + (comp (ref R7) + (value 2K2) + (libsource (lib device) (part R)) + (sheetpath (names /) (tstamps /)) + (tstamp 54DCE006)) + (comp (ref P3) + (value CONN_2) + (libsource (lib conn) (part CONN_2)) + (sheetpath (names /) (tstamps /)) + (tstamp 56B4E4CA)) + (comp (ref JP3) + (value JUMPER) + (libsource (lib device) (part JUMPER)) + (sheetpath (names /) (tstamps /)) + (tstamp 56B4E4E1)) + (comp (ref R8) + (value 470) + (libsource (lib device) (part R)) + (sheetpath (names /) (tstamps /)) + (tstamp 56B4E6D8)) + (comp (ref SW2) + (value BIND) + (libsource (lib device) (part SW_PUSH_4_PIN)) + (sheetpath (names /) (tstamps /)) + (tstamp 56B4EC6E)) + (comp (ref SW3) + (value RESET) + (libsource (lib device) (part SW_PUSH_4_PIN)) + (sheetpath (names /) (tstamps /)) + (tstamp 56B4EC7B)) + (comp (ref JP1) + (value JUMPER) + (libsource (lib device) (part JUMPER)) + (sheetpath (names /) (tstamps /)) + (tstamp 56B4EFD5))) + (libparts + (libpart (lib device) (part A7105) + (fields + (field (name Reference) U) + (field (name Value) A7105) + (field (name Footprint) ~) + (field (name Datasheet) ~)) + (pins + (pin (num 1) (name 3V3) (type input)) + (pin (num 2) (name SCS) (type input)) + (pin (num 3) (name GND) (type input)) + (pin (num 4) (name SCK) (type input)) + (pin (num 5) (name SDIO) (type input)) + (pin (num 6) (name GIO1) (type input)) + (pin (num 7) (name GIO2) (type output)) + (pin (num 8) (name RXEN) (type input)) + (pin (num 9) (name TXEN) (type output)))) + (libpart (lib device) (part C) + (description "Condensateur non polarise") + (footprints + (fp SM*) + (fp C?) + (fp C1-1)) + (fields + (field (name Reference) C) + (field (name Value) C) + (field (name Footprint) ~) + (field (name Datasheet) ~)) + (pins + (pin (num 1) (name ~) (type passive)) + (pin (num 2) (name ~) (type passive)))) + (libpart (lib device) (part CC2500) + (fields + (field (name Reference) U) + (field (name Value) CC2500) + (field (name Footprint) ~) + (field (name Datasheet) ~)) + (pins + (pin (num 1) (name 3V3) (type input)) + (pin (num 2) (name SI) (type input)) + (pin (num 3) (name SCLK) (type input)) + (pin (num 4) (name SO) (type input)) + (pin (num 5) (name GDO2) (type input)) + (pin (num 6) (name GND) (type input)) + (pin (num 7) (name GDOo) (type input)) + (pin (num 8) (name CSn) (type input)) + (pin (num 9) (name PA_EN) (type input)) + (pin (num 10) (name LNA_EN) (type input)))) + (libpart (lib device) (part CP1) + (description "Condensateur polarise") + (footprints + (fp CP*) + (fp SM*)) + (fields + (field (name Reference) C) + (field (name Value) CP1) + (field (name Footprint) ~) + (field (name Datasheet) ~)) + (pins + (pin (num 1) (name ~) (type passive)) + (pin (num 2) (name ~) (type passive)))) + (libpart (lib device) (part CRYSTAL) + (fields + (field (name Reference) X) + (field (name Value) CRYSTAL) + (field (name Footprint) ~) + (field (name Datasheet) ~)) + (pins + (pin (num 1) (name 1) (type passive)) + (pin (num 2) (name 2) (type passive)) + (pin (num 3) (name 3) (type passive)) + (pin (num 4) (name 4) (type passive)))) + (libpart (lib device) (part CYRF6936) + (fields + (field (name Reference) U) + (field (name Value) CYRF6936) + (field (name Footprint) ~) + (field (name Datasheet) ~)) + (pins + (pin (num 1) (name 5.0V) (type input)) + (pin (num 2) (name NCS) (type input)) + (pin (num 4) (name SCK) (type input)) + (pin (num 5) (name GND) (type input)) + (pin (num 6) (name GND) (type input)) + (pin (num 8) (name MOSI) (type input)) + (pin (num 9) (name RST) (type input)) + (pin (num 10) (name MISO) (type input)))) + (libpart (lib device) (part HEX_DIP) + (fields + (field (name Reference) SW) + (field (name Value) HEX_DIP) + (field (name Footprint) ~) + (field (name Datasheet) ~)) + (pins + (pin (num 1) (name 1) (type output)) + (pin (num 2) (name C) (type passive)) + (pin (num 3) (name 4) (type output)) + (pin (num 4) (name 2) (type output)) + (pin (num 5) (name C) (type passive)) + (pin (num 6) (name 8) (type output)))) + (libpart (lib device) (part JUMPER) + (fields + (field (name Reference) JP) + (field (name Value) JUMPER) + (field (name Footprint) ~) + (field (name Datasheet) ~)) + (pins + (pin (num 1) (name 1) (type passive)) + (pin (num 2) (name 2) (type passive)))) + (libpart (lib device) (part LED) + (footprints + (fp LED-3MM) + (fp LED-5MM) + (fp LED-10MM) + (fp LED-0603) + (fp LED-0805) + (fp LED-1206) + (fp LEDV)) + (fields + (field (name Reference) D) + (field (name Value) LED) + (field (name Footprint) ~) + (field (name Datasheet) ~)) + (pins + (pin (num 1) (name A) (type passive)) + (pin (num 2) (name K) (type passive)))) + (libpart (lib device) (part NRF24L01) + (fields + (field (name Reference) U) + (field (name Value) NRF24L01) + (field (name Footprint) ~) + (field (name Datasheet) ~)) + (pins + (pin (num 1) (name GND) (type input)) + (pin (num 2) (name 3V3) (type input)) + (pin (num 3) (name CE) (type input)) + (pin (num 4) (name CSN) (type input)) + (pin (num 5) (name SCK) (type input)) + (pin (num 6) (name MOSI) (type input)) + (pin (num 7) (name MISO) (type input)) + (pin (num 8) (name IRQ) (type NotConnected)))) + (libpart (lib device) (part R) + (description Resistance) + (footprints + (fp R?) + (fp SM0603) + (fp SM0805) + (fp R?-*) + (fp SM1206)) + (fields + (field (name Reference) R) + (field (name Value) R) + (field (name Footprint) ~) + (field (name Datasheet) ~)) + (pins + (pin (num 1) (name ~) (type passive)) + (pin (num 2) (name ~) (type passive)))) + (libpart (lib device) (part SW_PUSH_4_Pin) + (description "Push Button 4 Pin") + (fields + (field (name Reference) SW) + (field (name Value) SW_PUSH_4_Pin) + (field (name Footprint) ~) + (field (name Datasheet) ~)) + (pins + (pin (num 1) (name 1) (type passive)) + (pin (num 2) (name 2) (type input)) + (pin (num 3) (name 3) (type passive)) + (pin (num 4) (name 4) (type input)))) + (libpart (lib conn) (part CONN_2) + (description "Symbole general de connecteur") + (fields + (field (name Reference) P) + (field (name Value) CONN_2) + (field (name Footprint) ~) + (field (name Datasheet) ~)) + (pins + (pin (num 1) (name P1) (type passive)) + (pin (num 2) (name PM) (type passive)))) + (libpart (lib conn) (part CONN_3X2) + (description "Symbole general de connecteur") + (fields + (field (name Reference) P) + (field (name Value) CONN_3X2) + (field (name Footprint) ~) + (field (name Datasheet) ~)) + (pins + (pin (num 1) (name 1) (type passive)) + (pin (num 2) (name 2) (type passive)) + (pin (num 3) (name 3) (type passive)) + (pin (num 4) (name 4) (type passive)) + (pin (num 5) (name 5) (type passive)) + (pin (num 6) (name 6) (type passive)))) + (libpart (lib conn) (part CONN_5) + (description "Symbole general de connecteur") + (fields + (field (name Reference) P) + (field (name Value) CONN_5) + (field (name Footprint) ~) + (field (name Datasheet) ~)) + (pins + (pin (num 1) (name ~) (type passive)) + (pin (num 2) (name ~) (type passive)) + (pin (num 3) (name ~) (type passive)) + (pin (num 4) (name ~) (type passive)) + (pin (num 5) (name ~) (type passive)))) + (libpart (lib regul) (part NCP1117ST50T3G) + (description "NCP1117ST50T3G, 1A Low drop-out regulator, Fixed Output 5V, SOT223") + (docs http://www.onsemi.com/pub_link/Collateral/NCP1117-D.PDF) + (footprints + (fp SOT223)) + (fields + (field (name Reference) U) + (field (name Value) NCP1117ST50T3G) + (field (name Footprint) ~) + (field (name Datasheet) ~)) + (pins + (pin (num 1) (name GND) (type power_in)) + (pin (num 2) (name VO) (type power_out)) + (pin (num 3) (name VI) (type power_in)))) + (libpart (lib atmel) (part ATMEGA168A-A) + (description "ATMEGA168A, TQFP32, 16k Flash, 1kB SRAM, 512B EEPROM") + (docs http://www.atmel.com/dyn/resources/prod_documents/doc8271.pdf) + (fields + (field (name Reference) IC) + (field (name Value) ATMEGA168A-A) + (field (name Footprint) TQFP32) + (field (name Datasheet) ~)) + (pins + (pin (num 1) (name "(PCINT19/OC2B/INT1)PD3") (type BiDi)) + (pin (num 2) (name "(PCINT20/XCK/T0)PD4") (type BiDi)) + (pin (num 3) (name GND) (type power_in)) + (pin (num 4) (name VCC) (type power_in)) + (pin (num 5) (name GND) (type power_in)) + (pin (num 6) (name VCC) (type power_in)) + (pin (num 7) (name "(PCINT6/XTAL1/TOSC1)PB6") (type BiDi)) + (pin (num 8) (name "(PCINT7/XTAL2/TOSC2)PB7") (type BiDi)) + (pin (num 9) (name "(PCINT21/OC0B/T1)PD5") (type BiDi)) + (pin (num 10) (name "(PCINT22/OC0A/AIN0)PD6") (type BiDi)) + (pin (num 11) (name "(PCINT23/AIN1)PD7") (type BiDi)) + (pin (num 12) (name "(PCINT0/CLKO/ICP1)PB0") (type BiDi)) + (pin (num 13) (name "(PCINT1/OC1A)PB1") (type BiDi)) + (pin (num 14) (name "(PCINT2/OC1B/~SS~)PB2") (type BiDi)) + (pin (num 15) (name "(PCINT3/OC2A/MOSI)PB3") (type BiDi)) + (pin (num 16) (name "(PCINT4/MISO)PB4") (type BiDi)) + (pin (num 17) (name "(PCINT5/SCK)PB5") (type BiDi)) + (pin (num 18) (name AVCC) (type power_in)) + (pin (num 19) (name ADC6) (type NotConnected)) + (pin (num 20) (name AREF) (type BiDi)) + (pin (num 21) (name GND) (type power_in)) + (pin (num 22) (name ADC7) (type NotConnected)) + (pin (num 23) (name "(PCINT8/ADC0)PC0") (type BiDi)) + (pin (num 24) (name "(PCINT9/ADC1)PC1") (type BiDi)) + (pin (num 25) (name "(PCINT10/ADC2)PC2") (type BiDi)) + (pin (num 26) (name "(PCINT11/ADC3)PC3") (type BiDi)) + (pin (num 27) (name "(PCINT12/SDA/ADC4)PC4") (type BiDi)) + (pin (num 28) (name "(PCINT14/SCL/ADC5)PC5") (type BiDi)) + (pin (num 29) (name "(PCINT14/~RESET~)PC6") (type BiDi)) + (pin (num 30) (name "(PCINT16/RXD)PD0") (type BiDi)) + (pin (num 31) (name "(PCINT17/TXD)PD1") (type BiDi)) + (pin (num 32) (name "(PCINT18/INT0)PD2") (type BiDi))))) + (libraries + (library (logical device) + (uri "C:\\Program Files\\KiCad\\share\\library\\device.lib")) + (library (logical conn) + (uri "C:\\Program Files\\KiCad\\share\\library\\conn.lib")) + (library (logical regul) + (uri "C:\\Program Files\\KiCad\\share\\library\\regul.lib")) + (library (logical atmel) + (uri "C:\\Program Files\\KiCad\\share\\library\\atmel.lib"))) + (nets + (net (code 1) (name GND) + (node (ref P2) (pin 4)) + (node (ref C7) (pin 2)) + (node (ref SW1) (pin 5)) + (node (ref SW1) (pin 2)) + (node (ref C5) (pin 2)) + (node (ref C4) (pin 1)) + (node (ref X1) (pin 4)) + (node (ref SW3) (pin 4)) + (node (ref SW3) (pin 3)) + (node (ref SW2) (pin 4)) + (node (ref SW2) (pin 3)) + (node (ref D1) (pin 2)) + (node (ref R3) (pin 2)) + (node (ref U6) (pin 6)) + (node (ref U5) (pin 1)) + (node (ref U4) (pin 3)) + (node (ref U3) (pin 6)) + (node (ref U3) (pin 5)) + (node (ref C3) (pin 2)) + (node (ref C1) (pin 2)) + (node (ref U2) (pin 1)) + (node (ref U1) (pin 1)) + (node (ref C6) (pin 2)) + (node (ref IC1) (pin 21)) + (node (ref IC1) (pin 5)) + (node (ref IC1) (pin 3)) + (node (ref X1) (pin 2)) + (node (ref C2) (pin 2)) + (node (ref D2) (pin 2)) + (node (ref P1) (pin 6))) + (net (code 2) (name "") + (node (ref D2) (pin 1)) + (node (ref R6) (pin 2))) + (net (code 3) (name 3V3) + (node (ref R5) (pin 2)) + (node (ref U6) (pin 1)) + (node (ref U5) (pin 2)) + (node (ref C7) (pin 1)) + (node (ref U4) (pin 1)) + (node (ref U2) (pin 2)) + (node (ref IC1) (pin 18)) + (node (ref IC1) (pin 6)) + (node (ref P1) (pin 2)) + (node (ref IC1) (pin 4)) + (node (ref R1) (pin 1)) + (node (ref C6) (pin 1))) + (net (code 4) (name /CC25_CSN) + (node (ref IC1) (pin 11)) + (node (ref U6) (pin 8))) + (net (code 5) (name /MISO) + (node (ref U3) (pin 10)) + (node (ref IC1) (pin 10)) + (node (ref U5) (pin 7)) + (node (ref U6) (pin 4))) + (net (code 6) (name /SCK) + (node (ref IC1) (pin 2)) + (node (ref U4) (pin 4)) + (node (ref U6) (pin 3)) + (node (ref U3) (pin 4)) + (node (ref U5) (pin 5))) + (net (code 7) (name /MOSI) + (node (ref U5) (pin 6)) + (node (ref IC1) (pin 9)) + (node (ref U6) (pin 2)) + (node (ref U4) (pin 5)) + (node (ref U3) (pin 8))) + (net (code 8) (name +5V) + (node (ref U2) (pin 3)) + (node (ref U1) (pin 2)) + (node (ref C3) (pin 1)) + (node (ref U3) (pin 1)) + (node (ref R6) (pin 1))) + (net (code 9) (name /D11) + (node (ref P1) (pin 4)) + (node (ref SW1) (pin 4)) + (node (ref IC1) (pin 15))) + (net (code 10) (name /RESET) + (node (ref IC1) (pin 29)) + (node (ref SW3) (pin 1)) + (node (ref P1) (pin 5)) + (node (ref R1) (pin 2)) + (node (ref SW3) (pin 2))) + (net (code 11) (name /D12) + (node (ref P1) (pin 1)) + (node (ref IC1) (pin 16)) + (node (ref SW1) (pin 3))) + (net (code 12) (name "") + (node (ref U4) (pin 7)) + (node (ref U4) (pin 8))) + (net (code 13) (name "") + (node (ref U4) (pin 6)) + (node (ref U4) (pin 9))) + (net (code 14) (name /A7105_CSN) + (node (ref IC1) (pin 32)) + (node (ref U4) (pin 2))) + (net (code 15) (name /CC25_LANEN) + (node (ref U6) (pin 5)) + (node (ref U6) (pin 10))) + (net (code 16) (name /CC25_PAEN) + (node (ref U6) (pin 9)) + (node (ref U6) (pin 7))) + (net (code 17) (name /NRF_CE) + (node (ref R5) (pin 1)) + (node (ref U5) (pin 3))) + (net (code 18) (name /NRF_CSN) + (node (ref U5) (pin 4)) + (node (ref IC1) (pin 12))) + (net (code 19) (name "") + (node (ref R8) (pin 1)) + (node (ref P3) (pin 2)) + (node (ref JP3) (pin 2))) + (net (code 20) (name /PPM_IN) + (node (ref JP2) (pin 1)) + (node (ref P2) (pin 1)) + (node (ref R2) (pin 2))) + (net (code 21) (name "") + (node (ref JP3) (pin 1)) + (node (ref P2) (pin 5))) + (net (code 22) (name "") + (node (ref JP4) (pin 2)) + (node (ref P3) (pin 1))) + (net (code 23) (name "") + (node (ref JP2) (pin 2)) + (node (ref R7) (pin 1))) + (net (code 24) (name "") + (node (ref R3) (pin 1)) + (node (ref JP1) (pin 2))) + (net (code 25) (name /RX) + (node (ref IC1) (pin 30)) + (node (ref R7) (pin 2))) + (net (code 26) (name "") + (node (ref P2) (pin 2)) + (node (ref JP4) (pin 1))) + (net (code 27) (name /TX) + (node (ref IC1) (pin 31)) + (node (ref R8) (pin 2))) + (net (code 28) (name /CYRF_RST) + (node (ref IC1) (pin 28)) + (node (ref U3) (pin 9))) + (net (code 29) (name /CYRF_CSN) + (node (ref U3) (pin 2)) + (node (ref IC1) (pin 13))) + (net (code 30) (name /A0) + (node (ref IC1) (pin 23)) + (node (ref SW1) (pin 6))) + (net (code 31) (name /D10) + (node (ref SW1) (pin 1)) + (node (ref IC1) (pin 14))) + (net (code 32) (name /xtl2) + (node (ref X1) (pin 1)) + (node (ref IC1) (pin 8)) + (node (ref C5) (pin 1))) + (net (code 33) (name /xtl1) + (node (ref IC1) (pin 7)) + (node (ref X1) (pin 3)) + (node (ref C4) (pin 2))) + (net (code 34) (name "") + (node (ref D1) (pin 1)) + (node (ref SW2) (pin 1)) + (node (ref SW2) (pin 2)) + (node (ref R4) (pin 2))) + (net (code 35) (name /A3) + (node (ref IC1) (pin 26))) + (net (code 36) (name /D3) + (node (ref IC1) (pin 1)) + (node (ref R2) (pin 1)) + (node (ref JP1) (pin 1))) + (net (code 37) (name /A4) + (node (ref IC1) (pin 27))) + (net (code 38) (name /A2) + (node (ref IC1) (pin 25))) + (net (code 39) (name /A1) + (node (ref IC1) (pin 24))) + (net (code 40) (name /A6) + (node (ref IC1) (pin 19))) + (net (code 41) (name /A7) + (node (ref IC1) (pin 22))) + (net (code 42) (name /PB5) + (node (ref P1) (pin 3)) + (node (ref IC1) (pin 17)) + (node (ref R4) (pin 1))) + (net (code 43) (name "") + (node (ref IC1) (pin 20)) + (node (ref C2) (pin 1))) + (net (code 44) (name "") + (node (ref U5) (pin 8))) + (net (code 45) (name /BATT) + (node (ref C1) (pin 1)) + (node (ref P2) (pin 3)) + (node (ref U1) (pin 3))))) \ No newline at end of file diff --git a/PCB v2.3d/Multipro-txV2-3d.pro b/PCB v2.3d/Multipro-txV2-3d.pro new file mode 100644 index 0000000..1e8e02d --- /dev/null +++ b/PCB v2.3d/Multipro-txV2-3d.pro @@ -0,0 +1,41 @@ +update=04/02/2016 18:14:57 +last_client=pcbnew +[pcbnew] +version=1 +LastNetListRead=Multipro-txV2-3d.net +UseCmpFile=1 +PadDrill=0.750000000000 +PadDrillOvalY=0.750000000000 +PadSizeH=1.250000000000 +PadSizeV=1.250000000000 +PcbTextSizeV=1.500000000000 +PcbTextSizeH=1.500000000000 +PcbTextThickness=0.300000000000 +ModuleTextSizeV=1.000000000000 +ModuleTextSizeH=1.000000000000 +ModuleTextSizeThickness=0.150000000000 +SolderMaskClearance=0.000000000000 +SolderMaskMinWidth=0.000000000000 +DrawSegmentWidth=0.400000000000 +BoardOutlineThickness=0.100000000000 +ModuleOutlineThickness=0.150000000000 +[pcbnew/libraries] +LibDir=../Multipro-txV2 +LibName1=sockets +LibName2=connect +LibName3=discret +LibName4=pin_array +LibName5=divers +LibName6=smd_capacitors +LibName7=smd_resistors +LibName8=smd_crystal&oscillator +LibName9=smd_dil +LibName10=smd_transistors +LibName11=libcms +LibName12=display +LibName13=led +LibName14=dip_sockets +LibName15=pga_sockets +LibName16=valves +LibName17=Logo +LibName18=LogoBsilk diff --git a/PCB v2.3d/Multipro-txV2-3d.sch b/PCB v2.3d/Multipro-txV2-3d.sch new file mode 100644 index 0000000..df2fb8d --- /dev/null +++ b/PCB v2.3d/Multipro-txV2-3d.sch @@ -0,0 +1,1452 @@ +EESchema Schematic File Version 2 +LIBS:power +LIBS:device +LIBS:transistors +LIBS:conn +LIBS:linear +LIBS:regul +LIBS:74xx +LIBS:cmos4000 +LIBS:adc-dac +LIBS:memory +LIBS:xilinx +LIBS:special +LIBS:microcontrollers +LIBS:dsp +LIBS:microchip +LIBS:analog_switches +LIBS:motorola +LIBS:texas +LIBS:intel +LIBS:audio +LIBS:interface +LIBS:digital-audio +LIBS:philips +LIBS:display +LIBS:cypress +LIBS:siliconi +LIBS:opto +LIBS:atmel +LIBS:contrib +LIBS:valves +LIBS:Multipro-txV2-3d-cache +EELAYER 27 0 +EELAYER END +$Descr A4 11693 8268 +encoding utf-8 +Sheet 1 1 +Title "" +Date "5 feb 2016" +Rev "" +Comp "" +Comment1 "" +Comment2 "" +Comment3 "" +Comment4 "" +$EndDescr +$Comp +L ATMEGA328-A IC1 +U 1 1 53BC5C99 +P 3300 4100 +F 0 "IC1" H 2550 5350 40 0000 L BNN +F 1 "ATMEGA328-A" H 3700 2700 40 0000 L BNN +F 2 "TQFP32" H 3300 4100 30 0000 C CIN +F 3 "" H 3300 4100 60 0000 C CNN + 1 3300 4100 + 1 0 0 -1 +$EndComp +Wire Wire Line + 2050 3300 2400 3300 +Wire Wire Line + 2050 2700 2050 3000 +Wire Wire Line + 2050 3000 2050 3100 +Wire Wire Line + 2050 3100 2050 3300 +Wire Wire Line + 2400 3100 2050 3100 +Connection ~ 2050 3100 +Wire Wire Line + 2400 3000 2050 3000 +Connection ~ 2050 3000 +$Comp +L C C2 +U 1 1 53BC5DA8 +P 1700 3900 +F 0 "C2" H 1700 4000 40 0000 L CNN +F 1 "0.1uF" H 1706 3815 40 0000 L CNN +F 2 "~" H 1738 3750 30 0000 C CNN +F 3 "~" H 1700 3900 60 0000 C CNN + 1 1700 3900 + 1 0 0 -1 +$EndComp +Wire Wire Line + 2400 3600 1700 3600 +Wire Wire Line + 1700 3600 1700 3700 +$Comp +L GND #PWR01 +U 1 1 53BC5DDF +P 1700 4250 +F 0 "#PWR01" H 1700 4250 30 0001 C CNN +F 1 "GND" H 1700 4180 30 0001 C CNN +F 2 "" H 1700 4250 60 0000 C CNN +F 3 "" H 1700 4250 60 0000 C CNN + 1 1700 4250 + 1 0 0 -1 +$EndComp +Wire Wire Line + 1700 4100 1700 4250 +$Comp +L GND #PWR02 +U 1 1 53BC5E19 +P 2150 5600 +F 0 "#PWR02" H 2150 5600 30 0001 C CNN +F 1 "GND" H 2150 5530 30 0001 C CNN +F 2 "" H 2150 5600 60 0000 C CNN +F 3 "" H 2150 5600 60 0000 C CNN + 1 2150 5600 + 1 0 0 -1 +$EndComp +Wire Wire Line + 2400 5100 2150 5100 +Wire Wire Line + 2150 5100 2150 5200 +Wire Wire Line + 2150 5200 2150 5300 +Wire Wire Line + 2150 5300 2150 5600 +Wire Wire Line + 2400 5200 2150 5200 +Connection ~ 2150 5200 +Wire Wire Line + 2400 5300 2150 5300 +Connection ~ 2150 5300 +Wire Wire Line + 4300 4450 4900 4450 +Wire Wire Line + 4900 4450 5050 4450 +$Comp +L R R1 +U 1 1 53BC5FEA +P 4900 4100 +F 0 "R1" V 4980 4100 40 0000 C CNN +F 1 "10K" V 4907 4101 40 0000 C CNN +F 2 "~" V 4830 4100 30 0000 C CNN +F 3 "~" H 4900 4100 30 0000 C CNN + 1 4900 4100 + 1 0 0 -1 +$EndComp +Connection ~ 4900 4450 +Wire Wire Line + 4900 3850 4900 3750 +$Comp +L GND #PWR03 +U 1 1 53BC607C +P 5850 4650 +F 0 "#PWR03" H 5850 4650 30 0001 C CNN +F 1 "GND" H 5850 4580 30 0001 C CNN +F 2 "" H 5850 4650 60 0000 C CNN +F 3 "" H 5850 4650 60 0000 C CNN + 1 5850 4650 + 1 0 0 -1 +$EndComp +Wire Wire Line + 5650 4450 5850 4450 +Wire Wire Line + 5850 4450 5850 4650 +Wire Wire Line + 4900 4350 4900 4450 +Wire Wire Line + 5700 3850 5700 3500 +$Comp +L R R4 +U 1 1 53BC6125 +P 5250 3500 +F 0 "R4" V 5330 3500 40 0000 C CNN +F 1 "1K" V 5257 3501 40 0000 C CNN +F 2 "~" V 5180 3500 30 0000 C CNN +F 3 "~" H 5250 3500 30 0000 C CNN + 1 5250 3500 + 0 -1 -1 0 +$EndComp +Wire Wire Line + 6300 3850 6300 3950 +$Comp +L GND #PWR04 +U 1 1 53BC6155 +P 6300 3950 +F 0 "#PWR04" H 6300 3950 30 0001 C CNN +F 1 "GND" H 6300 3880 30 0001 C CNN +F 2 "" H 6300 3950 60 0000 C CNN +F 3 "" H 6300 3950 60 0000 C CNN + 1 6300 3950 + 1 0 0 -1 +$EndComp +$Comp +L LED D1 +U 1 1 53BC617C +P 6000 3850 +F 0 "D1" H 6000 3950 50 0000 C CNN +F 1 "LED" H 6000 3750 50 0000 C CNN +F 2 "~" H 6000 3850 60 0000 C CNN +F 3 "~" H 6000 3850 60 0000 C CNN + 1 6000 3850 + 1 0 0 -1 +$EndComp +Wire Wire Line + 5700 3850 5800 3850 +Wire Wire Line + 6200 3850 6300 3850 +$Comp +L CRYSTAL X1 +U 1 1 53BC62D3 +P 2500 6450 +F 0 "X1" V 2450 6750 60 0000 C CNN +F 1 "16MHz" V 2550 6750 60 0000 C CNN +F 2 "~" H 2500 6450 60 0000 C CNN +F 3 "~" H 2500 6450 60 0000 C CNN + 1 2500 6450 + -1 0 0 -1 +$EndComp +$Comp +L C C4 +U 1 1 53BC62F4 +P 3000 6250 +F 0 "C4" V 3050 6350 40 0000 L CNN +F 1 "18pF" V 3150 6200 40 0000 L CNN +F 2 "~" H 3038 6100 30 0000 C CNN +F 3 "~" H 3000 6250 60 0000 C CNN + 1 3000 6250 + -1 0 0 1 +$EndComp +$Comp +L C C5 +U 1 1 53BC631E +P 3000 6650 +F 0 "C5" V 3050 6750 40 0000 L CNN +F 1 "18pF" V 3150 6600 40 0000 L CNN +F 2 "~" H 3038 6500 30 0000 C CNN +F 3 "~" H 3000 6650 60 0000 C CNN + 1 3000 6650 + -1 0 0 1 +$EndComp +Wire Wire Line + 2000 6050 2200 6050 +Wire Wire Line + 2200 6050 3000 6050 +Wire Wire Line + 2000 6850 2800 6850 +Wire Wire Line + 2800 6850 3000 6850 +$Comp +L GND #PWR05 +U 1 1 53BC636B +P 3350 6800 +F 0 "#PWR05" H 3350 6800 30 0001 C CNN +F 1 "GND" H 3350 6730 30 0001 C CNN +F 2 "" H 3350 6800 60 0000 C CNN +F 3 "" H 3350 6800 60 0000 C CNN + 1 3350 6800 + 1 0 0 -1 +$EndComp +Text Label 2000 6050 0 60 ~ 0 +xtl1 +Text Label 2050 6850 0 60 ~ 0 +xtl2 +Wire Wire Line + 4300 3600 4650 3600 +Wire Wire Line + 4300 3700 4650 3700 +Text Label 4450 3600 0 60 ~ 0 +xtl1 +Text Label 4450 3700 0 60 ~ 0 +xtl2 +Wire Wire Line + 4300 3850 4650 3850 +Text Label 4500 3850 0 60 ~ 0 +A0 +Wire Wire Line + 4300 3950 4650 3950 +Wire Wire Line + 4300 4050 4650 4050 +Wire Wire Line + 4300 4150 4650 4150 +Wire Wire Line + 4300 4250 4650 4250 +Wire Wire Line + 4300 4350 4800 4350 +Wire Wire Line + 2400 4350 2100 4350 +Wire Wire Line + 2400 4450 2100 4450 +Text Label 2150 4450 0 60 ~ 0 +A7 +Text Label 2150 4350 0 60 ~ 0 +A6 +Text Label 4500 3950 0 60 ~ 0 +A1 +Text Label 4500 4050 0 60 ~ 0 +A2 +Text Label 4500 4150 0 60 ~ 0 +A3 +Text Label 4500 4250 0 60 ~ 0 +A4 +Text Label 4350 4350 0 60 ~ 0 +CYRF_RST +Wire Wire Line + 4300 4600 4650 4600 +Wire Wire Line + 4300 4700 4650 4700 +Wire Wire Line + 4300 4800 5100 4800 +Wire Wire Line + 4300 4900 5350 4900 +Wire Wire Line + 5350 4900 5450 4900 +Wire Wire Line + 4300 5000 5100 5000 +Wire Wire Line + 4300 5100 5100 5100 +Wire Wire Line + 4300 5200 5100 5200 +Wire Wire Line + 4300 5300 5100 5300 +Text Label 4450 4600 0 60 ~ 0 +RX +Text Label 4450 4700 0 60 ~ 0 +TX +Text Label 4450 4800 0 60 ~ 0 +A7105_CSN +Text Label 4450 4900 0 60 ~ 0 +D3 +Text Label 4450 5000 0 60 ~ 0 +SCK +Text Label 4450 5100 0 60 ~ 0 +MOSI +Text Label 4450 5200 0 60 ~ 0 +MISO +Text Label 4450 5300 0 60 ~ 0 +CC25_CSN +Wire Wire Line + 4300 3000 4950 3000 +Wire Wire Line + 4300 3100 4950 3100 +Wire Wire Line + 4300 3200 4650 3200 +Wire Wire Line + 4300 3300 4650 3300 +Wire Wire Line + 4300 3400 4650 3400 +Text Label 4450 3000 0 60 ~ 0 +NRF_CSN +Text Label 4450 3100 0 60 ~ 0 +CYRF_CSN +Text Label 4450 3200 0 60 ~ 0 +D10 +Text Label 4450 3300 0 60 ~ 0 +D11 +Text Label 4450 3400 0 60 ~ 0 +D12 +Wire Wire Line + 4300 3500 5000 3500 +Wire Wire Line + 5500 3500 5700 3500 +Wire Wire Line + 5700 3500 5800 3500 +$Comp +L +BATT #PWR06 +U 1 1 53C2AB0F +P 900 950 +F 0 "#PWR06" H 900 900 20 0001 C CNN +F 1 "+BATT" H 900 1050 30 0000 C CNN +F 2 "" H 900 950 60 0000 C CNN +F 3 "" H 900 950 60 0000 C CNN + 1 900 950 + 1 0 0 -1 +$EndComp +$Comp +L 3V3 #PWR07 +U 1 1 53C2AB1E +P 3800 1000 +F 0 "#PWR07" H 3800 1100 40 0001 C CNN +F 1 "3V3" H 3800 1125 40 0000 C CNN +F 2 "" H 3800 1000 60 0000 C CNN +F 3 "" H 3800 1000 60 0000 C CNN + 1 3800 1000 + 1 0 0 -1 +$EndComp +$Comp +L NCP1117ST50T3G U1 +U 1 1 53C2ACE9 +P 1550 1350 +F 0 "U1" H 1700 1154 40 0000 C CNN +F 1 "NCP1117ST50T3G" H 1550 1550 40 0000 C CNN +F 2 "~" H 1550 1350 60 0000 C CNN +F 3 "~" H 1550 1350 60 0000 C CNN + 1 1550 1350 + 1 0 0 -1 +$EndComp +$Comp +L NCP1117ST50T3G U2 +U 1 1 53C2AD08 +P 3150 1350 +F 0 "U2" H 3300 1154 40 0000 C CNN +F 1 "NCP1117ST33T3G" H 3150 1550 40 0000 C CNN +F 2 "~" H 3150 1350 60 0000 C CNN +F 3 "~" H 3150 1350 60 0000 C CNN + 1 3150 1350 + 1 0 0 -1 +$EndComp +$Comp +L CP1 C1 +U 1 1 53C2AE5B +P 900 1500 +F 0 "C1" H 950 1600 50 0000 L CNN +F 1 "22uF" H 950 1400 50 0000 L CNN +F 2 "~" H 900 1500 60 0000 C CNN +F 3 "~" H 900 1500 60 0000 C CNN + 1 900 1500 + 1 0 0 -1 +$EndComp +$Comp +L CP1 C3 +U 1 1 53C2AE76 +P 2150 1500 +F 0 "C3" H 2200 1600 50 0000 L CNN +F 1 "22uF" H 2200 1400 50 0000 L CNN +F 2 "~" H 2150 1500 60 0000 C CNN +F 3 "~" H 2150 1500 60 0000 C CNN + 1 2150 1500 + 1 0 0 -1 +$EndComp +$Comp +L GND #PWR08 +U 1 1 53C2AEB5 +P 1550 1900 +F 0 "#PWR08" H 1550 1900 30 0001 C CNN +F 1 "GND" H 1550 1830 30 0001 C CNN +F 2 "" H 1550 1900 60 0000 C CNN +F 3 "" H 1550 1900 60 0000 C CNN + 1 1550 1900 + 1 0 0 -1 +$EndComp +$Comp +L GND #PWR09 +U 1 1 53C2AEC4 +P 900 1900 +F 0 "#PWR09" H 900 1900 30 0001 C CNN +F 1 "GND" H 900 1830 30 0001 C CNN +F 2 "" H 900 1900 60 0000 C CNN +F 3 "" H 900 1900 60 0000 C CNN + 1 900 1900 + 1 0 0 -1 +$EndComp +Wire Wire Line + 900 1700 900 1900 +Wire Wire Line + 900 1300 1150 1300 +Wire Wire Line + 900 950 900 1300 +Wire Wire Line + 1950 1300 2150 1300 +Wire Wire Line + 2150 1300 2500 1300 +Wire Wire Line + 2500 1300 2750 1300 +Wire Wire Line + 1550 1600 1550 1700 +Wire Wire Line + 1550 1700 1550 1900 +Wire Wire Line + 2150 1700 1550 1700 +Connection ~ 1550 1700 +Connection ~ 2150 1300 +$Comp +L +5V #PWR010 +U 1 1 53C2B0E8 +P 2500 1000 +F 0 "#PWR010" H 2500 1090 20 0001 C CNN +F 1 "+5V" H 2500 1090 30 0000 C CNN +F 2 "" H 2500 1000 60 0000 C CNN +F 3 "" H 2500 1000 60 0000 C CNN + 1 2500 1000 + 1 0 0 -1 +$EndComp +Wire Wire Line + 2500 1000 2500 1300 +Wire Wire Line + 2500 1300 2500 1400 +$Comp +L CP1 C6 +U 1 1 53C2B150 +P 3800 1500 +F 0 "C6" H 3850 1600 50 0000 L CNN +F 1 "22uF" H 3850 1400 50 0000 L CNN +F 2 "~" H 3800 1500 60 0000 C CNN +F 3 "~" H 3800 1500 60 0000 C CNN + 1 3800 1500 + 1 0 0 -1 +$EndComp +$Comp +L GND #PWR011 +U 1 1 53C2B15F +P 3150 1900 +F 0 "#PWR011" H 3150 1900 30 0001 C CNN +F 1 "GND" H 3150 1830 30 0001 C CNN +F 2 "" H 3150 1900 60 0000 C CNN +F 3 "" H 3150 1900 60 0000 C CNN + 1 3150 1900 + 1 0 0 -1 +$EndComp +Wire Wire Line + 3150 1600 3150 1700 +Wire Wire Line + 3150 1700 3150 1900 +Wire Wire Line + 3800 1700 3150 1700 +Connection ~ 3150 1700 +Wire Wire Line + 3550 1300 3800 1300 +Wire Wire Line + 3800 1300 3800 1000 +Entry Wire Line + 8100 2950 8200 3050 +Wire Wire Line + 8100 2650 7400 2650 +Entry Wire Line + 8100 3250 8200 3350 +Entry Wire Line + 8100 3100 8200 3200 +Entry Wire Line + 8100 3400 8200 3500 +Entry Wire Line + 8100 3550 8200 3650 +Entry Wire Line + 8100 3700 8200 3800 +Entry Wire Line + 8100 2800 8200 2900 +Entry Wire Line + 8100 2650 8200 2750 +Wire Wire Line + 8100 2800 7400 2800 +Wire Wire Line + 8100 2950 7400 2950 +Wire Wire Line + 8100 3100 7400 3100 +Wire Wire Line + 8100 3250 7400 3250 +Wire Wire Line + 8100 3400 7400 3400 +Wire Wire Line + 8100 3550 7400 3550 +Wire Wire Line + 8100 3700 7400 3700 +Text Label 7450 3700 0 60 ~ 0 +CYRF_RST +Text Label 7450 3550 0 60 ~ 0 +A7105_CSN +Text Label 7450 3400 0 60 ~ 0 +SCK +Text Label 7450 3250 0 60 ~ 0 +MOSI +Text Label 7450 3100 0 60 ~ 0 +MISO +Text Label 7450 2950 0 60 ~ 0 +CC25_CSN +Text Label 7450 2800 0 60 ~ 0 +NRF_CSN +Text Label 7450 2650 0 60 ~ 0 +CYRF_CSN +Entry Wire Line + 8100 4800 8200 4900 +$Comp +L R R5 +U 1 1 53C2B787 +P 7450 4800 +F 0 "R5" V 7530 4800 40 0000 C CNN +F 1 "2K2" V 7457 4801 40 0000 C CNN +F 2 "~" V 7380 4800 30 0000 C CNN +F 3 "~" H 7450 4800 30 0000 C CNN + 1 7450 4800 + 0 1 1 0 +$EndComp +$Comp +L 3V3 #PWR012 +U 1 1 53C2B7A5 +P 7200 4600 +F 0 "#PWR012" H 7200 4700 40 0001 C CNN +F 1 "3V3" H 7200 4725 40 0000 C CNN +F 2 "" H 7200 4600 60 0000 C CNN +F 3 "" H 7200 4600 60 0000 C CNN + 1 7200 4600 + 1 0 0 -1 +$EndComp +Wire Wire Line + 7200 4600 7200 4800 +Wire Wire Line + 7700 4800 8100 4800 +Text Label 7750 4800 0 60 ~ 0 +NRF_CE +$Comp +L 3V3 #PWR013 +U 1 1 53C2B981 +P 2050 2700 +F 0 "#PWR013" H 2050 2800 40 0001 C CNN +F 1 "3V3" H 2050 2825 40 0000 C CNN +F 2 "" H 2050 2700 60 0000 C CNN +F 3 "" H 2050 2700 60 0000 C CNN + 1 2050 2700 + 1 0 0 -1 +$EndComp +$Comp +L R R2 +U 1 1 53C2B990 +P 5700 4900 +F 0 "R2" V 5780 4900 40 0000 C CNN +F 1 "2K2" V 5707 4901 40 0000 C CNN +F 2 "~" V 5630 4900 30 0000 C CNN +F 3 "~" H 5700 4900 30 0000 C CNN + 1 5700 4900 + 0 -1 -1 0 +$EndComp +$Comp +L R R3 +U 1 1 53C2B99F +P 6450 5300 +F 0 "R3" V 6530 5300 40 0000 C CNN +F 1 "1K" V 6457 5301 40 0000 C CNN +F 2 "~" V 6380 5300 30 0000 C CNN +F 3 "~" H 6450 5300 30 0000 C CNN + 1 6450 5300 + 0 -1 -1 0 +$EndComp +Wire Wire Line + 5950 4900 6500 4900 +$Comp +L GND #PWR014 +U 1 1 53C2BAA6 +P 6700 5500 +F 0 "#PWR014" H 6700 5500 30 0001 C CNN +F 1 "GND" H 6700 5430 30 0001 C CNN +F 2 "" H 6700 5500 60 0000 C CNN +F 3 "" H 6700 5500 60 0000 C CNN + 1 6700 5500 + 1 0 0 -1 +$EndComp +Wire Wire Line + 6700 5300 6700 5500 +Text Label 6150 4900 0 60 ~ 0 +PPM_IN +$Comp +L CYRF6936 U3 +U 1 1 53C2BF57 +P 10350 1350 +F 0 "U3" H 10850 1900 60 0000 C CNN +F 1 "CYRF6936" H 10350 2150 60 0000 C CNN +F 2 "" H 10350 950 60 0000 C CNN +F 3 "" H 10350 950 60 0000 C CNN + 1 10350 1350 + 1 0 0 -1 +$EndComp +$Comp +L A7105 U4 +U 1 1 53C2C184 +P 10350 3050 +F 0 "U4" H 10850 3700 60 0000 C CNN +F 1 "A7105" H 10350 3850 60 0000 C CNN +F 2 "" H 10350 2650 60 0000 C CNN +F 3 "" H 10350 2650 60 0000 C CNN + 1 10350 3050 + 1 0 0 -1 +$EndComp +$Comp +L NRF24L01 U5 +U 1 1 53C2C24E +P 10350 4750 +F 0 "U5" H 10850 5400 60 0000 C CNN +F 1 "NRF24L01" H 10350 5550 60 0000 C CNN +F 2 "" H 10350 4350 60 0000 C CNN +F 3 "" H 10350 4350 60 0000 C CNN + 1 10350 4750 + 1 0 0 -1 +$EndComp +$Comp +L CC2500 U6 +U 1 1 53C2C3F4 +P 10350 6200 +F 0 "U6" H 10850 6800 60 0000 C CNN +F 1 "CC2500" H 10350 6900 60 0000 C CNN +F 2 "" H 10350 5800 60 0000 C CNN +F 3 "" H 10350 5800 60 0000 C CNN + 1 10350 6200 + 1 0 0 -1 +$EndComp +Wire Bus Line + 8200 2750 8200 2900 +Wire Bus Line + 8200 2900 8200 3050 +Wire Bus Line + 8200 3050 8200 3200 +Wire Bus Line + 8200 3200 8200 3350 +Wire Bus Line + 8200 3350 8200 3500 +Wire Bus Line + 8200 3500 8200 3650 +Wire Bus Line + 8200 3650 8200 3800 +Wire Bus Line + 8200 3800 8200 4900 +Wire Bus Line + 8200 4900 8200 7100 +Wire Bus Line + 8650 750 8650 900 +Wire Bus Line + 8650 900 8650 1050 +Wire Bus Line + 8650 1050 8650 1500 +Wire Bus Line + 8650 1500 8650 1650 +Wire Bus Line + 8650 1650 8650 1850 +Wire Bus Line + 8650 1850 8650 2550 +Wire Bus Line + 8650 2550 8650 2850 +Wire Bus Line + 8650 2850 8650 3000 +Wire Bus Line + 8650 3000 8650 4400 +Wire Bus Line + 8650 4400 8650 4550 +Wire Bus Line + 8650 4550 8650 4700 +Wire Bus Line + 8650 4700 8650 4850 +Wire Bus Line + 8650 4850 8650 5000 +Wire Bus Line + 8650 5000 8650 5700 +Wire Bus Line + 8650 5700 8650 5850 +Wire Bus Line + 8650 5850 8650 6000 +Wire Bus Line + 8650 6000 8650 6600 +Wire Bus Line + 8650 6600 8650 7100 +Wire Wire Line + 9700 1000 8750 1000 +Wire Wire Line + 9700 1150 8750 1150 +Wire Wire Line + 9700 1600 8750 1600 +Wire Wire Line + 9700 1750 8750 1750 +Wire Wire Line + 9700 1950 8750 1950 +Entry Wire Line + 8650 900 8750 1000 +Entry Wire Line + 8650 1050 8750 1150 +Entry Wire Line + 8650 1500 8750 1600 +Entry Wire Line + 8650 1650 8750 1750 +Entry Wire Line + 8650 1850 8750 1950 +Wire Wire Line + 9700 2500 9150 2500 +Wire Wire Line + 9700 2650 8750 2650 +Wire Wire Line + 9700 2950 8750 2950 +Wire Wire Line + 9700 3100 8750 3100 +Wire Wire Line + 9700 3250 9100 3250 +Wire Wire Line + 9100 3250 9100 3700 +Wire Wire Line + 9100 3700 9700 3700 +Wire Wire Line + 9700 3400 9250 3400 +Wire Wire Line + 9250 3400 9250 3550 +Wire Wire Line + 9250 3550 9700 3550 +Entry Wire Line + 8650 2550 8750 2650 +Entry Wire Line + 8650 2850 8750 2950 +Entry Wire Line + 8650 3000 8750 3100 +$Comp +L 3V3 #PWR015 +U 1 1 53C2CB43 +P 9150 2350 +F 0 "#PWR015" H 9150 2450 40 0001 C CNN +F 1 "3V3" H 9150 2475 40 0000 C CNN +F 2 "" H 9150 2350 60 0000 C CNN +F 3 "" H 9150 2350 60 0000 C CNN + 1 9150 2350 + 1 0 0 -1 +$EndComp +Wire Wire Line + 9150 2500 9150 2350 +$Comp +L GND #PWR016 +U 1 1 53C2CBE8 +P 9500 2850 +F 0 "#PWR016" H 9500 2850 30 0001 C CNN +F 1 "GND" H 9500 2780 30 0001 C CNN +F 2 "" H 9500 2850 60 0000 C CNN +F 3 "" H 9500 2850 60 0000 C CNN + 1 9500 2850 + 1 0 0 -1 +$EndComp +Wire Wire Line + 9700 2800 9500 2800 +Wire Wire Line + 9500 2800 9500 2850 +Text Label 8900 3100 0 60 ~ 0 +MOSI +Text Label 8900 2950 0 60 ~ 0 +SCK +Text Label 8900 2650 0 60 ~ 0 +A7105_CSN +$Comp +L GND #PWR017 +U 1 1 53C2CC8E +P 9500 4250 +F 0 "#PWR017" H 9500 4250 30 0001 C CNN +F 1 "GND" H 9500 4180 30 0001 C CNN +F 2 "" H 9500 4250 60 0000 C CNN +F 3 "" H 9500 4250 60 0000 C CNN + 1 9500 4250 + 1 0 0 -1 +$EndComp +Wire Wire Line + 9700 4200 9500 4200 +Wire Wire Line + 9500 4200 9500 4250 +$Comp +L 3V3 #PWR018 +U 1 1 53C2CD36 +P 9250 4100 +F 0 "#PWR018" H 9250 4200 40 0001 C CNN +F 1 "3V3" H 9250 4225 40 0000 C CNN +F 2 "" H 9250 4100 60 0000 C CNN +F 3 "" H 9250 4100 60 0000 C CNN + 1 9250 4100 + 1 0 0 -1 +$EndComp +Wire Wire Line + 9700 4350 9250 4350 +Wire Wire Line + 9250 4350 9250 4100 +Wire Wire Line + 9700 4500 8750 4500 +Wire Wire Line + 9700 4650 8750 4650 +Wire Wire Line + 9700 4800 8750 4800 +Wire Wire Line + 9700 4950 8750 4950 +Wire Wire Line + 9700 5100 8750 5100 +Entry Wire Line + 8650 4400 8750 4500 +Entry Wire Line + 8650 4550 8750 4650 +Entry Wire Line + 8650 4700 8750 4800 +Entry Wire Line + 8650 4850 8750 4950 +Entry Wire Line + 8650 5000 8750 5100 +Text Label 8900 4500 0 60 ~ 0 +NRF_CE +Text Label 8900 4650 0 60 ~ 0 +NRF_CSN +Text Label 8900 4800 0 60 ~ 0 +SCK +Text Label 8900 4950 0 60 ~ 0 +MOSI +Text Label 8900 5100 0 60 ~ 0 +MISO +Wire Wire Line + 9700 5650 9250 5650 +Wire Wire Line + 9250 5650 9250 5350 +Wire Wire Line + 9700 6250 8900 6250 +Wire Wire Line + 8900 6250 8900 7000 +Wire Wire Line + 8900 7000 9700 7000 +Wire Wire Line + 9700 6550 9050 6550 +Wire Wire Line + 9050 6550 9050 6850 +Wire Wire Line + 9050 6850 9700 6850 +$Comp +L GND #PWR019 +U 1 1 53C2D1E0 +P 9350 6450 +F 0 "#PWR019" H 9350 6450 30 0001 C CNN +F 1 "GND" H 9350 6380 30 0001 C CNN +F 2 "" H 9350 6450 60 0000 C CNN +F 3 "" H 9350 6450 60 0000 C CNN + 1 9350 6450 + 1 0 0 -1 +$EndComp +Wire Wire Line + 9700 6400 9350 6400 +Wire Wire Line + 9350 6400 9350 6450 +Wire Wire Line + 9700 5800 8750 5800 +Wire Wire Line + 9700 5950 8750 5950 +Wire Wire Line + 9700 6100 8750 6100 +Wire Wire Line + 9700 6700 8750 6700 +Entry Wire Line + 8650 5700 8750 5800 +Entry Wire Line + 8650 5850 8750 5950 +Entry Wire Line + 8650 6000 8750 6100 +Entry Wire Line + 8650 6600 8750 6700 +Text Label 8900 5800 0 60 ~ 0 +MOSI +Text Label 8900 5950 0 60 ~ 0 +SCK +Text Label 8900 6100 0 60 ~ 0 +MISO +Text Label 9100 6700 0 60 ~ 0 +CC25_CSN +Text Label 9100 6850 0 60 ~ 0 +CC25_PAEN +Text Label 9100 7000 0 60 ~ 0 +CC25_LANEN +$Comp +L 3V3 #PWR020 +U 1 1 53C2D624 +P 4900 3750 +F 0 "#PWR020" H 4900 3850 40 0001 C CNN +F 1 "3V3" H 4900 3875 40 0000 C CNN +F 2 "" H 4900 3750 60 0000 C CNN +F 3 "" H 4900 3750 60 0000 C CNN + 1 4900 3750 + 1 0 0 -1 +$EndComp +Connection ~ 2500 1300 +$Comp +L R R6 +U 1 1 53C2D8C4 +P 2500 1650 +F 0 "R6" V 2580 1650 40 0000 C CNN +F 1 "1K" V 2507 1651 40 0000 C CNN +F 2 "~" V 2430 1650 30 0000 C CNN +F 3 "~" H 2500 1650 30 0000 C CNN + 1 2500 1650 + 1 0 0 -1 +$EndComp +$Comp +L LED D2 +U 1 1 53C2D9F8 +P 2500 2250 +F 0 "D2" H 2500 2350 50 0000 C CNN +F 1 "LED" H 2500 2150 50 0000 C CNN +F 2 "~" H 2500 2250 60 0000 C CNN +F 3 "~" H 2500 2250 60 0000 C CNN + 1 2500 2250 + 0 1 1 0 +$EndComp +Wire Wire Line + 2500 1900 2500 2050 +$Comp +L GND #PWR021 +U 1 1 53C2DAEB +P 2500 2550 +F 0 "#PWR021" H 2500 2550 30 0001 C CNN +F 1 "GND" H 2500 2480 30 0001 C CNN +F 2 "" H 2500 2550 60 0000 C CNN +F 3 "" H 2500 2550 60 0000 C CNN + 1 2500 2550 + 1 0 0 -1 +$EndComp +Wire Wire Line + 2500 2450 2500 2550 +$Comp +L CONN_3X2 P1 +U 1 1 53C2DBCC +P 6150 2900 +F 0 "P1" H 6150 3150 50 0000 C CNN +F 1 "ISP" V 6150 2950 40 0000 C CNN +F 2 "" H 6150 2900 60 0000 C CNN +F 3 "" H 6150 2900 60 0000 C CNN + 1 6150 2900 + 1 0 0 -1 +$EndComp +Wire Wire Line + 5750 2750 5350 2750 +Wire Wire Line + 5750 2850 5350 2850 +Wire Wire Line + 5750 2950 5350 2950 +Wire Wire Line + 6550 2750 6950 2750 +Wire Wire Line + 6550 2850 6950 2850 +Wire Wire Line + 6550 2950 6800 2950 +Text Label 5500 2750 0 60 ~ 0 +D12 +Text Label 5500 2850 0 60 ~ 0 +PB5 +Text Label 4450 3500 0 60 ~ 0 +PB5 +Text Label 4450 4450 0 60 ~ 0 +RESET +Text Label 5450 2950 0 60 ~ 0 +RESET +Text Label 6600 2850 0 60 ~ 0 +D11 +$Comp +L GND #PWR022 +U 1 1 53C2DF8B +P 6800 3150 +F 0 "#PWR022" H 6800 3150 30 0001 C CNN +F 1 "GND" H 6800 3080 30 0001 C CNN +F 2 "" H 6800 3150 60 0000 C CNN +F 3 "" H 6800 3150 60 0000 C CNN + 1 6800 3150 + 1 0 0 -1 +$EndComp +Wire Wire Line + 6800 2950 6800 3150 +Wire Wire Line + 6950 2750 6950 2450 +$Comp +L GND #PWR023 +U 1 1 53C41453 +P 9400 1500 +F 0 "#PWR023" H 9400 1500 30 0001 C CNN +F 1 "GND" H 9400 1430 30 0001 C CNN +F 2 "" H 9400 1500 60 0000 C CNN +F 3 "" H 9400 1500 60 0000 C CNN + 1 9400 1500 + 1 0 0 -1 +$EndComp +Wire Wire Line + 9700 1450 9400 1450 +Wire Wire Line + 9400 1300 9400 1450 +Wire Wire Line + 9400 1450 9400 1500 +Wire Wire Line + 9700 1300 9400 1300 +Connection ~ 9400 1450 +$Comp +L +5V #PWR024 +U 1 1 53C41598 +P 9200 650 +F 0 "#PWR024" H 9200 740 20 0001 C CNN +F 1 "+5V" H 9200 740 30 0000 C CNN +F 2 "" H 9200 650 60 0000 C CNN +F 3 "" H 9200 650 60 0000 C CNN + 1 9200 650 + 1 0 0 -1 +$EndComp +Wire Wire Line + 9700 850 9200 850 +Wire Wire Line + 9200 850 9200 650 +Text Label 6800 3150 1 60 ~ 0 +GND +Text Label 9400 1300 0 60 ~ 0 +GND +Text Label 9500 2800 0 60 ~ 0 +GND +Text Label 9500 4200 0 60 ~ 0 +GND +Text Label 9400 6400 0 60 ~ 0 +GND +$Comp +L 3V3 #PWR025 +U 1 1 53CC3C56 +P 9250 5350 +F 0 "#PWR025" H 9250 5450 40 0001 C CNN +F 1 "3V3" H 9250 5475 40 0000 C CNN +F 2 "" H 9250 5350 60 0000 C CNN +F 3 "" H 9250 5350 60 0000 C CNN + 1 9250 5350 + 1 0 0 -1 +$EndComp +Text Label 8900 1600 0 60 ~ 0 +MOSI +Text Label 8900 1950 0 60 ~ 0 +MISO +Text Label 8950 1150 0 60 ~ 0 +SCK +Text Label 8950 1000 0 60 ~ 0 +CYRF_CSN +Text Label 8900 1750 0 60 ~ 0 +CYRF_RST +$Comp +L 3V3 #PWR026 +U 1 1 53CC42D8 +P 6950 2450 +F 0 "#PWR026" H 6950 2550 40 0001 C CNN +F 1 "3V3" H 6950 2575 40 0000 C CNN +F 2 "" H 6950 2450 60 0000 C CNN +F 3 "" H 6950 2450 60 0000 C CNN + 1 6950 2450 + 1 0 0 -1 +$EndComp +$Comp +L CONN_5 P2 +U 1 1 53FE5423 +P 4100 6750 +F 0 "P2" V 4050 6750 50 0000 C CNN +F 1 "CONN_5" V 4150 6750 50 0000 C CNN +F 2 "" H 4100 6750 60 0000 C CNN +F 3 "" H 4100 6750 60 0000 C CNN + 1 4100 6750 + -1 0 0 -1 +$EndComp +Text Label 5200 6550 2 60 ~ 0 +PPM_IN +Wire Wire Line + 4500 6850 4850 6850 +Wire Wire Line + 4850 6850 4850 7200 +$Comp +L GND #PWR027 +U 1 1 53FE54D3 +P 4850 7200 +F 0 "#PWR027" H 4850 7200 30 0001 C CNN +F 1 "GND" H 4850 7130 30 0001 C CNN +F 2 "" H 4850 7200 60 0000 C CNN +F 3 "" H 4850 7200 60 0000 C CNN + 1 4850 7200 + -1 0 0 -1 +$EndComp +Wire Wire Line + 4500 6750 4650 6750 +Wire Wire Line + 4650 6750 4650 6100 +$Comp +L +BATT #PWR028 +U 1 1 53FE5585 +P 4650 6100 +F 0 "#PWR028" H 4650 6050 20 0001 C CNN +F 1 "+BATT" H 4650 6200 30 0000 C CNN +F 2 "" H 4650 6100 60 0000 C CNN +F 3 "" H 4650 6100 60 0000 C CNN + 1 4650 6100 + -1 0 0 -1 +$EndComp +Wire Wire Line + 4500 6550 4800 6550 +Wire Wire Line + 4800 6550 5200 6550 +Wire Wire Line + 4500 6650 5050 6650 +Wire Wire Line + 4500 6950 5050 6950 +$Comp +L JUMPER JP2 +U 1 1 53FE5887 +P 5350 6300 +F 0 "JP2" H 5350 6450 60 0000 C CNN +F 1 "JUMPER" H 5350 6220 40 0000 C CNN +F 2 "~" H 5350 6300 60 0000 C CNN +F 3 "~" H 5350 6300 60 0000 C CNN + 1 5350 6300 + 1 0 0 -1 +$EndComp +$Comp +L JUMPER JP4 +U 1 1 53FE5896 +P 5350 6650 +F 0 "JP4" H 5350 6800 60 0000 C CNN +F 1 "JUMPER" H 5350 6570 40 0000 C CNN +F 2 "~" H 5350 6650 60 0000 C CNN +F 3 "~" H 5350 6650 60 0000 C CNN + 1 5350 6650 + 1 0 0 -1 +$EndComp +Text Label 6200 6300 0 60 ~ 0 +RX +Text Label 6450 6950 0 60 ~ 0 +TX +$Comp +L HEX_DIP SW1 +U 1 1 54394777 +P 5500 1600 +F 0 "SW1" H 5500 1250 60 0000 C CNN +F 1 "HEX_DIP" H 5500 1950 60 0000 C CNN +F 2 "" H 5500 1600 60 0000 C CNN +F 3 "" H 5500 1600 60 0000 C CNN + 1 5500 1600 + 1 0 0 -1 +$EndComp +Wire Wire Line + 6000 1750 6350 1750 +Wire Wire Line + 6000 1600 6600 1600 +Wire Wire Line + 6000 1450 6350 1450 +Text Label 6100 1750 0 60 ~ 0 +D10 +Text Label 6100 1450 0 60 ~ 0 +D12 +Wire Wire Line + 5000 1450 4700 1450 +Wire Wire Line + 5000 1750 4700 1750 +Text Label 4750 1450 0 60 ~ 0 +D11 +Text Label 4800 1750 0 60 ~ 0 +A0 +Wire Wire Line + 5000 1600 4450 1600 +Wire Wire Line + 4450 1600 4450 1950 +Wire Wire Line + 6600 1600 6600 2000 +$Comp +L GND #PWR029 +U 1 1 54394CCF +P 4450 1950 +F 0 "#PWR029" H 4450 1950 30 0001 C CNN +F 1 "GND" H 4450 1880 30 0001 C CNN +F 2 "" H 4450 1950 60 0000 C CNN +F 3 "" H 4450 1950 60 0000 C CNN + 1 4450 1950 + 1 0 0 -1 +$EndComp +$Comp +L GND #PWR030 +U 1 1 54394CDE +P 6600 2000 +F 0 "#PWR030" H 6600 2000 30 0001 C CNN +F 1 "GND" H 6600 1930 30 0001 C CNN +F 2 "" H 6600 2000 60 0000 C CNN +F 3 "" H 6600 2000 60 0000 C CNN + 1 6600 2000 + 1 0 0 -1 +$EndComp +Connection ~ 5700 3500 +$Comp +L GND #PWR031 +U 1 1 548220D4 +P 6400 3650 +F 0 "#PWR031" H 6400 3650 30 0001 C CNN +F 1 "GND" H 6400 3580 30 0001 C CNN +F 2 "" H 6400 3650 60 0000 C CNN +F 3 "" H 6400 3650 60 0000 C CNN + 1 6400 3650 + 1 0 0 -1 +$EndComp +Wire Wire Line + 6400 3400 6400 3500 +Wire Wire Line + 6400 3500 6400 3650 +$Comp +L C C7 +U 1 1 54845FE2 +P 1700 5050 +F 0 "C7" H 1700 5150 40 0000 L CNN +F 1 "0.1uF" H 1706 4965 40 0000 L CNN +F 2 "~" H 1738 4900 30 0000 C CNN +F 3 "~" H 1700 5050 60 0000 C CNN + 1 1700 5050 + 1 0 0 -1 +$EndComp +$Comp +L GND #PWR032 +U 1 1 54845FF1 +P 1700 5500 +F 0 "#PWR032" H 1700 5500 30 0001 C CNN +F 1 "GND" H 1700 5430 30 0001 C CNN +F 2 "" H 1700 5500 60 0000 C CNN +F 3 "" H 1700 5500 60 0000 C CNN + 1 1700 5500 + 1 0 0 -1 +$EndComp +Wire Wire Line + 1700 4850 1700 4600 +Wire Wire Line + 1700 5250 1700 5500 +$Comp +L 3V3 #PWR033 +U 1 1 548461AD +P 1700 4600 +F 0 "#PWR033" H 1700 4700 40 0001 C CNN +F 1 "3V3" H 1700 4725 40 0000 C CNN +F 2 "" H 1700 4600 60 0000 C CNN +F 3 "" H 1700 4600 60 0000 C CNN + 1 1700 4600 + 1 0 0 -1 +$EndComp +$Comp +L R R7 +U 1 1 54DCE006 +P 5900 6300 +F 0 "R7" V 5980 6300 40 0000 C CNN +F 1 "2K2" V 5907 6301 40 0000 C CNN +F 2 "~" V 5830 6300 30 0000 C CNN +F 3 "~" H 5900 6300 30 0000 C CNN + 1 5900 6300 + 0 -1 -1 0 +$EndComp +Wire Wire Line + 2200 6400 2200 6050 +Connection ~ 2200 6050 +Wire Wire Line + 2800 6500 2800 6850 +Connection ~ 2800 6850 +$Comp +L GND #PWR034 +U 1 1 56B4E3D6 +P 1800 6600 +F 0 "#PWR034" H 1800 6600 30 0001 C CNN +F 1 "GND" H 1800 6530 30 0001 C CNN +F 2 "" H 1800 6600 60 0000 C CNN +F 3 "" H 1800 6600 60 0000 C CNN + 1 1800 6600 + 1 0 0 -1 +$EndComp +Wire Wire Line + 2200 6500 1800 6500 +Wire Wire Line + 1800 6500 1800 6600 +$Comp +L CONN_2 P3 +U 1 1 56B4E4CA +P 6550 6600 +F 0 "P3" V 6500 6600 40 0000 C CNN +F 1 "CONN_2" V 6600 6600 40 0000 C CNN +F 2 "~" H 6550 6600 60 0000 C CNN +F 3 "~" H 6550 6600 60 0000 C CNN + 1 6550 6600 + 1 0 0 -1 +$EndComp +$Comp +L JUMPER JP3 +U 1 1 56B4E4E1 +P 5350 6950 +F 0 "JP3" H 5350 7100 60 0000 C CNN +F 1 "JUMPER" H 5350 6870 40 0000 C CNN +F 2 "~" H 5350 6950 60 0000 C CNN +F 3 "~" H 5350 6950 60 0000 C CNN + 1 5350 6950 + 1 0 0 -1 +$EndComp +Wire Wire Line + 5050 6300 4800 6300 +Wire Wire Line + 4800 6300 4800 6550 +Connection ~ 4800 6550 +Wire Wire Line + 6150 6300 6600 6300 +$Comp +L R R8 +U 1 1 56B4E6D8 +P 6150 6950 +F 0 "R8" V 6230 6950 40 0000 C CNN +F 1 "470" V 6157 6951 40 0000 C CNN +F 2 "~" V 6080 6950 30 0000 C CNN +F 3 "~" H 6150 6950 30 0000 C CNN + 1 6150 6950 + 0 -1 -1 0 +$EndComp +Wire Wire Line + 5650 6950 5800 6950 +Wire Wire Line + 5800 6950 5900 6950 +Wire Wire Line + 6400 6950 6600 6950 +Wire Wire Line + 6200 6700 5800 6700 +Wire Wire Line + 5800 6700 5800 6950 +Connection ~ 5800 6950 +Wire Wire Line + 5650 6650 5650 6500 +Wire Wire Line + 5650 6500 6200 6500 +Wire Wire Line + 2800 6400 2900 6400 +Wire Wire Line + 2900 6400 2900 6450 +Wire Wire Line + 2900 6450 3000 6450 +Wire Wire Line + 3000 6450 3350 6450 +Wire Wire Line + 3350 6450 3350 6800 +Connection ~ 3000 6450 +$Comp +L SW_PUSH_4_PIN SW2 +U 1 1 56B4EC6E +P 6100 3400 +F 0 "SW2" H 6250 3510 50 0000 C CNN +F 1 "BIND" H 6100 3200 50 0000 C CNN +F 2 "~" H 6100 3400 60 0000 C CNN +F 3 "~" H 6100 3400 60 0000 C CNN + 1 6100 3400 + 1 0 0 -1 +$EndComp +$Comp +L SW_PUSH_4_PIN SW3 +U 1 1 56B4EC7B +P 5350 4450 +F 0 "SW3" H 5500 4560 50 0000 C CNN +F 1 "RESET" H 5350 4250 50 0000 C CNN +F 2 "~" H 5350 4450 60 0000 C CNN +F 3 "~" H 5350 4450 60 0000 C CNN + 1 5350 4450 + 1 0 0 -1 +$EndComp +Connection ~ 6400 3500 +Wire Wire Line + 5800 3500 5800 3400 +Wire Wire Line + 5650 4450 5650 4550 +Wire Wire Line + 5050 4450 5050 4550 +$Comp +L JUMPER JP1 +U 1 1 56B4EFD5 +P 5800 5300 +F 0 "JP1" H 5800 5450 60 0000 C CNN +F 1 "JUMPER" H 5800 5220 40 0000 C CNN +F 2 "~" H 5800 5300 60 0000 C CNN +F 3 "~" H 5800 5300 60 0000 C CNN + 1 5800 5300 + 1 0 0 -1 +$EndComp +Wire Wire Line + 5350 4900 5350 5300 +Wire Wire Line + 5350 5300 5500 5300 +Connection ~ 5350 4900 +Wire Bus Line + 8650 7100 8200 7100 +Text Label 4650 6200 0 60 ~ 0 +BATT +Text Label 900 1050 0 60 ~ 0 +BATT +Wire Wire Line + 6100 5300 6200 5300 +$EndSCHEMATC diff --git a/PCB v2.3d/Readme.txt b/PCB v2.3d/Readme.txt new file mode 100644 index 0000000..ee5a7e0 --- /dev/null +++ b/PCB v2.3d/Readme.txt @@ -0,0 +1,35 @@ +These are KiCad files and you are free to do what you will with them. KiCad is a good, free, and fairly +easy to learn. Build your own BOM and gerber files. + +This is a variant of the Multipro V2.3c circuit design. It is basicly the same as the 2.3c board as far +as component placement goes. What's changed is the added resistors for the serial protocol and also +the addition of solder jumpers on the bottom of the board for the various options to connect the TX, RX, and PPM +lines through them. See below for more detail. + +The schematic has been updated to reflect the added components and jumper pads as well as cleaned +up a little. As it sits now, the .net file loads without any complaints and DRC checks pass. + +The jumpers, and how they are used: + + +There are four solder type jumpers on the bottom side of the board near the lower left corner when the +bottom of the board is facing towards you. The silkscreen shows which jumper is which. These four jumpers +enable the board to be configured in several ways as explaned below. + + (J-1) Use (PPM V/V) if the incoming PPM signal is at a higher voltage level, leave open if ~~5V. + + (J-2) Use (Jumper 2) to connect the incomming PPM signal to the RX pin on the processor + + (J-3) Short (TELEM) only if you have done a telemetry mod to your radio, leave open if not needed. When + connected, pin 2 of the two pin header (P3) is also connected. + + (J-4) Use (MOD) only to connect the transmitter pin 2 to pin 1 of the two pin header (P3). + +The direction this project is going, it is most likely J-2 will be the only one needing to be shorted for +the serial method of sending model protocols. + + +These files are submitted without any guarentee of accureacy or suitability for any intended use. I am strictly +an amature with time on his hands. Although I have done all I know to make it correct, things outside of my +knowledge base are beyond my control. Do not use untested equipment around persons not familiar with the hazards +of remote controlled vehicals. \ No newline at end of file From bf506d382fa74379ab081d71115e997d7f091b11 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 10 Feb 2016 10:53:13 +0100 Subject: [PATCH 053/293] PCB v2.3d --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index c778e1c..f1221ab 100644 --- a/README.md +++ b/README.md @@ -505,7 +505,7 @@ Using a [home made PCB](http://www.rcgroups.com/forums/showpost.php?p=32645328&p ![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8226720-197-thumb-IMG_20150715_230603155.jpg?d=1441816457) ![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8226719-72-thumb-IMG_20150715_230024065.jpg?d=1441816456) -or build your own board using [SMD components](http://www.rcgroups.com/forums/showpost.php?p=31064232&postcount=1020) and an [associated PCB](https://oshpark.com/shared_projects/MaGYDg0y): +or build your own board using [SMD components](http://www.rcgroups.com/forums/showpost.php?p=31064232&postcount=1020) and an [associated PCB v2.3c](https://oshpark.com/shared_projects/MaGYDg0y): ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7566755-3-thumb-i.png?d=1423810885) ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7952726-108-thumb-image-62c29cf2.jpg?d=1433909893) @@ -513,6 +513,7 @@ or build your own board using [SMD components](http://www.rcgroups.com/forums/sh **If you build this PCB v2.3c and want to enable serial mode for er9x/ersky9x, you have to do [this mod](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8667856-242-multi.jpg).** +**New PCB v2.3d! available in the [github repository](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/tree/master/PCB%20v2.3d)** ###Schematic ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8443844-119-multiprotocol_diagram_rotary_serial_2.jpg) From 24106ac3d2a4a4834d0d4bbf83dec6f066e61a50 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 10 Feb 2016 11:26:39 +0100 Subject: [PATCH 054/293] PCB v2.3d pictures --- PCB v2.3d/PCB_v2.3d.jpg | Bin 0 -> 176431 bytes PCB v2.3d/PCB_v2.3d_mini.jpg | Bin 0 -> 21935 bytes PCB v2.3d/Schematic_v2.3d.jpg | Bin 0 -> 229690 bytes PCB v2.3d/Schematic_v2.3d_mini.jpg | Bin 0 -> 34304 bytes 4 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 PCB v2.3d/PCB_v2.3d.jpg create mode 100644 PCB v2.3d/PCB_v2.3d_mini.jpg create mode 100644 PCB v2.3d/Schematic_v2.3d.jpg create mode 100644 PCB v2.3d/Schematic_v2.3d_mini.jpg diff --git a/PCB v2.3d/PCB_v2.3d.jpg b/PCB v2.3d/PCB_v2.3d.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e1133b43d64c4e53e986c7320132738232debc1a GIT binary patch literal 176431 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�XBaXZTx=>F9^8!`j1G`;z5?D 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 zob�&T*%-%n(u3s;LDFU3Ua zW}wweh0q^0S!RIWu6qk7V7)L9gyU+?2(n`%CxtfhmQY)tljRQd;V*A1P!!6hpZ>7K zn8{!kG|YIp9bT9(oog6ir7=T7z?Iukm7GIW8B|TAP#!jPx$IaXPG3&vtc-fShT(hU zpo|W@FseE1A5HwgCjmxkDM=IXw3D@?-PE`X5DLqS(>Bak^&id~1`{;JX|X>Yd|qV5 zM_!Ja#yksWr9Se(;yOE0awtt6tbw$bIX#&@Xv%rZ7cm>;ysu?Z8-8+1hUPb(r-8`-c&QP_!jYuk*Fphl`DENq?o5b{<*8`_)3gm$P`ux&C)Qp zv4WDK4$#@L@6AvOz;@G`L48zGyuUPft2(GeO0Z6=l7&Cw1>-3b2L_8ICyBmTB9@dv zEd}i`fDZ@;!raX7Cw8cMbJER*h2w99-S}Ad zXR71;HXw=#_A@wQ`kes*Eb$am;;XeK?$OC*C=y$;sJ z{gX_qU};MX$79PUEcsraHL?`5o!6LwRLhNn2KvP&;x;vPL8R#_uz-|`9whP~>@Q=y zK^5gE+nfFxkR#x6+$gNhm6gc6ge+iLJ8C(a%~1S+Pgm-@cfD>rKh&m*&p7&~mT(r= zce5=(;XoePpw?%GgBcJl>vmt$Q6o2Dul$9}8vbRloVbM@+d&=7>>GsCKq?GAR&Hnf z5|B(e@;F`%YD-1WLiYN(4)@jHA09NPpRORiW~TT+MgC!xvAmaf^cHZsR_pvKE?Ss~ zNcIpeps#(l@0rjlJrvq2IZt{Ve0p-GqsiI&JEh!JasA!8=ol?AWC%hkM>}mFiP8bf z&95ZDS<+od*1}wH&A8xRC2sHubhSioCmq@t%#;it5(*ereNv-kY9h20_6z3;>qGI; zz~hZDf-R_3gU1>MzJdtuUDq!KoLP68R8+&@4vE4uYCU-gPwZp`gd826WFE{RRmx5h z=r@ozscFP0m@#!qF$}|}dF>~n0CBb)W*%?T4$o_cBaR{&AXl7fqdBW)B;^{CtGiwx z*85uQ3slJ7tGl`i@W=Py;th&^*WxRxOP)tcL5~d``0zPAeML zGaEY?Bu9A>6gLRo#auw?jdAJZ^trr%?33?q8LMdBUVtHqI0n?R7yC z2NNZ??UVw|u_vkdT^ynmo_wzu2JcYN-Hij8as$^<{YR91cV|b^L3>hCQe4s92X4cS z6;Im4zW=EI@19m~EEkb_YXQt*t5Zr7p$27k{;;)?Pab_yTXX!x{4kuW{_y=wU57{Q z+Yt>Os&lIyBNa%=xVRE3rKX9G37Qzz%C>SjI=d;5Mf9JzH=us(pDq0CX2uDq&oq+z zk)zJM$6m;0%&{nvgK9}G)gnp%LWidW=lq~OBJIy%^I-L^&ydoDFi9VMZG-f2!X2lt zHV@08Nz)EzHg>dyWDdK!N*BioD?HKJE^}X{a&B?-a2CI7n4ewm;l2e^Nb&taO5@NP zMubnm<&UQhOXzR?G&J2qGb%j)W$29}xVJb1H)H|8Y5{^}VDZ064z!zH0C8;s89BsF z>CWvW(9Yp1M4skP^#cW$-W-$M`=X{$K0os(sb0>jaXrtK^Nw4MpfdNO%%f!oAD}hI zpFJVUA%0Nf5>k0|9};S8;{upk^9ih+YknyrK^*JlxYgn5A}%h)ipb4a`(V>4CW-K+ zujTPP+KRp}Q}5ty^&W_F73%iDW;Y!hpeKJQRA-^g_oaLe>*lWP5m3{Fxwz@)>+Y<2 zB*pe>xK9pJh#He`o%JQf`cZ8%$FH;b;=YgHJm{<~Qo@L$`n(<&VNQ{~gx){kGU!tK z$U3deVGo2j=^q2VJ=m(b2$DIWCK4kG6VMp#cKi+&wF3$!++AUz9p&R)F8+R~2pelp#dCsE!cdDQZF7fL;Im^i$efyj1{7#Z87X)j#e97mX>p!_k6)42b>M@Hs znUF^9#VSp5lyB!;&)quAu+$1jnkX1dR|76>`Ps#Bvc4>*I|mH~!bNt5$5qg5(D{pd zZ~^O7^m{;LF6|WKHfcP*?VbFB<({Vj!%Cj($_*guU+!v}JH?+`lLIYl+p)17fFfQ5 z-S6Sndsa}k*>Can)I?+~MFB9}oi!pk1^EzvXb2)uaOqYI+eo8elK6K$pAy&NQrJlA zX_u=H&b3(Q>{sqgS4MEmd}|JPsnlZg9($EOi!I9l*du#Z+@*=X(O)k|+&3$+JgX_G z({nSknqId`lH^`wCWkR4BKhvz4A#yQU{^|0AvF`<^mB;z5@ue)h5BIm4XUCe0R!wx z1PQIzPeqdm>ndh8Ltb$Wm?pa@jei-0QXwEzKcHV}ba!@lUNGRAfvSv7pQ}tVb~@j6 zHjvUkjb&?IJYO6WnXZ14vekITw-dh|QS*>o&+a2~ZTpPqiR|D{8Vnf7*dLJ~2!03S zqLPAN`)4nF=qi0qGHFyIBCn(B;V2V9&Z8pU*F^(gd#@htx4Zx#zAs~AD z6!iyd)l7nj|J}!3D(IXO7c!&`GSyUNae!cLzcg=O)qgni^&}nmjIa_2ekG()b-{hg zRT|`qVUVL^S|xNl|ir zoCB>B>0%>K&BuMOTi?4?^rm%LOF%=P7Wa*qXExJEFf<30V%@jHfZ^EZ&6QMn% z;f%2{D@uH%NmEgAZ+@LT8RBr{evtlQK_5*)kjp#2Pf>Z>B76#6#}(dG%yg9%g1?4a zM0|hyv;WkQxz4c>O?3nX#9)yDk#y0}YPIJhlD0%D?xyg)?<hK~neopE3Lv6{bxc z%jE;dR2Uw6%p+HNa(#avy$NgqqUMCsV{bqws3g9GNO#TU*UwH#sMPTWe^a~A+;isZ zXlqN+(nTX6&85fGD0^%^RV_IDc4;8ED2VaDM29i$*#8k7mV9Pm_A*EBxPrLA8z|B| zJ(e2Y)SCf)3-C*N+IW-_x*kyd0g`8-0h&zt6SDl+;=A$gg=y>ip*=A-KRAosH@m^| zt!%nqNi@P^w}yYckOXg!s_N)^8Al*k>wO&Vx^&3+8=Y`pNvOoKe({BrjK7ZTvf?;q zIHQ9O$)}3EbPmqmE}l0#()O#F%^XMYK|oBd^DmfI4k=pGAa~ur1WPeWOG@mCk z_+v)J;+!;@HOO5}pCvO7A=}pH8@uK^tQ|+vl7;t!?72eU7uCHfuHOvYz^>yY$3qNrM-85t!p%<{&8uIeam0O7r?%34-nKB#FDN=c@7b4o(fc?!k!} zoJcsSe&sQ6Abs+CK%UM0mc)5)%`8seUH*&bMtS$JgX~M~ZVi+EQ?Ix}s9NN?frXHb z%5oRfjh+1p!pZPdkK^Si^}H#QG8ft=LBZQps=?sJuL*xR*|}BYZzUoxwR^qOs3b5T zZzeXc=h_pbvQni(in5<>*2+Io<#*3NeZgGtX@97Bp-wR8`djW1&C);Lp-wRee0R4Dv2@n#GXEDoe7OF+2#sQ$ z{K;7^ZxC35^QUb!CONGwZ+`tvDXGMJoRfyx(GPnCorrBM}cF*SLSY*Td0hD^P@%gdlpSSRdPZL_hTO~q6 zTXKoyYuY{a{*g|W{GG`=jGc*>kVBC*bLY|TcPG~}%4hpyz9S!3klY%9LGk-Ul3re8 z;=H4llDO1v(hYB%uYjlc$00TO9Gd(|9#T=Nig0XePZu@wtKrGXjd-K^PY29r_LGavB~FDmeC&Aw0blB{ z9++?T&m70_Yj4m7({Uj$a7M6V-fv`?7Tw~vn3@bu06)5B39^EB95toc*zjmRt7HWRnyHo52@aUt|mfGwY| zglF=tR2DLJJ{#P1)L5w8yZU0ab=}n09CNeAudr$Q9i~*%pbdhX6Ld(m!d7xp7M8No zxp3;Syoo?pNb-%#k<8D{>4O&dFl4HQ?9wA%r2#Y12ENM~-xwGeYH_}yEA)pG^VGAA zz`CIeF0WL_?p(tF2hT$YUD?Wb@ncmr?sqmuTR_Gle8)_dsj?bR7b4@A9^We`(OUss&Z=V^y`-BiJe=cn*^wfRfI0g>)W9f&Tv><6L z=^~oCgsMX~m)xbve?*5zKt1F;+h(h?t2WGr*s^xpzg-?7ZeBmu831;20Y0~q&{6$q zNL{-AYl+p4t@%5mhYG0sh>+F;`jv_8$~3EvUA-~y=`cxYi7mW~o1{ooxX!iMpO>SH zE{NT~@$o_-h8IlMU&romWE`o8odExYz#l+*1j9fJ_DBq}3L$S&+z-zHyaEWlLk50= z$iR*z0fgiL@{+sDt0-U;;j6nM|uR2~CLp$++?$q=d|U|6Uarvt0mZ`Bd>Ec%4G zFc;DYOQvcA$qC!~|1tn-o;`(E2z@3;1iLXktN%@J!Eu5F_J$=zP-8UYbcR%IRX32 zPaTte=11o;vC4nGE!De$nw8lp7$y|obGb;SNUi09P;E{E9&c46sUPRQ#iG=|zLacV z99*N867KGZs$O@S_usGCuqUK}+cjh-irnQ@(^!rPd4ZL6-b3!vQ>8aK6-J;3tn7S2 zNxk7Z-*GmF(58nD)h{sz_VSd-l46GuompFTOPXJ3n>L%`oo(OkvDw+05_$-XZ1x0o znI=hPTd*}=J6dT2>OUentUhyb8O`*;;JLT~FRu$?^ZUcR9`vG6g=7Z(F*15%h@L=B zH5f5JL5E6~dNVnJJ)E(XDgB&YqmPBtn66yBbp3rN!ylv_bsNAW-j5e=tYF5a8nwLm z$BPM)y3!SER_VP7)jL@Ugy1oQ&yU0)(r4Xk&qd#E#H#JD+F`Wg2bcmA#L64C)QU)=V;xr1?8B7%lGCpyKvWxS1+U zr$5U>P~Y#`r)fYLWp9nx5`F2%b9l-LDzvV_h5CiQhSETdL#`kLh~Q{DHR>m9c~Cnx zs1aUFO|-6)zvvTF<;vNrHl7{?@Y%^ zy+OQ)K%fqe0J9EIZ8KW^Ek7PXv>@6RiWIY^3$ys?FZW&T-l~!L9L3k=yjO|?(=RoU zd5NXLC6)g&a3NohRjEqq4sC41)dW+*;>~NOB;YU~zaRB#Y?XdoY-cV#y<}^9QOGeM z&c9H)eX!M}$3@H2WaS`jTfldExKDRt#B}9V9RZj6&YGk)LBUZ2bEzZG$>U|YJrv+h zPM5B%9$Ah`7y^Wha+Hq*{qFXsp7MK=>~~Z@E5pB>YSN_0Qp0koUc`(*H}~9QHI}uL;O4#)v0WIPpvmVhbO2FA1t+`=u2WMZZC%KtfSBJ}yp8u9_wK4p~mEQtVz- zm4|Wh+Fw=uIkU9rX^|Lb$ropl@+X)4hXjg3n&zxoIby1^)^@MEOWHX{cKntyBg{6p z`CU+J*WtD~m#F37*?}nl`9n6jB|{k`tt5cYZO5vQ{18CfX&T;srH@f*7wOTydMVOI*opKLF8 za97{bWR3h}^71yuW%pgbq*8-YyOyoU{#$Y3ZJ#tA?;LTht@P-5zrsIn{aUxVaRBvJ z=^Ild=ciyu4e5Bbh7vd- zlGP6E+ZBz2)HRjG$bt|n+}q)Ybm89~B$G0W3;AY2PX-cx->xlrx3)Pext)JN({I04 zHk!Zm1&Cw&bk$8#muyxsJ`0&~qOp-;Hd#p_9q3CXY9R7+qFEqtby#b)A4W2O(F!}1 zH@H#RXKyxGyiww038<=_tA~Ym&SoOZL}U4!od>qC)#%WTJ?ZPzXR39d^cBJg&JQZ9 z&D8H!q@Vhue6VS)0l?xP!x4mO{8uZvM4kZ3ha5dhguWn=;27!4xl{JSmTkH_3hRHf ziy?0Fga}cjy`vudKqAO2sRgbn?twIUXM8CuHTvoc@_2GVkKe83WZ`??JJ~}d983&3 zEaF99n%-zw2szgD@Eb~C+2lFMA zK@t{ZtBoc=E*kK*`qF&BL!%Z6t081fW6bVP2&JZuY z9)<91vSE4P*!65cE;XU?|&)(4=Ty$5dXY?DxP zxz_P{Gr#IyDd?nhkChJrF$a>q2~iK{&4xDR#IIK}6^gRHl>Av4c=BBA$E)+ddRzTZ zUA(2sUI-`@E`jK5y!=3#c3nf=bjHtxsDHdW)xE~cv99jn0^DScz=e4xs@a5Hj1H+P z%pGj*f*BE?5jMUn&eann6qxR3f5y#vPo*}`EG|!>X%1#>wtXw>U1g0qIPOiY)t9%i zL6^*e2usJc?b-*PW7dUG?LM#&I|Z1Z;)4D+9^>~PJjVKe<1wJALb@&&FsN*}3}g4~ zC&uP$oM~x(;n>ZQzX|fC(FExOQ#$yhlKzq8PS?GNo`^Z=8n_8`s1R7!9{lx+0uRam zN%Y0_zpbJ%|1Vb2D4_QCzr3Q`XKm*6+;0Rc!C!NZ`y|0OkM%BC$6a6QT3C2f*MFX1 zz%5kzWkvu~HHolWn_V^q3R)j-Z^#xosES$L2%>A&I>y*>T~caRzTvTRcb7MMpHhiZ z%(EvUkx66u;`8P!!zyTVm5lTKtN1j%o|@=2r@9)8p(MXvGn*?ait3>^R{nuusW&NE zq)y_>w9~OxC+(&}>UX~(d_KK$p6>z`GMr%h5h6c6pV*!_FejYGycV-neDFw z@coPGA4=92 zLrqfOQJNwEr7l_kU-9}l_~fiv2+0infBnt-;{*~SgU~aUf%6xr3t;+Bz}FiHw{(d- z@1~+=b$s`+7wcUCw(?&hPgb~p3kih8j|@n0_)LATtUBq7`WWXJA9)%D1#vfvo;f3W z%Eax4Glm*C(4NLfpF;oXDB)`5bHS~gyfHWdaRgMGbMVPsdndZZB<>|76mVodi;QBiAit95`b_R9zIu6sVc9a7Zmzr*>-$0oI$k*9DY8_>{CZnbJ z^%ZS&!jS`cyBea?a9vFg|Nr-aYsm8i)}eY^_@XT{tuo0zN2hAWG%O{#mcX( zH!3VE+#0*bnyVTjq>iwhNve5=fM_EL979O5A#ENu*1^_!CpR6_=bz0{{cqN5-?@Cb z<+=FQVKToHmXxGD+IW$qX-t-G14LbAjUarsUh1FB`q~iVaruk*8rIjt`IbU8)hQ3$ zZeD#ctEJjK^l4`#(Z)1Uji=oTwOjcrqj4J9SY6ZJm(#E|TcxfvLbxQmlqbgQHvK6* zb;{0c-&c(T`vMX^(1MgJOMh_iEyCubW!C;I&rFhyxAGarz&>YmD-Tk$lNLV>qVeVd zH=p?`xIM}bj{(N_vp5o0C){ejEm4D=8dYrlhkX5Y30$<=Uuypc%PRiD`-k45vGf5S zwcezza_e7(>~qMpV?Ej(YS4G;w$AWG=bUix`1m_(^d`dLGq-oL!`Hrmw^urHVS)t} zGj7wuew;ynaM93$g!ZtclO%pGl}Cs=0h=`Td% zVfm7}bKPx>%3k~<@a+kH*38nkBv7>ZFEC>zHe#Mb9>OUVq+C5hlg3A=h9!jGJd~1p z^GYu@ERHi_F`lg}S?L8?3sivArS6l=DP?-x!S+pJWr z6ZS7IW^VtgFr_b3BiUhAje|p$EvaK=aG7Sq}kdiYDBlk z+NR!z8kq3dEku@1gaGe_=lCd1%6V#P0F$jH!a|#eIPhuB?9(ruUqT0Uw{?Dr{`2Jd zm}Mp~GkiqQUW^i;uSn7BKJa2yS6`2okfCho!|1I1Ep^x!@(Iu@h-GJ*N5lX(N?zv7 z>}tAT+2C^G-0Wg?RU}SL?3%=x=MpzV<(`&5wH4SBSvxVVi=-?=cs}X}Lzo`=;nR;piJqXR@Y#dO2BK077QnpO_1>5RXU=1B&u5l1$sEgNrzT2>dW z=TH4+%Fv2+6fd$TZH2AbZ8=bwH8jDAV zmI10BL|{AD1a53BHyJ<8>wl+u9wSVLTl*lB6=-!IGvRYr26tcZ%tJ{K?mRmozwVUI9nWDfF z|3F6fg5!&#l90fUthy(sPvW*wd{k%R$w2c7kfwr-(GUh0xd@;F4yF=_h^BEQZ)Pc& zspPa*NM={ex`nqm+?&3z_>Zzo-nnB}sxc8C5`hte&9nHpUzLw(oo9#Hv5-T8Z;ftA zji$otB$sL{60)YR4HjNB_6`%WAkEoWJAOEH@o?fnCOALLhMFLM#+MtrR}pTUu&A!oNgXBsSu= zM4Vhs+Em!BFhGweUzLe&R-wySyBxL2AmqQNz#J}KuFv`GS-1QBPt@I4toQFPl4KC2 zu#*&kL3udd=vN4Z69=y9!@ShTu$0Df-KSPhjqkt2l(RS($*($DNGZajRo~@m%AQ&} zUfJk7HlST6ceciaRp8d&qGEGt;9;lQ8US;SXsb@NipDDKZVg(s2HdL~6+&#}eG-PR zUel*+tm$9w9bPY$oLXB7~+Hmzsw6gNB7#8Ha4zEYW*=5IVESIk{J zhE1^@NI?NBI6%)9AziC$`Y!Q( z4#LI`QSiscPZA;{1j}y7<|Xay@2b^xSgbyDQ|r?OLsh5RJLb6*64#EVW=;-7$?Pi8 z&whR`Fv>IjdevqqUSBv4y6ZX*b3rUZD$LuL6HGCn^RM5NGzrWa)(QJ3T}dc>zsZM4 zKH~X$Ff*zX!ro|PFFc5NhM*-|aSJBW`-Gz=3Sw7$7X7x@AqF%BY7;4gXh35x>;$nf z0w-vAqLuUqpC;7@^%LKl>aATQ)2$s6cb4&RHjX&!h70E^dD8m!=3Nr;3s2Z;s5P4x z3uyPLssO`xAw8ZD!?k9f=<$z4P(PDT*<1N3{ZsJ5%9U!)8 zy+||TR}({%oSgwJl`AIom<#!2T=694L3RBO8T)%&0^;TsNpMpEbvJBk5?E25{dku!+9g*%&#W!iRtof?6hRtFtMd5!c4tv;tU-o=5m{UDe?;P*3mk|Tv(%@XT z;%bo;SOjM$I_=NL`&#iYEc*D75k++^YmMY!pP+Z&(xPZqIhz9Yt7tk)4~Iswn*Bpp#MeX5ugJxBZ913I^8XEM++;|BZ)>|v#= zo2WS+D**vs2SE^<(Y=8Br(P0QXRYU~XN9F^6%U`aKYqfk#O=u4!w_&x(LO1s@gJMd z%tEW_AUG?K($ul_?vA}qrpu>PCat?h4ZPoH_^&KKz5OC55F`C;lN3Q*!YuDd>__q3 z7NTD;Y|X2?pmJMkYm$F9#u)m7{N?pC1&p>6!AA9g&xOwYD~|N16+hySHZE`)9b#>FV{Y;L~fn-Snp) zOi_l99S|el5nDLF4gP!^giZ;O>Q9#18r2p`GlLy7F;$t))^$X$?aGRG zznne-ZTKu0uu|Pk>Hsma`$?uf$-TuaWzTmN5arFeUeU>yUx=(VP`Ulcw-vQXe*DEM$j`@Eg( zRXBB*;y(=c0Y~6oPb8A&rv8v;*1aqTt|Ll`W=3@DNj~0JoKIe0m1RtawiY@-3=$?#VzD{^;sW$ z8CZAm#sMcr z_~(qJk$!J=A(LeX|DbbEa`v3>%{x^m_MO;k?%-E{8-JT?P~5eQLh#l11r7Ixd4`$Ox74MqtjPS{SlP*$&fvbJqknJFq09y;`F>*GBi z{bU+(>;8*pI+q-WXo>|$7+IqfQ30j=gKNVjX8HKMxmokGMpjTRM7V)r_Xb;sz+;Ki zS@+uCu52cg$_IY25^P!eK3gLg+uq|$Z^0n^cFQ#!9*)uk7aV4P9iy~CK}$sR(-wDtl(F?F+2!Yb!}}Ds10aq zIk>OGndy@crE|>{74($Pz4RRJFirThe#30WM7m4Q-@Q%x{d0s9vlUS<)g%F_$ma>; zv|3J2(a6t}h`FkLvl^NWC z*Pa`NKjwFpX4P|ztJk`j?g969vfR+0tt`8%ikjJJA?crMEFp44g_nN9g^=d)|n-Qp|s&PtZ=MA-SIWP)|e32=7?X%6- z?~B8_=0md>Gh%nVUu7(d++6G*WNSgeEET3xi%#)PvEUvs4i&_)mMGq3EV-+~z&L0n z+SGcxc$_x}@;UxaFKn_v3q(^g9LK3F39nY|8W=&6L6#RE6W=Q-6vZ zw8xhYPi)G@qONPF=(4658GDpBEE(ukk1s=FG?-n}*-3rv2jLpri0RfNwM%xe9(~=` zwuXlvS9)tg@7qU;Rd6SFm;AbL_(4D~7kL^OKhIc(JRcRRj8lKWJeN%Ir~R=yBlNvX zkpUm}m{-^|_TH{o&6!n$P&COp;GHeinxx&D)oG_d9(~IfJT zhw?tIPD#A1s; zo?QI3Yv+)(v=ESXE%$URp=X_{_Ecu7UD~zetAEkPa9m|7w8UZCH)Uf_BR-g##~Rjl z;-`^RNf9IIi_e|#=u&1yGj|8tw!_L0k7tYFmJXv1HmpZ4SiQFYfZ01v?WF2~H@V`C zMup?M<~+TQdy>|xywd&8mUS6=dg>O6hHMUmtC_?2N8`Y_Jk!_%*ZO_|uA|^6 z8~;VZCD6eokco%FfD+#Q{nxfMG4tZ*-B#@>O;ph#U5rrl%n!2uCF)M@=*=N3++kBm zU(7{>b{m=p3AfKgI6oL`)GD?OvE~v;jnj>D{)_g#`(_L7&6)kayDR9`z?np86%n+%_!6&qD#SlQD<f{tw*y>;FJ=PrRD3hqr-&!47;N^dGrhC^-MzU%B1G?qN7hhz? zI`6t|Ot8ssVW+jVTd}W8n5!x;MK(OW%%p65x{Sf+T=bkrvzpD9tAN^WJh&pMCug9U zeDpH^Ev6^?tt3{X=~+@sjo~zq{0A-WYbkEWTv0Z(eqB4j-TC7z=%M(K#)W`F+#Z-tO+1 z4X#M?22|*eUh9lKuKs+QW$u{&*+{g1=bW)(0LEGMYUx#Bl{=7 zuu{Zl(o|?}47Y5zRA=|Aj+V53bQli@MZYQhyn_T+%_kng-fb5jQ`GGV84+;Q6`DF# zdx5thzqD!~nAA>$TnQ-Hdy0ELHQo5rLPs!=M`E|PdWgTRBX{Opd~b~R{FN$qDs+2t zw{4D}w2>4;uqe@vgnOs*rU3=Tb2hwn|1f{E(RP<_?`x27sKH4XCTKf`W0ZkU5bVwg zop@`O0rPVFJ`X9$_m^M+I}I4rNX zW*F+5^xSS*A=$g$E$^j=1oT?m^qhnnc{^G@YACSdcg8T=CbRntpEMG9Bak ziuZth=%yK8@IM8cXIB_fjteOtsAKqfR+s{cgFYH#TwU`M%(Atg_KdovBR$5swQQ+j znp}K!d}`%VtK{3v^sCw6kBA8RC8k1{ip0* zn{dH*x^?-ygzx2!d3D4wK_HXNveRCYSzcK+T#RYYo0^&~x;r_27^f>}gB%D>`0dZV z_^Pd;On5@;X&!qr;m$;_iT%d5Bj;SXj>5E2z_3|W+7?bTN?XrDd>&|#3DF*h@V@o| z;o>PbNl`Vyl_#zS*MM-<2IXtFpF|)IUL0eu|Al!etmInal#p~Hx>;T0 z8cg5@_24_T;7OIOcngXv?%k$=O|(Hd4p($H>E3TyWU95NL~LMfyHI>k4~rMRbW_m_ zKkL+KI0~{E+3!;rXI2@p859lfciDVpF|Jgy+51@a50UNhL)FK_=k5p>VIT?PNXwHl z5J4ogn&%))&4ak^X8Ag=x{5R#ywJTS^{NV*vLo{+M8H8(ptY&H^KD;li^FF-yb^QBZ53d`8(@ZEJ{ve^9o zgb*ee#i=xA#9{x)kmG*KL?!LsNo`dOi!0ZJpGs$FBe;0|>TgL(epWk7{qxQ}Ga$Ig zxZ|gK>uU>~#nSuDOKr0L=}-aw^h;F|PIgIhLfs>7eOC9Zrkbt^mLwSj)!9lzeR|Zf zrR)2u(o|8=)_~`DaLm4Rn1ED_H7O&|Tb*s|ah7K(4EE!&o%1%Oe5*F^RV6_x8L<1F8s z?a)d&NZ@E6=@2`i7_;HrkE)Zz6o9Y~UlxtFNatqDO0eX&Qs#f+D8&4z))%oh=7HF& zTM;mc_thOXuof-&nt)p;^coc@0YapQ8b#?%KtQQ4O*)YpI?|hf^xk_iUyXM|4~x=g zgKQQni8JxwOVAIgE;4WN1OW?1VoGmU4#<*gSv>GA(>gv!Tr#lQo4-a`E#JAHVWuWz!TU#!BG`+uF|>+&^QVNF~Hqmw&9~DQx`R zgew)}-~IDzH34gs&M|S3Kj3h0qKvJ&d`-|>TW)N=Pf}SA5)r~q*R(l1^{g}ziW=eH z+YMyGs}QV4WUMU^6oVzISrD%u{2h%PPTeQYx_s$8I+k_sjD_hJDNB++Fy2@BRIL1a z+J+JfEP}yePJjr=I}XEUVC~FB{!?YbnUxf|B)lZ*3`pUYM(n?;nxpkqrLRt=8T5@ZL?1 z=SW9jk<-PD&gnOO4sgP4Pgc!d1s@K)oPa7n5vzBhLaq-M&ilHTz8jV#O<42_SNciA zHo&~$4tN2r^jPwRk~d$uPDMhbM|Vq8YpR>4z{RUD>JzJ$;t(PCGMa?Q#u;nr@`;T7 z;itGIv_k80GJ>jSDDutr)Y0xG-!z! zgw?ku<Og7=<}2XG<~nI2exuxiihcC=`^s~ROIXmy`A%b z_*GPY>7{NmCzT|8r>GQqo>2|APtR3Mz-@sX_b-bC`5HX67fev~Xn3R-L^^+L!N&xp zk-8uqSdj;i67^hnmDS1u`0FY#LTxKR8P8;ccSVsVA{U5W=FZ=>;j0;`9*CM_gA{}+ zh?T*(TVt6TqgQ*3KmT-Q^i>qc2^bv{yRvHd!}bqTfN16AxUif$DX0C(l*_^H5~$

UyscX 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�!_Zfh8CR73-Pw01b|NViqC1d5r?+*EElhKeD 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 N@AcgN>bCv=n*b^QZh!y) literal 0 HcmV?d00001 diff --git a/PCB v2.3d/PCB_v2.3d_mini.jpg b/PCB v2.3d/PCB_v2.3d_mini.jpg new file mode 100644 index 0000000000000000000000000000000000000000..25a7523c2215a22f017d430bfc933e370a6c44a5 GIT binary patch literal 21935 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

I8gB6*mzY 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 S|3CZhfrtN1$BFCL$o~M9vEeiT literal 0 HcmV?d00001 diff --git a/PCB v2.3d/Schematic_v2.3d_mini.jpg b/PCB v2.3d/Schematic_v2.3d_mini.jpg new file mode 100644 index 0000000000000000000000000000000000000000..8d355bc1e1c8b9fdcf690e67b6f9307fdfb4a06b GIT binary patch literal 34304 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 O|0YTOZ-4$f`~Lt(gJ|*q literal 0 HcmV?d00001 From abc8bf0e627295544d0abb4d2c968de4138fc041 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 10 Feb 2016 11:39:41 +0100 Subject: [PATCH 055/293] PCB v2.3d details --- README.md | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/README.md b/README.md index f1221ab..a82d079 100644 --- a/README.md +++ b/README.md @@ -515,6 +515,13 @@ or build your own board using [SMD components](http://www.rcgroups.com/forums/sh **New PCB v2.3d! available in the [github repository](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/tree/master/PCB%20v2.3d)** +This is a variant of the Multipro V2.3c circuit design. It is basicly the same as the 2.3c board as far +as component placement goes. What's changed is the added resistors for the serial protocol and also +the addition of solder jumpers on the bottom of the board for the various options to connect the TX, RX, and PPM +lines through them. + +![alt_text](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/PCB%20v2.3d/PCB_v2.3d_mini.jpg "Miniature") + ###Schematic ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8443844-119-multiprotocol_diagram_rotary_serial_2.jpg) From d8bd38c1245492fa12f20269bedda5d37350e2f5 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 10 Feb 2016 16:31:20 +0100 Subject: [PATCH 056/293] OSH Park link --- README.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index a82d079..f624618 100644 --- a/README.md +++ b/README.md @@ -520,7 +520,10 @@ as component placement goes. What's changed is the added resistors for the seri the addition of solder jumpers on the bottom of the board for the various options to connect the TX, RX, and PPM lines through them. -![alt_text](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/PCB%20v2.3d/PCB_v2.3d_mini.jpg "Miniature") +![Screenshot](https://644db4de3505c40a0444-327723bce298e3ff5813fb42baeefbaa.ssl.cf1.rackcdn.com/b637193364a5e228dc8ab6ad90c0ca3c.png) +![Screenshot](https://644db4de3505c40a0444-327723bce298e3ff5813fb42baeefbaa.ssl.cf1.rackcdn.com/97b87a89b75785d70b354e5b033f5209.png) + +[OSH Park link](https://oshpark.com/shared_projects/Ztus1ah8) if you want to order. ###Schematic ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8443844-119-multiprotocol_diagram_rotary_serial_2.jpg) From 09cab9d82557641661f5232305e6cbfca7b626c9 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 10 Feb 2016 16:32:47 +0100 Subject: [PATCH 057/293] Removed some pics --- PCB v2.3d/PCB_v2.3d_mini.jpg | Bin 21935 -> 0 bytes PCB v2.3d/Schematic_v2.3d_mini.jpg | Bin 34304 -> 0 bytes 2 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 PCB v2.3d/PCB_v2.3d_mini.jpg delete mode 100644 PCB v2.3d/Schematic_v2.3d_mini.jpg diff --git a/PCB v2.3d/PCB_v2.3d_mini.jpg b/PCB v2.3d/PCB_v2.3d_mini.jpg deleted file mode 100644 index 25a7523c2215a22f017d430bfc933e370a6c44a5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21935 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 O|0YTOZ-4$f`~Lt(gJ|*q From 6d655242a634ae24038b6903ef33b854860dd39f Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 11 Feb 2016 22:11:08 +0100 Subject: [PATCH 058/293] Update list of protocols --- README.md | 56 ++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 21 deletions(-) diff --git a/README.md b/README.md index f624618..1e54edb 100644 --- a/README.md +++ b/README.md @@ -141,37 +141,51 @@ Note: ####Using serial input with er9x/ersky9x Serial is allowing access to all existing protocols & sub_protocols listed below. -Protocol|Sub_protocol|RF Module ---------|------------|--------- -Flysky||A7105 +#####A7105 RF module +Protocol|Sub_protocol +--------|------------ +Flysky| |Flysky |V9x9 |V6x6 |V912 -Hubsan||A7105 -Frsky||CC2500 -Hisky||NRF24L01 - |Hisky - |HK310 -V2x2||NRF24L01 -DSM2||CYRF6936 +Hubsan| + +#####CC2500 RF module +Protocol|Sub_protocol +--------|------------ +FrSky| +FrSkyX| + +#####CYRF6936 RF module +Protocol|Sub_protocol +--------|------------ +DSM2| |DSM2 |DSMX -Devo||CYRF6936 -YD717||NRF24L01 +Devo| + +#####NRF24L01 RF module +Protocol|Sub_protocol +--------|------------ +Hisky| + |Hisky + |HK310 +V2x2| +YD717| |YD717 |SKYWLKR |SYMAX4 |XINXUN |NIHUI -KN||NRF24L01 +KN| |WLTOYS |FEILUN -SymaX||NRF24L01 +SymaX| |SYMAX |SYMAX5C -SLT||NRF24L01 -CX10||NRF24L01 +SLT| +CX10| |GREEN |BLUE |DM007 @@ -180,18 +194,18 @@ CX10||NRF24L01 |JC3015_2 |MK33041 |Q242 -CG023||NRF24L01 +CG023| |CG023 |YD829 |H8_3D -Bayang||NRF24L01 +Bayang| FrskyX||CC2500 -ESky||NRF24L01 -MT99XX||NRF24L01 +ESky| +MT99XX| |MT |H7 |YZ -MJXQ||NRF24L01 +MJXQ| |WLH08 |X600 |X800 From 122ed79a982ddab35cd5e8ebfc6500aa01ccf685 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 11 Feb 2016 22:29:33 +0100 Subject: [PATCH 059/293] Create Protocols_Details.md --- Protocols_Details.md | 296 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 296 insertions(+) create mode 100644 Protocols_Details.md diff --git a/Protocols_Details.md b/Protocols_Details.md new file mode 100644 index 0000000..9a272fe --- /dev/null +++ b/Protocols_Details.md @@ -0,0 +1,296 @@ +#Protocols details +**You'll find below a detailed description of every supported protocols sorted by RF modules.** + +Legend: +- Extended limits supported: -125%..+125% can be used and will be transmitted. Otherwise the default is -100%..+100% only. +- Autobind protocol: you do not need to press the bind button at power up to bind, this is done automatically. + +*** +#A7105 RF Module + +##FLYSKY +Extended limits supported + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +---|---|---|---|---|---|---|--- +A|E|T|R|CH5|CH6|CH7|CH8 + +###Sub_protocol V9X9 +CH5|CH6|CH7|CH8 +---|---|---|--- +FLIP|LIGHT|PICTURE|VIDEO + +###Sub_protocol V6X6 +CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 +---|---|---|---|---|---|---|--- +FLIP|LIGHT|PICTURE|VIDEO|HEADLESS|RTH|XCAL|YCAL + +###Sub_protocol V912 +CH5|CH6 +---|--- +BTMBTN|TOPBTN + +##HUBSAN +Models: Hubsan H102D, H107/L/C/D and Hubsan H107P/C+/D+ + +Autobind protocol + +Telemetry enabled for battery voltage and TX RSSI + +Option=vTX frequency (H107D) 5645 - 5900 MHz + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP|LIGHT|PICTURE|VIDEO|HEADLESS + +*** +#CC2500 RF Module + +##FRSKY +Extended limits supported + +Telemetry enabled for A0, A1, RSSI, TSSI and Hub + +Option=fine frequency tuning, usually 0 or -41 based on the manufacturer boards + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +---|---|---|---|---|---|---|--- +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 + +##FRSKYX +Models: FrSky receivers X4R, X6R and X8R. + +Extended limits supported + +Telemetry enabled for A1 (RxBatt), A2, RSSI + +Option=fine frequency tuning, usually 0 or -41 based on the manufacturer boards + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16 +---|---|---|---|---|---|---|---|---|----|----|----|----|----|----|---- +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16 + +*** +#CYRF6936 RF Module + +##DEVO +Extended limits supported + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +---|---|---|---|---|---|---|--- +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 + +##DSM2 +Extended limits supported + +7 channels @11ms + +CH1|CH2|CH3|CH4|CH5|CH6|CH7 +---|---|---|---|---|---|--- +A|E|T|R|CH5|CH6|CH7 + +###Sub_protocol DSMX +Same as above + +*** +#NRF24L01 RF Module + +##BAYANG +Models: EAchine H8(C) mini, BayangToys X6/X7/X9, JJRC JJ850, Floureon H101 ... + +Autobind protocol + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10 +---|---|---|---|---|---|---|---|---|---- +A|E|T|R|FLIP|RTH|PICTURE|VIDEO|HEADLESS|INVERTED + +##CG023 +Models: EAchine CG023/CG031/3D X4 + +Autobind protocol + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP|LIGHT|PICTURE|VIDEO|HEADLESS + +###Sub_protocol YD829 +Models: Attop YD-822/YD-829/YD-829C ... + +CH5|CH6|CH7|CH8|CH9 +---|---|---|---|--- +FLIP||PICTURE|VIDEO|HEADLESS + +###Sub_protocol H8_3D +Models: EAchine H8 mini 3D, JJRC H20/H22 + +CH5|CH6|CH7|CH8|CH9 +---|---|---|---|--- +FLIP|LIGTH|OPT1|OPT2|CAL + +JJRC H20: OPT1=Headless, OPT2=RTH + +JJRC H22: OPT1=RTH, OPT2=180/360° flip mode + +H8 3D: OPT1=RTH + headless, OPT2=180/360° flip mode + +CAL: calibrate accelerometers + +##CX10 +Extended limits supported + +Autobind protocol + +CH1|CH2|CH3|CH4|CH5|CH6 +---|---|---|---|---|--- +A|E|T|R|FLIP|RATE + +Rate: -100%=rate 1, 0%=rate 2, +100%=rate 3 + +###Sub_protocol GREEN +Models: Cheerson CX-10 green pcb + +Same channels assignement as above. + +###Sub_protocol BLUE +Models: Cheerson CX-10 blue pcb & some newer red pcb, CX-10A, CX-10C, CX11, CX12, Floureon FX10, JJRC DHD D1 + +CH5|CH6|CH7|CH8 +---|---|---|--- +FLIP|RATE|PICTURE|VIDEO + +Rate: -100%=rate 1, 0%=rate 2, +100%=rate 3 or headless for CX-10A + +###Sub_protocol DM007 + +CH5|CH6|CH7|CH8|CH9 +---|---|---|---|--- +FLIP|MODE|PICTURE|VIDEO|HEADLESS + +###Sub_protocol Q282 and Q242 + +CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 +---|---|---|---|---|---|---|--- +FLIP|LED|PICTURE|VIDEO|HEADLESS|RTH|XCAL|YCAL + +Model: JXD 509 is using Q282 with CH12=Start/Stop motors + +###Sub_protocol JC3015_1 + +CH5|CH6|CH7|CH8 +---|---|---|--- +FLIP|MODE|PICTURE|VIDEO + +###Sub_protocol JC3015_2 + +CH5|CH6|CH7|CH8 +---|---|---|--- +FLIP|MODE|LED|DFLIP + +###Sub_protocol MK33041 + +CH5|CH6|CH7|CH8|CH9|CH10 +---|---|---|---|---|--- +FLIP|MODE|PICTURE|VIDEO|HEADLESS|RTH + +##ESKY + +CH1|CH2|CH3|CH4|CH5|CH6 +---|---|---|---|---|--- +A|E|T|R|GYRO|PITCH + +##HISKY +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +---|---|---|---|---|---|---|--- +A|E|T|R|GEAR|PITCH|GYRO|CH8 + +GYRO: -100%=6G, +100%=3G + +###HK310 +Models: RX HK-3000, HK3100 and XY3000 (TX are HK-300, HK-310 and TL-3C) + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +---|---|---|---|---|---|---|--- +|||T|R|AUX|T_FSAFE|R_FSAFE|AUX_FSAFE + +##KN +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11 +---|---|---|---|---|---|---|---|---|----|---- +A|E|T|R|DR|THOLD|IDLEUP|GYRO|Ttrim|Atrim|Etrim + +Dual Rate: +100%=full range, Throttle Hold: +100%=hold, Idle Up: +100%=3D, GYRO: -100%=6G, +100%=3G + +###Sub_protocol WLTOYS +###Sub_protocol FEILUN +Same channels assignement as above. + +##MJXQ +Autobind protocol + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13 +---|---|---|---|---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP|LED|PICTURE|VIDEO|HEADLESS|RTH|AUTOFLIP|PAN|TILT + +###Sub_protocol WLH08 +###Sub_protocol X600 +###Sub_protocol X800 +###Sub_protocol H26D + +##MT99XX +Autobind protocol + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP|LED|PICTURE|VIDEO|HEADLESS + +###Sub_protocol MT +Models: MT99xx +###Sub_protocol H7 +Models: Eachine H7 +###Sub_protocol YZ +Models: Yi Zhan i6S +Only one model can be flown at the same time since the ID is hardcoded. + +##SLT +Autobind protocol + +CH1|CH2|CH3|CH4|CH5|CH6 +---|---|---|---|---|--- +A|E|T|R|GEAR|PITCH + +##Symax +Autobind protocol + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP||PICTURE|VIDEO|HEADLESS + +###Sub_protocol SYMAX +Models: Syma X5C-1/X11/X11C/X12 + +###Sub_protocol SYMAX5C +Model: Syma X5C (original) and X2 + +##V2X2 +Models: WLToys V202/252/272, JXD 385/388, JJRC H6C, Yizhan Tarantula X6 ... + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11 +---|---|---|---|---|---|---|---|---|----|---- +A|E|T|R|FLIP|LIGHT|PICTURE|VIDEO|HEADLESS|MAG_CAL_X|MAG_CAL_Y + +PICTURE: also automatic Missile Launcher and Hoist in one direction + +VIDEO: also Sprayer, Bubbler, Missile Launcher(1), and Hoist in the other dir + +##YD717 +Autobind protocol + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP|LIGHT|PICTURE|VIDEO|HEADLESS + +###Sub_protocol YD717 +###Sub_protocol SKYWLKR +###Sub_protocol SYMAX4 +###Sub_protocol XINXUN +###Sub_protocol NIHUI +Same channels assignement as above. From 13ce3d1c9249821ab9ca9c3dbc5fd867aa847d17 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 11 Feb 2016 22:35:38 +0100 Subject: [PATCH 060/293] Separate MD files for readability --- README.md | 279 +----------------------------------------------------- 1 file changed, 2 insertions(+), 277 deletions(-) diff --git a/README.md b/README.md index 1e54edb..8377731 100644 --- a/README.md +++ b/README.md @@ -214,283 +214,8 @@ MJXQ| Note: - The dial should be set to 0 for serial. Which means all protocol selection pins should be left unconnected. -###Protocol details -Extended limits supported: -125%..+125% can be used and will be transmitted. Otherwise the default is -100%..+100% only. - -Autobind protocol: you do not need to press the bind button at power up to bind, this is done automatically. - -####BAYANG -Models: EAchine H8(C) mini, BayangToys X6/X7/X9, JJRC JJ850, Floureon H101 ... - -Autobind protocol - -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10 ----|---|---|---|---|---|---|---|---|---- -A|E|T|R|FLIP|RTH|PICTURE|VIDEO|HEADLESS|INVERTED - -####CG023 -Models: EAchine CG023/CG031/3D X4 - -Autobind protocol - -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 ----|---|---|---|---|---|---|---|--- -A|E|T|R|FLIP|LIGHT|PICTURE|VIDEO|HEADLESS - -#####Sub_protocol YD829 -Models: Attop YD-822/YD-829/YD-829C ... - -CH5|CH6|CH7|CH8|CH9 ----|---|---|---|--- -FLIP||PICTURE|VIDEO|HEADLESS - -#####Sub_protocol H8_3D -Models: EAchine H8 mini 3D, JJRC H20/H22 - -CH5|CH6|CH7|CH8|CH9 ----|---|---|---|--- -FLIP|LIGTH|OPT1|OPT2|CAL - -JJRC H20: OPT1=Headless, OPT2=RTH - -JJRC H22: OPT1=RTH, OPT2=180/360° flip mode - -H8 3D: OPT1=RTH + headless, OPT2=180/360° flip mode - -CAL: calibrate accelerometers - -####CX10 -Extended limits supported - -Autobind protocol - -CH1|CH2|CH3|CH4|CH5|CH6 ----|---|---|---|---|--- -A|E|T|R|FLIP|RATE - -Rate: -100%=rate 1, 0%=rate 2, +100%=rate 3 - -#####Sub_protocol GREEN -Models: Cheerson CX-10 green pcb - -Same channels assignement as above. - -#####Sub_protocol BLUE -Models: Cheerson CX-10 blue pcb & some newer red pcb, CX-10A, CX-10C, CX11, CX12, Floureon FX10, JJRC DHD D1 - -CH5|CH6|CH7|CH8 ----|---|---|--- -FLIP|RATE|PICTURE|VIDEO - -Rate: -100%=rate 1, 0%=rate 2, +100%=rate 3 or headless for CX-10A - -#####Sub_protocol DM007 - -CH5|CH6|CH7|CH8|CH9 ----|---|---|---|--- -FLIP|MODE|PICTURE|VIDEO|HEADLESS - -#####Sub_protocol Q282 and Q242 - -CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 ----|---|---|---|---|---|---|--- -FLIP|LED|PICTURE|VIDEO|HEADLESS|RTH|XCAL|YCAL - -Model: JXD 509 is using Q282 with CH12=Start/Stop motors - -#####Sub_protocol JC3015_1 - -CH5|CH6|CH7|CH8 ----|---|---|--- -FLIP|MODE|PICTURE|VIDEO - -#####Sub_protocol JC3015_2 - -CH5|CH6|CH7|CH8 ----|---|---|--- -FLIP|MODE|LED|DFLIP - -#####Sub_protocol MK33041 - -CH5|CH6|CH7|CH8|CH9|CH10 ----|---|---|---|---|--- -FLIP|MODE|PICTURE|VIDEO|HEADLESS|RTH - -####DEVO -Extended limits supported - -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ----|---|---|---|---|---|---|--- -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 - -####DSM2 -Extended limits supported - -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ----|---|---|---|---|---|---|--- -A|E|T|R|CH5|CH6|CH7|CH8 - -####ESKY - -CH1|CH2|CH3|CH4|CH5|CH6 ----|---|---|---|---|--- -A|E|T|R|GYRO|PITCH - -####FLYSKY -Extended limits supported - -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ----|---|---|---|---|---|---|--- -A|E|T|R|CH5|CH6|CH7|CH8 - -#####Sub_protocol V9X9 -CH5|CH6|CH7|CH8 ----|---|---|--- -FLIP|LIGHT|PICTURE|VIDEO - -#####Sub_protocol V6X6 -CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 ----|---|---|---|---|---|---|--- -FLIP|LIGHT|PICTURE|VIDEO|HEADLESS|RTH|XCAL|YCAL - -#####Sub_protocol V912 -CH5|CH6 ----|--- -BTMBTN|TOPBTN - -####FRSKY -Extended limits supported - -Telemetry enabled for A0, A1, RSSI, TSSI and Hub - -Option=fine frequency tuning, usually 0 or -41 based on the manufacturer boards - -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ----|---|---|---|---|---|---|--- -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 - -####FRSKYX -Models: FrSky receivers X4R, X6R and X8R. - -Extended limits supported - -Telemetry enabled for A1 (RxBatt), A2, RSSI - -Option=fine frequency tuning, usually 0 or -41 based on the manufacturer boards - -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16 ----|---|---|---|---|---|---|---|---|----|----|----|----|----|----|---- -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16 - -####HISKY -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ----|---|---|---|---|---|---|--- -A|E|T|R|GEAR|PITCH|GYRO|CH8 - -GYRO: -100%=6G, +100%=3G - -#####HK310 -Models: RX HK-3000, HK3100 and XY3000 (TX are HK-300, HK-310 and TL-3C) - -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ----|---|---|---|---|---|---|--- -|||T|R|AUX|T_FSAFE|R_FSAFE|AUX_FSAFE - -####HUBSAN -Models: Hubsan H102D, H107/L/C/D and Hubsan H107P/C+/D+ - -Autobind protocol - -Telemetry enabled for battery voltage and TX RSSI - -Option=vTX frequency (H107D) 5645 - 5900 MHz - -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 ----|---|---|---|---|---|---|---|--- -A|E|T|R|FLIP|LIGHT|PICTURE|VIDEO|HEADLESS - -####KN -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11 ----|---|---|---|---|---|---|---|---|----|---- -A|E|T|R|DR|THOLD|IDLEUP|GYRO|Ttrim|Atrim|Etrim - -Dual Rate: +100%=full range, Throttle Hold: +100%=hold, Idle Up: +100%=3D, GYRO: -100%=6G, +100%=3G - -#####Sub_protocol WLTOYS -#####Sub_protocol FEILUN -Same channels assignement as above. - -####MJXQ -Autobind protocol - -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13 ----|---|---|---|---|---|---|---|---|---|---|---|--- -A|E|T|R|FLIP|LED|PICTURE|VIDEO|HEADLESS|RTH|AUTOFLIP|PAN|TILT - -#####Sub_protocol WLH08 -#####Sub_protocol X600 -#####Sub_protocol X800 -#####Sub_protocol H26D - -####MT99XX -Autobind protocol - -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 ----|---|---|---|---|---|---|---|--- -A|E|T|R|FLIP|LED|PICTURE|VIDEO|HEADLESS - -#####Sub_protocol MT -Models: MT99xx -#####Sub_protocol H7 -Models: Eachine H7 -#####Sub_protocol YZ -Models: Yi Zhan i6S -Only one model can be flown at the same time since the ID is hardcoded. - -####SLT -Autobind protocol - -CH1|CH2|CH3|CH4|CH5|CH6 ----|---|---|---|---|--- -A|E|T|R|GEAR|PITCH - -####Symax -Autobind protocol - -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 ----|---|---|---|---|---|---|---|--- -A|E|T|R|FLIP||PICTURE|VIDEO|HEADLESS - -#####Sub_protocol SYMAX -Models: Syma X5C-1/X11/X11C/X12 - -#####Sub_protocol SYMAX5C -Model: Syma X5C (original) and X2 - -####V2X2 -Models: WLToys V202/252/272, JXD 385/388, JJRC H6C, Yizhan Tarantula X6 ... - -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11 ----|---|---|---|---|---|---|---|---|----|---- -A|E|T|R|FLIP|LIGHT|PICTURE|VIDEO|HEADLESS|MAG_CAL_X|MAG_CAL_Y - -PICTURE: also automatic Missile Launcher and Hoist in one direction - -VIDEO: also Sprayer, Bubbler, Missile Launcher(1), and Hoist in the other dir - -####YD717 -Autobind protocol - -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 ----|---|---|---|---|---|---|---|--- -A|E|T|R|FLIP|LIGHT|PICTURE|VIDEO|HEADLESS - -#####Sub_protocol YD717 -#####Sub_protocol SKYWLKR -#####Sub_protocol SYMAX4 -#####Sub_protocol XINXUN -#####Sub_protocol NIHUI -Same channels assignement as above. +###Protocols details +**Check the [Protocols_Details.md](./Protocols_Details.md) file for a detailed description of every protocols with channels assignements.** ##Hardware From c310d698ca6c125ab380049f007cb6c51526b0a8 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 11 Feb 2016 22:52:41 +0100 Subject: [PATCH 061/293] Short description on how to compile --- README.md | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 8377731..f092a8a 100644 --- a/README.md +++ b/README.md @@ -280,11 +280,17 @@ You can 3D print your box (details [here](http://www.rcgroups.com/forums/showpos ##Compilation and programmation ###Toolchain -Supported Arduino version is [1.6.7](https://www.arduino.cc/download_handler.php?f=/arduino-1.6.7-windows.exe). Make sure to select "Arduino Pro or Pro Mini, ATmega328 (5V,16MHz)" before compiling. +Multiprotocol source can be compiled using the Arduino IDE. -Compilation of the code posted here works. So if it doesn't for you this is a problem with your setup, please double check everything before asking. +The currently supported Arduino version is [1.6.7](https://www.arduino.cc/download_handler.php?f=/arduino-1.6.7-windows.exe). -_Config.h file can be modified to compile with/without some protocols, change protocols/sub_protocols/settings associated with dial for PPM input, different channel orders, different channels timing, Telemetry or not, ... +Download the [zip file](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/archive/master.zip) of this repository, unzip it in a folder, navigate to the Multiprotocol directory and then click on Multiprotocol.ino. The Arduino environment will appear and the Multiprotocol project will be loaded. + +[_Config.h file](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Multiprotocol/_Config.h) must be modified to select which protocols will be available, change protocols/sub_protocols/settings associated with dial for PPM input, different TX channel orders and timing, Telemetry or not, ... + +Notes: +- Make sure to select "Arduino Pro or Pro Mini, ATmega328 (5V,16MHz)" before compiling. +- Compilation of the code posted here works. So if it doesn't for you this is a problem with your setup, please double check everything before asking. ###Upload the code using ISP (In System Programming) It is recommended to use an external programmer like [USBASP](http://www.banggood.com/USBASP-USBISP-3_3-5V-AVR-Downloader-Programmer-With-ATMEGA8-ATMEGA128-p-934425.html) to upload the code in the Atmega328. The programmer should be set to 3.3V or nothing to not supply any over voltage to the multimodule and avoid any damages. From 71ef72bae335bdcb6649d3efedf947a23c0d7c0b Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 11 Feb 2016 22:56:26 +0100 Subject: [PATCH 062/293] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index f092a8a..711b842 100644 --- a/README.md +++ b/README.md @@ -250,9 +250,9 @@ or build your own board using [SMD components](http://www.rcgroups.com/forums/sh ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7952726-108-thumb-image-62c29cf2.jpg?d=1433909893) ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7952733-114-thumb-P4100002.JPG?d=1433910155) ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7952734-189-thumb-P4100003.JPG?d=1433910159) -**If you build this PCB v2.3c and want to enable serial mode for er9x/ersky9x, you have to do [this mod](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8667856-242-multi.jpg).** +If you build this PCB v2.3c and want to enable serial mode for er9x/ersky9x, you have to do [this mod](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8667856-242-multi.jpg). -**New PCB v2.3d! available in the [github repository](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/tree/master/PCB%20v2.3d)** +**[New PCB v2.3d!](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/tree/master/PCB%20v2.3d) available** This is a variant of the Multipro V2.3c circuit design. It is basicly the same as the 2.3c board as far as component placement goes. What's changed is the added resistors for the serial protocol and also @@ -335,7 +335,7 @@ This will make sure your ATMEGA328 is well configured and the global TX ID is no - Connect 1 to 4 of the selection protocol pins to GND. ####Input Mode - Serial -- Make sure you have done the mods to the v2.3c PCB by adding the 2.2k and 330 ohm resistors as indicated in the [Board section] (https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#board). +- Make sure you have done the mods to the v2.3c PCB by adding the 2.2k and 470 ohm resistors as indicated in the [Board section] (https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#board). - Leave all 4 selection pins unconnected. ###Bind From d4287d30463b6cc9a27019d73b241018df37e372 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 11 Feb 2016 23:01:39 +0100 Subject: [PATCH 063/293] Update README.md --- README.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/README.md b/README.md index 711b842..93631f7 100644 --- a/README.md +++ b/README.md @@ -254,8 +254,7 @@ If you build this PCB v2.3c and want to enable serial mode for er9x/ersky9x, you **[New PCB v2.3d!](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/tree/master/PCB%20v2.3d) available** -This is a variant of the Multipro V2.3c circuit design. It is basicly the same as the 2.3c board as far -as component placement goes. What's changed is the added resistors for the serial protocol and also +Repository includes Kicad files of schematic and pcb. This is a variant of the Multipro V2.3c circuit design. It is basicly the same as the 2.3c board as far as component placement goes. What's changed is the added resistors for the serial protocol and also the addition of solder jumpers on the bottom of the board for the various options to connect the TX, RX, and PPM lines through them. From 5607740e77b2afa5d7bee6ceb4a029b9ed4efd62 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sat, 13 Feb 2016 09:06:58 +0100 Subject: [PATCH 064/293] Update Protocols_Details.md --- Protocols_Details.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 9a272fe..ec49550 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -245,7 +245,7 @@ A|E|T|R|FLIP|LED|PICTURE|VIDEO|HEADLESS ###Sub_protocol MT Models: MT99xx ###Sub_protocol H7 -Models: Eachine H7 +Models: Eachine H7, Cheerson CX023 ###Sub_protocol YZ Models: Yi Zhan i6S Only one model can be flown at the same time since the ID is hardcoded. From 795df2937e8c60aafb0f21c494fb22361edad5fe Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 15 Feb 2016 21:15:09 +0100 Subject: [PATCH 065/293] Space and ram optimization on FrSky & FrSkyX --- Multiprotocol/CC2500_SPI.ino | 2 +- Multiprotocol/DSM2_cyrf6936.ino | 8 - Multiprotocol/FlySky_a7105.ino | 4 +- Multiprotocol/FrSkyX_cc2500.ino | 272 ++++++++++++++++---------------- Multiprotocol/FrSky_cc2500.ino | 52 ++---- Multiprotocol/Multiprotocol.ino | 10 +- Multiprotocol/NRF24l01_SPI.ino | 2 +- Multiprotocol/_Config.h | 71 +++++---- Multiprotocol/iface_cc2500.h | 39 +++++ 9 files changed, 232 insertions(+), 228 deletions(-) diff --git a/Multiprotocol/CC2500_SPI.ino b/Multiprotocol/CC2500_SPI.ino index bc6928e..afcd8bb 100644 --- a/Multiprotocol/CC2500_SPI.ino +++ b/Multiprotocol/CC2500_SPI.ino @@ -185,4 +185,4 @@ void CC2500_SetTxRxMode(uint8_t mode) cc2500_writeReg(CC2500_02_IOCFG0, 0x2F); cc2500_writeReg(CC2500_00_IOCFG2, 0x2F); } -} \ No newline at end of file +} diff --git a/Multiprotocol/DSM2_cyrf6936.ino b/Multiprotocol/DSM2_cyrf6936.ino index 928d24e..0882d77 100644 --- a/Multiprotocol/DSM2_cyrf6936.ino +++ b/Multiprotocol/DSM2_cyrf6936.ino @@ -114,14 +114,6 @@ uint8_t data_col; uint16_t cyrf_state; uint8_t crcidx; uint8_t binding; -/* -#ifdef USE_FIXED_MFGID -const uint8_t cyrfmfg_id[6] = {0x5e, 0x28, 0xa3, 0x1b, 0x00, 0x00}; //dx8 -const uint8_t cyrfmfg_id[6] = {0xd4, 0x62, 0xd6, 0xad, 0xd3, 0xff}; //dx6i -#else -//uint8_t cyrfmfg_id[6]; -#endif -*/ static void __attribute__((unused)) build_bind_packet() { diff --git a/Multiprotocol/FlySky_a7105.ino b/Multiprotocol/FlySky_a7105.ino index 8c5f956..84fa3df 100644 --- a/Multiprotocol/FlySky_a7105.ino +++ b/Multiprotocol/FlySky_a7105.ino @@ -45,7 +45,7 @@ enum { FLAG_V9X9_VIDEO = 0x40, FLAG_V9X9_CAMERA= 0x80, // flags going to byte 12 - FLAG_V9X9_UNK = 0x10, // undocumented ? + FLAG_V9X9_FLIP = 0x10, FLAG_V9X9_LED = 0x20, }; @@ -82,7 +82,7 @@ static void __attribute__((unused)) flysky_apply_extension_flags() { case V9X9: if(Servo_AUX1) - packet[12] |= FLAG_V9X9_UNK; + packet[12] |= FLAG_V9X9_FLIP; if(Servo_AUX2) packet[12] |= FLAG_V9X9_LED; if(Servo_AUX3) diff --git a/Multiprotocol/FrSkyX_cc2500.ino b/Multiprotocol/FrSkyX_cc2500.ino index 19044ef..dc6e2f2 100644 --- a/Multiprotocol/FrSkyX_cc2500.ino +++ b/Multiprotocol/FrSkyX_cc2500.ino @@ -43,101 +43,12 @@ 0x34, 0x1B, 0x00, 0x1D, 0x03 }; - uint8_t hop(uint8_t byte) + static uint8_t __attribute__((unused)) hop(uint8_t byte) { return pgm_read_byte_near(&hop_data[byte]); } - uint16_t initFrSkyX() - { - while(!chanskip) - { - randomSeed((uint32_t)analogRead(A6) << 10 | analogRead(A7)); - chanskip=random(0xfefefefe)%47; - } - while((chanskip-ctr)%4) - ctr=(ctr+1)%4; - - counter_rst=(chanskip-ctr)>>2; - //for test*************** - //rx_tx_addr[3]=0xB3; - //rx_tx_addr[2]=0xFD; - //************************ - frskyX_init(); - // - if(IS_AUTOBIND_FLAG_on) - { - state = FRSKY_BIND; - initialize_data(1); - } - else - { - state = FRSKY_DATA1; - initialize_data(0); - } - return 10000; - } - - uint16_t ReadFrSkyX() - { - switch(state) - { - default: - set_start(47); - CC2500_SetPower(); - cc2500_strobe(CC2500_SFRX); - // - frskyX_build_bind_packet(); - cc2500_strobe(CC2500_SIDLE); - cc2500_writeFifo(packet, packet[0]+1); - state++; - return 9000; - case FRSKY_BIND_DONE: - initialize_data(0); - channr=0; - BIND_DONE; - state++; - break; - case FRSKY_DATA1: - LED_ON; - CC2500_SetTxRxMode(TX_EN); - set_start(channr); - CC2500_SetPower(); - cc2500_strobe(CC2500_SFRX); - channr = (channr+chanskip)%47; - cc2500_strobe(CC2500_SIDLE); - cc2500_writeFifo(packet, packet[0]+1); - // - frskyX_data_frame(); - state++; - return 5500; - case FRSKY_DATA2: - CC2500_SetTxRxMode(RX_EN); - cc2500_strobe(CC2500_SIDLE); - state++; - return 200; - case FRSKY_DATA3: - cc2500_strobe(CC2500_SRX); - state++; - return 3000; - case FRSKY_DATA4: - len = cc2500_readReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F; - if (len &&(len>8) ^ byte) & 0xFF]); + return byte; + } + + static uint16_t __attribute__((unused)) scaleForPXX( uint8_t i ) + { //mapped 860,2140(125%) range to 64,1984(PXX values); + return (uint16_t)(((Servo_data[i]-PPM_MIN)*3)>>1)+64; + } + + static void __attribute__((unused)) frskyX_build_bind_packet() { crc=0; packet[0] = 0x1D; @@ -243,7 +159,7 @@ // } - void frskyX_data_frame() + static void __attribute__((unused)) frskyX_data_frame() { //0x1D 0xB3 0xFD 0x02 0x56 0x07 0x15 0x00 0x00 0x00 0x04 0x40 0x00 0x04 0x40 0x00 0x04 0x40 0x00 0x04 0x40 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x96 0x12 // @@ -302,14 +218,92 @@ packet[29]=lowByte(crc); } - uint16_t scaleForPXX( uint8_t i ) - { //mapped 860,2140(125%) range to 64,1984(PXX values); - return (uint16_t)(((Servo_data[i]-PPM_MIN)*3)>>1)+64; - } - - uint8_t crc_Byte( uint8_t byte ) + uint16_t ReadFrSkyX() { - crc = (crc<<8) ^ pgm_read_word(&CRCTable[((uint8_t)(crc>>8) ^ byte) & 0xFF]); - return byte; + switch(state) + { + default: + set_start(47); + CC2500_SetPower(); + cc2500_strobe(CC2500_SFRX); + // + frskyX_build_bind_packet(); + cc2500_strobe(CC2500_SIDLE); + cc2500_writeFifo(packet, packet[0]+1); + state++; + return 9000; + case FRSKY_BIND_DONE: + initialize_data(0); + channr=0; + BIND_DONE; + state++; + break; + case FRSKY_DATA1: + LED_ON; + CC2500_SetTxRxMode(TX_EN); + set_start(channr); + CC2500_SetPower(); + cc2500_strobe(CC2500_SFRX); + channr = (channr+chanskip)%47; + cc2500_strobe(CC2500_SIDLE); + cc2500_writeFifo(packet, packet[0]+1); + // + frskyX_data_frame(); + state++; + return 5500; + case FRSKY_DATA2: + CC2500_SetTxRxMode(RX_EN); + cc2500_strobe(CC2500_SIDLE); + state++; + return 200; + case FRSKY_DATA3: + cc2500_strobe(CC2500_SRX); + state++; + return 3000; + case FRSKY_DATA4: + len = cc2500_readReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F; + if (len &&(len>2; + //for test*************** + //rx_tx_addr[3]=0xB3; + //rx_tx_addr[2]=0xFD; + //************************ + frskyX_init(); + // + if(IS_AUTOBIND_FLAG_on) + { + state = FRSKY_BIND; + initialize_data(1); + } + else + { + state = FRSKY_DATA1; + initialize_data(0); + } + return 10000; + } #endif \ No newline at end of file diff --git a/Multiprotocol/FrSky_cc2500.ino b/Multiprotocol/FrSky_cc2500.ino index f3c6d3c..ec17450 100644 --- a/Multiprotocol/FrSky_cc2500.ino +++ b/Multiprotocol/FrSky_cc2500.ino @@ -38,45 +38,19 @@ static void __attribute__((unused)) frsky2way_init(uint8_t bind) // Configure cc2500 for tx mode CC2500_Reset(); // - cc2500_writeReg(CC2500_02_IOCFG0, 0x06); - cc2500_writeReg(CC2500_00_IOCFG2, 0x06); - cc2500_writeReg(CC2500_17_MCSM1, 0x0c); - cc2500_writeReg(CC2500_18_MCSM0, 0x18); - cc2500_writeReg(CC2500_06_PKTLEN, 0x19); - cc2500_writeReg(CC2500_07_PKTCTRL1, 0x04); - cc2500_writeReg(CC2500_08_PKTCTRL0, 0x05); - cc2500_writeReg(CC2500_3E_PATABLE, 0xff); - cc2500_writeReg(CC2500_0B_FSCTRL1, 0x08); - cc2500_writeReg(CC2500_0C_FSCTRL0, option); - //base freq FREQ = 0x5C7627 (F = 2404MHz) - cc2500_writeReg(CC2500_0D_FREQ2, 0x5c); - cc2500_writeReg(CC2500_0E_FREQ1, 0x76); - cc2500_writeReg(CC2500_0F_FREQ0, 0x27); - // - cc2500_writeReg(CC2500_10_MDMCFG4, 0xAA); - cc2500_writeReg(CC2500_11_MDMCFG3, 0x39); - cc2500_writeReg(CC2500_12_MDMCFG2, 0x11); - cc2500_writeReg(CC2500_13_MDMCFG1, 0x23); - cc2500_writeReg(CC2500_14_MDMCFG0, 0x7a); - cc2500_writeReg(CC2500_15_DEVIATN, 0x42); - cc2500_writeReg(CC2500_19_FOCCFG, 0x16); - cc2500_writeReg(CC2500_1A_BSCFG, 0x6c); - cc2500_writeReg(CC2500_1B_AGCCTRL2, bind ? 0x43 : 0x03); - cc2500_writeReg(CC2500_1C_AGCCTRL1,0x40); - cc2500_writeReg(CC2500_1D_AGCCTRL0,0x91); - cc2500_writeReg(CC2500_21_FREND1, 0x56); - cc2500_writeReg(CC2500_22_FREND0, 0x10); - cc2500_writeReg(CC2500_23_FSCAL3, 0xa9); - cc2500_writeReg(CC2500_24_FSCAL2, 0x0A); - cc2500_writeReg(CC2500_25_FSCAL1, 0x00); - cc2500_writeReg(CC2500_26_FSCAL0, 0x11); - cc2500_writeReg(CC2500_29_FSTEST, 0x59); - cc2500_writeReg(CC2500_2C_TEST2, 0x88); - cc2500_writeReg(CC2500_2D_TEST1, 0x31); - cc2500_writeReg(CC2500_2E_TEST0, 0x0B); - cc2500_writeReg(CC2500_03_FIFOTHR, 0x07); - cc2500_writeReg(CC2500_09_ADDR, 0x00); - // + for(uint8_t i=0;i<36;i++) + { + uint8_t reg=pgm_read_byte_near(&cc2500_conf[i][0]); + uint8_t val=pgm_read_byte_near(&cc2500_conf[i][1]); + + if(reg==CC2500_0C_FSCTRL0) + val=option; + else + if(reg==CC2500_1B_AGCCTRL2) + val=bind ? 0x43 : 0x03; + cc2500_writeReg(reg,val); + } + CC2500_SetTxRxMode(TX_EN); CC2500_SetPower(); diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 38c23aa..802c8c6 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -44,8 +44,6 @@ uint8_t packet[40]; // Servo data uint16_t Servo_data[NUM_CHN]; uint8_t Servo_AUX; -// PPM variable -volatile uint16_t PPM_data[NUM_CHN]; // Protocol variables uint8_t rx_tx_addr[5]; @@ -74,6 +72,9 @@ uint8_t RX_num; uint8_t mode_select; uint8_t protocol_flags=0,protocol_flags2=0; +// PPM variable +volatile uint16_t PPM_data[NUM_CHN]; + // Serial variables #define RXBUFFER_SIZE 25 #define TXBUFFER_SIZE 12 @@ -156,7 +157,9 @@ void setup() MProtocol_id_master=random_id(10,false); //Init RF modules - CC2500_Reset(); + #ifdef CC2500_INSTALLED + CC2500_Reset(); + #endif //Protocol and interrupts initialization if(mode_select != MODE_SERIAL) @@ -582,7 +585,6 @@ void Serial_write(uint8_t data) static void Mprotocol_serial_init() { - #define BAUD 100000 #include UBRR0H = UBRRH_VALUE; UBRR0L = UBRRL_VALUE; diff --git a/Multiprotocol/NRF24l01_SPI.ino b/Multiprotocol/NRF24l01_SPI.ino index cec1439..df596e1 100644 --- a/Multiprotocol/NRF24l01_SPI.ino +++ b/Multiprotocol/NRF24l01_SPI.ino @@ -154,7 +154,7 @@ void NRF24L01_SetBitrate(uint8_t bitrate) // Note that bitrate 250kbps (and bit RF_DR_LOW) is valid only // for nRF24L01+. There is no way to programmatically tell it from // older version, nRF24L01, but the older is practically phased out - // by Nordic, so we assume that we deal with with modern version. + // by Nordic, so we assume that we deal with modern version. // Bit 0 goes to RF_DR_HIGH, bit 1 - to RF_DR_LOW rf_setup = (rf_setup & 0xD7) | ((bitrate & 0x02) << 4) | ((bitrate & 0x01) << 3); diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 83bf3ec..090fe4e 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -59,24 +59,23 @@ #endif //Update this table to set which protocol and all associated settings are called for the corresponding dial number -static const PPM_Parameters PPM_prot[15]= -{ -// Protocol Sub protocol RX_Num Power Auto Bind Option - {MODE_FLYSKY, Flysky , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=1 - {MODE_HUBSAN, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=2 - {MODE_FRSKY , 0 , 0 , P_HIGH , NO_AUTOBIND , 0xD7 }, //Dial=3 - {MODE_HISKY , Hisky , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=4 - {MODE_V2X2 , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=5 - {MODE_DSM2 , DSM2 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=6 - {MODE_DEVO , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=7 - {MODE_YD717 , YD717 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=8 - {MODE_KN , WLTOYS , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=9 - {MODE_SYMAX , SYMAX , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=10 - {MODE_SLT , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=11 - {MODE_CX10 , CX10_BLUE , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=12 - {MODE_CG023 , CG023 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=13 - {MODE_BAYANG, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, //Dial=14 - {MODE_SYMAX , SYMAX5C , 0 , P_HIGH , NO_AUTOBIND , 0 } //Dial=15 +const PPM_Parameters PPM_prot[15]= { +// Dial Protocol Sub protocol RX_Num Power Auto Bind Option +/* 1 */ {MODE_FLYSKY, Flysky , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 2 */ {MODE_HUBSAN, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 3 */ {MODE_FRSKY , 0 , 0 , P_HIGH , NO_AUTOBIND , 0xD7 }, +/* 4 */ {MODE_HISKY , Hisky , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 5 */ {MODE_V2X2 , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 6 */ {MODE_DSM2 , DSM2 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 7 */ {MODE_DEVO , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 8 */ {MODE_YD717 , YD717 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 9 */ {MODE_KN , WLTOYS , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 10 */ {MODE_SYMAX , SYMAX , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 11 */ {MODE_SLT , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 12 */ {MODE_CX10 , CX10_BLUE , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 13 */ {MODE_CG023 , CG023 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 14 */ {MODE_BAYANG, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 15 */ {MODE_SYMAX , SYMAX5C , 0 , P_HIGH , NO_AUTOBIND , 0 } }; /* Available protocols and associated sub protocols: MODE_FLYSKY @@ -155,10 +154,10 @@ Option value between 0 and 255. 0xD7 or 0x00 for Frsky fine tuning. // Turnigy PPM and channels #if defined(TX_ER9X) -#define PPM_MAX 2140 -#define PPM_MIN 860 -#define PPM_MAX_100 2012 -#define PPM_MIN_100 988 +#define PPM_MAX 2140 // 125% +#define PPM_MIN 860 // 125% +#define PPM_MAX_100 2012 // 100% +#define PPM_MIN_100 988 // 100% enum chan_order{ AILERON =0, ELEVATOR, @@ -178,10 +177,10 @@ enum chan_order{ // Devo PPM and channels #if defined(TX_DEVO7) -#define PPM_MAX 2100 -#define PPM_MIN 900 -#define PPM_MAX_100 1920 -#define PPM_MIN_100 1120 +#define PPM_MAX 2100 // 125% +#define PPM_MIN 900 // 125% +#define PPM_MAX_100 1920 // 100% +#define PPM_MIN_100 1120 // 100% enum chan_order{ ELEVATOR=0, AILERON, @@ -201,10 +200,10 @@ enum chan_order{ // SPEKTRUM PPM and channels #if defined(TX_SPEKTRUM) -#define PPM_MAX 2000 -#define PPM_MIN 1000 -#define PPM_MAX_100 1900 -#define PPM_MIN_100 1100 +#define PPM_MAX 2000 // 125% +#define PPM_MIN 1000 // 125% +#define PPM_MAX_100 1900 // 100% +#define PPM_MIN_100 1100 // 100% enum chan_order{ THROTTLE=0, AILERON, @@ -224,10 +223,10 @@ enum chan_order{ // HISKY #if defined(TX_HISKY) -#define PPM_MAX 2000 -#define PPM_MIN 1000 -#define PPM_MAX_100 1900 -#define PPM_MIN_100 1100 +#define PPM_MAX 2000 // 125% +#define PPM_MIN 1000 // 125% +#define PPM_MAX_100 1900 // 100% +#define PPM_MIN_100 1100 // 100% enum chan_order{ AILERON =0, ELEVATOR, @@ -248,3 +247,7 @@ enum chan_order{ #define PPM_MIN_COMMAND 1250 #define PPM_SWITCH 1550 #define PPM_MAX_COMMAND 1750 + +//Uncoment the desired serial speed +#define BAUD 100000 +//#define BAUD 125000 diff --git a/Multiprotocol/iface_cc2500.h b/Multiprotocol/iface_cc2500.h index cb7b623..ee5242f 100644 --- a/Multiprotocol/iface_cc2500.h +++ b/Multiprotocol/iface_cc2500.h @@ -156,4 +156,43 @@ enum { //void CC2500_WriteData(u8 *packet, u8 length); //void CC2500_ReadData(u8 *dpbuffer, int len); //void CC2500_SetTxRxMode(enum TXRX_State); + +const PROGMEM uint8_t cc2500_conf[][2]={ + { CC2500_02_IOCFG0, 0x06 }, + { CC2500_00_IOCFG2, 0x06 }, + { CC2500_17_MCSM1, 0x0c }, + { CC2500_18_MCSM0, 0x18 }, + { CC2500_06_PKTLEN, 0x19 }, + { CC2500_07_PKTCTRL1, 0x04 }, + { CC2500_08_PKTCTRL0, 0x05 }, + { CC2500_3E_PATABLE, 0xff }, + { CC2500_0B_FSCTRL1, 0x08 }, + { CC2500_0C_FSCTRL0, 0x00 }, // option + { CC2500_0D_FREQ2, 0x5c }, + { CC2500_0E_FREQ1, 0x76 }, + { CC2500_0F_FREQ0, 0x27 }, + { CC2500_10_MDMCFG4, 0xAA }, + { CC2500_11_MDMCFG3, 0x39 }, + { CC2500_12_MDMCFG2, 0x11 }, + { CC2500_13_MDMCFG1, 0x23 }, + { CC2500_14_MDMCFG0, 0x7a }, + { CC2500_15_DEVIATN, 0x42 }, + { CC2500_19_FOCCFG, 0x16 }, + { CC2500_1A_BSCFG, 0x6c }, + { CC2500_1B_AGCCTRL2, 0x43 }, // bind ? 0x43 : 0x03 + { CC2500_1C_AGCCTRL1,0x40 }, + { CC2500_1D_AGCCTRL0,0x91 }, + { CC2500_21_FREND1, 0x56 }, + { CC2500_22_FREND0, 0x10 }, + { CC2500_23_FSCAL3, 0xa9 }, + { CC2500_24_FSCAL2, 0x0A }, + { CC2500_25_FSCAL1, 0x00 }, + { CC2500_26_FSCAL0, 0x11 }, + { CC2500_29_FSTEST, 0x59 }, + { CC2500_2C_TEST2, 0x88 }, + { CC2500_2D_TEST1, 0x31 }, + { CC2500_2E_TEST0, 0x0B }, + { CC2500_03_FIFOTHR, 0x07 }, + { CC2500_09_ADDR, 0x00 } +}; #endif From 05fb8bc742dca0dd86b6ad0e938a3c213eb92784 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 26 Feb 2016 19:02:26 +0100 Subject: [PATCH 066/293] Added Shenqi protocol and LT8910 emulation layer --- Multiprotocol/Multiprotocol.ino | 10 +- Multiprotocol/NRF24l01_SPI.ino | 193 ++++++++++++++++++++++++++++++ Multiprotocol/SHENQI_nrf24l01.ino | 108 +++++++++++++++++ Multiprotocol/_Config.h | 3 + Multiprotocol/multiprotocol.h | 4 +- 5 files changed, 315 insertions(+), 3 deletions(-) create mode 100644 Multiprotocol/SHENQI_nrf24l01.ino diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 802c8c6..f7393da 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -146,7 +146,7 @@ void setup() // after this mode_select will be one of {0000, 0001, ..., 1111} mode_select=0x0F - ( ( (PINB>>2)&0x07 ) | ( (PINC<<3)&0x08) );//encoder dip switches 1,2,4,8=>B2,B3,B4,C0 //********************************** -//mode_select=14; // here to test PPM +//mode_select=1; // here to test PPM //********************************** // Update LED @@ -431,6 +431,12 @@ static void protocol_init() next_callback=initMJXQ(); remote_callback = MJXQ_callback; break; +#endif +#if defined(SHENQI_NRF24L01_INO) + case MODE_SHENQI: + next_callback=initSHENQI(); + remote_callback = SHENQI_callback; + break; #endif } @@ -513,7 +519,7 @@ static void module_reset() case MODE_DEVO: CYRF_Reset(); break; - default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY, MODE_MT99XX, MODE_MJXQ + default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY, MODE_MT99XX, MODE_MJXQ, MODE_SHENQI NRF24L01_Reset(); break; } diff --git a/Multiprotocol/NRF24l01_SPI.ino b/Multiprotocol/NRF24l01_SPI.ino index df596e1..f95e86f 100644 --- a/Multiprotocol/NRF24l01_SPI.ino +++ b/Multiprotocol/NRF24l01_SPI.ino @@ -409,3 +409,196 @@ void XN297_ReadPayload(uint8_t* msg, uint8_t len) } // End of XN297 emulation + +/////////////// +// LT8910 emulation layer +uint8_t LT8910_buffer[64]; +uint8_t LT8910_buffer_start; +uint16_t LT8910_buffer_overhead_bits; +uint8_t LT8910_addr[8]; +uint8_t LT8910_addr_size; +uint8_t LT8910_Preamble_Len; +uint8_t LT8910_Tailer_Len; +uint8_t LT8910_CRC_Initial_Data; +uint8_t LT8910_Flags; +#define LT8910_CRC_ON 6 +#define LT8910_SCRAMBLE_ON 5 +#define LT8910_PACKET_LENGTH_EN 4 +#define LT8910_DATA_PACKET_TYPE_1 3 +#define LT8910_DATA_PACKET_TYPE_0 2 +#define LT8910_FEC_TYPE_1 1 +#define LT8910_FEC_TYPE_0 0 + +void LT8910_Config(uint8_t preamble_len, uint8_t trailer_len, uint8_t flags, uint8_t crc_init) +{ + //Preamble 1 to 8 bytes + LT8910_Preamble_Len=preamble_len; + //Trailer 4 to 18 bits + LT8910_Tailer_Len=trailer_len; + //Flags + // CRC_ON: 1 on, 0 off + // SCRAMBLE_ON: 1 on, 0 off + // PACKET_LENGTH_EN: 1 1st byte of payload is payload size + // DATA_PACKET_TYPE: 00 NRZ, 01 Manchester, 10 8bit/10bit line code, 11 interleave data type + // FEC_TYPE: 00 No FEC, 01 FEC13, 10 FEC23, 11 reserved + LT8910_Flags=flags; + //CRC init constant + LT8910_CRC_Initial_Data=crc_init; +} + +void LT8910_SetChannel(uint8_t channel) +{ + NRF24L01_WriteReg(NRF24L01_05_RF_CH, channel +2); //NRF24L01 is 2400+channel but LT8900 is 2402+channel +} + +void LT8910_SetTxRxMode(enum TXRX_State mode) +{ + if(mode == TX_EN) + { + //Switch to TX + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_SetTxRxMode(TX_EN); + //Disable CRC + NRF24L01_WriteReg(NRF24L01_00_CONFIG, (1 << NRF24L01_00_PWR_UP)); + } + else + if (mode == RX_EN) + { + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only + NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, 32); + //Switch to RX + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_FlushRx(); + NRF24L01_SetTxRxMode(RX_EN); + // Disable CRC + NRF24L01_WriteReg(NRF24L01_00_CONFIG, (1 << NRF24L01_00_PWR_UP) | (1 << NRF24L01_00_PRIM_RX) ); + } + else + NRF24L01_SetTxRxMode(TXRX_OFF); +} + +void LT8910_BuildOverhead() +{ + uint8_t pos; + + //Build overhead + //preamble + memset(LT8910_buffer,LT8910_addr[0]&0x01?0xAA:0x55,LT8910_Preamble_Len-1); + pos=LT8910_Preamble_Len-1; + //address + for(uint8_t i=0;i5?5:pos; +} + +void LT8910_SetAddress(uint8_t *address,uint8_t addr_size) +{ + uint8_t addr[5]; + + //Address size (SyncWord) 2 to 8 bytes, 16/32/48/64 bits + LT8910_addr_size=addr_size; + memcpy(LT8910_addr,address,LT8910_addr_size); + + //Build overhead + LT8910_BuildOverhead(); + + //Set NRF RX&TX address based on overhead content + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, LT8910_buffer_start-2); + for(uint8_t i=0;i>8)&0xFF; + } + //Check len + if(LT8910_Flags&_BV(LT8910_PACKET_LENGTH_EN)) + { + crc=crc16_update(crc,buffer[pos]); + if(bit_reverse(len)!=buffer[pos++]) + return 0; // wrong len... + } + //Decode message + for(i=0;i>8)&0xFF)) return 0; // wrong CRC... + if(buffer[pos]!=(crc&0xFF)) return 0; // wrong CRC... + } + //Everything ok + return 1; +} + +void LT8910_WritePayload(uint8_t* msg, uint8_t len) +{ + unsigned int crc=LT8910_CRC_Initial_Data,a,mask; + uint8_t i, pos=0,tmp, buffer[64], pos_final,shift; + //Add packet len + if(LT8910_Flags&_BV(LT8910_PACKET_LENGTH_EN)) + { + tmp=bit_reverse(len); + buffer[pos++]=tmp; + crc=crc16_update(crc,tmp); + } + //Add payload + for(i=0;i>8; + buffer[pos++]=crc; + } + //Shift everything to fit behind the trailer (4 to 18 bits) + shift=LT8910_buffer_overhead_bits&0x7; + pos_final=LT8910_buffer_overhead_bits/8; + mask=~(0xFF<<(8-shift)); + LT8910_buffer[pos_final+pos]=0xFF; + for(i=pos-1;i!=0xFF;i--) + { + a=buffer[i]<<(8-shift); + LT8910_buffer[pos_final+i]=(LT8910_buffer[pos_final+i]&mask>>8)|a>>8; + LT8910_buffer[pos_final+i+1]=(LT8910_buffer[pos_final+i+1]&mask)|a; + } + if(shift) + pos++; + //Send everything + NRF24L01_WritePayload(LT8910_buffer+LT8910_buffer_start,pos_final+pos-LT8910_buffer_start); +} +// End of LT8910 emulation diff --git a/Multiprotocol/SHENQI_nrf24l01.ino b/Multiprotocol/SHENQI_nrf24l01.ino new file mode 100644 index 0000000..18d5037 --- /dev/null +++ b/Multiprotocol/SHENQI_nrf24l01.ino @@ -0,0 +1,108 @@ +#if defined(SHENQI_NRF24L01_INO) + +#include "iface_nrf24l01.h" + +const uint8_t PROGMEM SHENQI_Freq[] = { + 50,50,20,60,30,40, + 10,30,40,20,60,10, + 50,20,50,40,10,60, + 30,30,60,10,40,50, + 20,10,60,20,50,30, + 40,40,30,50,20,60, + 10,10,20,30,40,50, + 60,60,50,40,30,20, + 10,60,10,50,30,40, + 20,10,40,30,60,20 }; + +void SHENQI_init() +{ + NRF24L01_Initialize(); + 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_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5 bytes rx/tx address + + LT8910_Config(4, 8, _BV(LT8910_CRC_ON)|_BV(LT8910_PACKET_LENGTH_EN), 0xAA); + LT8910_SetChannel(2); + LT8910_SetAddress((uint8_t *)"\x9A\x9A\x9A\x9A",4); + LT8910_SetTxRxMode(RX_EN); +} + +void SHENQI_send_packet() +{ + packet[0]=0x00; + if(packet_count==0) + { + uint8_t bind_addr[4]; + bind_addr[0]=0x9A; + bind_addr[1]=0x9A; + bind_addr[2]=rx_tx_addr[2]; + bind_addr[3]=rx_tx_addr[3]; + LT8910_SetAddress(bind_addr,4); + LT8910_SetChannel(2); + packet[1]=rx_tx_addr[1]; + packet[2]=rx_tx_addr[0]; + packet_period=2508; + } + else + { + LT8910_SetAddress(rx_tx_addr,4); + packet[1]=255-convert_channel_8b(RUDDER); + packet[2]=255-convert_channel_8b_scale(THROTTLE,0x60,0xA0); + uint8_t freq=pgm_read_byte_near(&SHENQI_Freq[hopping_frequency_no])+(rx_tx_addr[1]&0x0F); + LT8910_SetChannel(freq); + hopping_frequency_no++; + if(hopping_frequency_no==60) + hopping_frequency_no=0; + packet_period=1750; + } + // Send packet + 1 retransmit - not sure why but needed (not present on original TX...) + LT8910_WritePayload(packet,3); + while(NRF24L01_packet_ack()!=PKT_ACKED); + LT8910_WritePayload(packet,3); + + packet_count++; + if(packet_count==7) + { + packet_count=0; + packet_period=3000; + } + // Set power + NRF24L01_SetPower(); +} + +uint16_t SHENQI_callback() +{ + if(IS_BIND_DONE_on) + SHENQI_send_packet(); + else + { + if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR)) + { + if(LT8910_ReadPayload(packet, 3)) + { + BIND_DONE; + rx_tx_addr[3]=packet[1]; + rx_tx_addr[2]=packet[2]; + LT8910_SetTxRxMode(TX_EN); + packet_period=14000; + } + NRF24L01_FlushRx(); + } + } + return packet_period; +} + +uint16_t initSHENQI() +{ + BIND_IN_PROGRESS; // autobind protocol + SHENQI_init(); + hopping_frequency_no = 0; + packet_count=0; + packet_period=100; + return 1000; +} + +#endif \ No newline at end of file diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 090fe4e..46226bc 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -56,6 +56,7 @@ #define YD717_NRF24L01_INO #define MT99XX_NRF24L01_INO #define MJXQ_NRF24L01_INO + #define SHENQI_NRF24L01_INO #endif //Update this table to set which protocol and all associated settings are called for the corresponding dial number @@ -139,6 +140,8 @@ const PPM_Parameters PPM_prot[15]= { X600 X800 H26D + MODE_SHENQI + NONE RX_Num value between 0 and 15 diff --git a/Multiprotocol/multiprotocol.h b/Multiprotocol/multiprotocol.h index ec6e437..d5a51aa 100644 --- a/Multiprotocol/multiprotocol.h +++ b/Multiprotocol/multiprotocol.h @@ -44,7 +44,8 @@ enum PROTOCOLS MODE_FRSKYX = 15, // =>CC2500 MODE_ESKY = 16, // =>NRF24L01 MODE_MT99XX=17, // =>NRF24L01 - MODE_MJXQ=18 // =>NRF24L01 + MODE_MJXQ=18, // =>NRF24L01 + MODE_SHENQI=19 // =>NRF24L01 }; enum Flysky @@ -419,6 +420,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- ESky 16 MT99XX 17 MJXQ 18 + SHENQI 19 BindBit=> 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No From 35eedda352d9455700e00a54596ff40288da86f9 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 26 Feb 2016 19:32:11 +0100 Subject: [PATCH 067/293] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 93631f7..054833a 100644 --- a/README.md +++ b/README.md @@ -210,6 +210,7 @@ MJXQ| |X600 |X800 |H26D +Shenqi| Note: - The dial should be set to 0 for serial. Which means all protocol selection pins should be left unconnected. From 0a08b09d7059f79f4da192a9896e062f9ca7137f Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 26 Feb 2016 19:40:34 +0100 Subject: [PATCH 068/293] Update Protocols_Details.md --- Protocols_Details.md | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index ec49550..2596082 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -247,9 +247,18 @@ Models: MT99xx ###Sub_protocol H7 Models: Eachine H7, Cheerson CX023 ###Sub_protocol YZ -Models: Yi Zhan i6S +Model: Yi Zhan i6S Only one model can be flown at the same time since the ID is hardcoded. +##Shenqi +Autobind protocol +Model: Shenqiwei 1/20 Mini Motorcycle +CH1|CH2|CH3|CH4 +---|---|---|--- +||T|R + +Throttle +100%=full forward,0%=stop,-100%=full backward. + ##SLT Autobind protocol From 4f5d1ba26b3c09dd574f41b15d9578426b3b0ef2 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 3 Mar 2016 16:26:17 +0100 Subject: [PATCH 069/293] Correct serial init --- Multiprotocol/Multiprotocol.ino | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index f7393da..5dc6e62 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -138,6 +138,9 @@ void setup() Servo_data[THROTTLE]=PPM_MIN_100; memcpy((void *)PPM_data,Servo_data, sizeof(Servo_data)); + //Wait for every component to start + delay(100); + // Read status of bind button if( (PINB & _BV(5)) == 0x00 ) BIND_BUTTON_FLAG_on; // If bind button pressed save the status for protocol id reset under hubsan @@ -594,12 +597,13 @@ static void Mprotocol_serial_init() #include UBRR0H = UBRRH_VALUE; UBRR0L = UBRRL_VALUE; + UCSR0A = 0 ; // Clear X2 bit //Set frame format to 8 data bits, even parity, 2 stop bits - UCSR0C |= (1< Date: Thu, 3 Mar 2016 16:34:57 +0100 Subject: [PATCH 070/293] Add Arduino Mini has a supported platform. --- Multiprotocol/multiprotocol.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Multiprotocol/multiprotocol.h b/Multiprotocol/multiprotocol.h index d5a51aa..37a8e36 100644 --- a/Multiprotocol/multiprotocol.h +++ b/Multiprotocol/multiprotocol.h @@ -14,8 +14,8 @@ */ // Check selected board type -#ifndef ARDUINO_AVR_PRO - #error You must select the board type "Arduino Pro or Pro Mini" +#if not defined(ARDUINO_AVR_PRO) && not defined(ARDUINO_AVR_MINI) + #error You must select the board type "Arduino Pro or Pro Mini" or "Arduino Mini" #endif #if F_CPU != 16000000L || not defined(__AVR_ATmega328P__) #error You must select the processor type "ATmega328(5V, 16MHz)" From 5b44439dd2595db58a3cc1a23d4f8dda01b77469 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 3 Mar 2016 17:10:40 +0100 Subject: [PATCH 071/293] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 054833a..38fb112 100644 --- a/README.md +++ b/README.md @@ -233,7 +233,7 @@ You also need some [antennas](http://www.banggood.com/2_4GHz-3dBi-RP-SMA-Connect ###Board The main program is running on an ATMEGA328p running @16MHz and 3.3V. -An [Arduino pro mini 16Mhz/5V](http://www.banggood.com/Wholesale-New-Ver-Pro-Mini-ATMEGA328-328p-5V-16MHz-Arduino-Compatible-Nano-Size-p-68534.html) powered at 3.3V (yes it works) can be used to build your own Multimodule. +An [Arduino pro mini 16Mhz/5V](http://www.banggood.com/Wholesale-New-Ver-Pro-Mini-ATMEGA328-328p-5V-16MHz-Arduino-Compatible-Nano-Size-p-68534.html) powered at 3.3V (yes it works) can be used to build your own Multimodule. An Arduino Mini based on Atmega328p can also be used. Using stripboard: From 8cfa9a891dca00ef00d1da1812f48dd8c808696b Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 8 Mar 2016 22:18:44 +0100 Subject: [PATCH 072/293] Delete multiprotocol.h --- Multiprotocol/multiprotocol.h | 487 ---------------------------------- 1 file changed, 487 deletions(-) delete mode 100644 Multiprotocol/multiprotocol.h diff --git a/Multiprotocol/multiprotocol.h b/Multiprotocol/multiprotocol.h deleted file mode 100644 index 37a8e36..0000000 --- a/Multiprotocol/multiprotocol.h +++ /dev/null @@ -1,487 +0,0 @@ -/* - 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 . - */ - -// Check selected board type -#if not defined(ARDUINO_AVR_PRO) && not defined(ARDUINO_AVR_MINI) - #error You must select the board type "Arduino Pro or Pro Mini" or "Arduino Mini" -#endif -#if F_CPU != 16000000L || not defined(__AVR_ATmega328P__) - #error You must select the processor type "ATmega328(5V, 16MHz)" -#endif - -//****************** -// Protocols -//****************** -enum PROTOCOLS -{ - MODE_SERIAL = 0, // Serial commands - MODE_FLYSKY = 1, // =>A7105 - MODE_HUBSAN = 2, // =>A7105 - MODE_FRSKY = 3, // =>CC2500 - MODE_HISKY = 4, // =>NRF24L01 - MODE_V2X2 = 5, // =>NRF24L01 - MODE_DSM2 = 6, // =>CYRF6936 - MODE_DEVO =7, // =>CYRF6936 - MODE_YD717 = 8, // =>NRF24L01 - MODE_KN = 9, // =>NRF24L01 - MODE_SYMAX = 10, // =>NRF24L01 - MODE_SLT = 11, // =>NRF24L01 - MODE_CX10 = 12, // =>NRF24L01 - MODE_CG023 = 13, // =>NRF24L01 - MODE_BAYANG = 14, // =>NRF24L01 - MODE_FRSKYX = 15, // =>CC2500 - MODE_ESKY = 16, // =>NRF24L01 - MODE_MT99XX=17, // =>NRF24L01 - MODE_MJXQ=18, // =>NRF24L01 - MODE_SHENQI=19 // =>NRF24L01 -}; - -enum Flysky -{ - Flysky=0, - V9X9=1, - V6X6=2, - V912=3 -}; -enum Hisky -{ - Hisky=0, - HK310=1 -}; -enum DSM2{ - DSM2=0, - DSMX=1 -}; -enum YD717 -{ - YD717=0, - SKYWLKR=1, - SYMAX4=2, - XINXUN=3, - NIHUI=4 -}; -enum KN -{ - WLTOYS=0, - FEILUN=1 -}; -enum SYMAX -{ - SYMAX=0, - SYMAX5C=1 -}; -enum CX10 -{ - CX10_GREEN = 0, - CX10_BLUE=1, // also compatible with CX10-A, CX12 - DM007=2, - Q282=3, - JC3015_1=4, - JC3015_2=5, - MK33041=6, - Q242=7 -}; -enum CG023 -{ - CG023 = 0, - YD829 = 1, - H8_3D = 2 -}; -enum MT99XX -{ - MT99 = 0, - H7 = 1, - YZ = 2 -}; -enum MJXQ -{ - WLH08 = 0, - X600 = 1, - X800 = 2, - H26D = 3 -}; - -#define NONE 0 -#define P_HIGH 1 -#define P_LOW 0 -#define AUTOBIND 1 -#define NO_AUTOBIND 0 - -struct PPM_Parameters -{ - uint8_t protocol : 5; - uint8_t sub_proto : 3; - uint8_t rx_num : 4; - uint8_t power : 1; - uint8_t autobind : 1; - uint8_t option; -}; - -//******************* -//*** Pinouts *** -//******************* -//#define BIND_pin 13 -#define LED_pin 13 //Promini original led on B5 -// -#define PPM_pin 3 //PPM -D3 -#define SDI_pin 5 //SDIO-D5 -#define SCLK_pin 4 //SCK-D4 -#define CS_pin 2 //CS-D2 -#define SDO_pin 6 //D6 -// -#define CTRL1 1 //C1 (A1) -#define CTRL2 2 //C2 (A2) -// -#define CTRL1_on PORTC |= _BV(1) -#define CTRL1_off PORTC &= ~_BV(1) -// -#define CTRL2_on PORTC |= _BV(2) -#define CTRL2_off PORTC &= ~_BV(2) -// -#define CS_on PORTD |= _BV(2) //D2 -#define CS_off PORTD &= ~_BV(2) //D2 -// -#define SCK_on PORTD |= _BV(4) //D4 -#define SCK_off PORTD &= ~_BV(4) //D4 -// -#define SDI_on PORTD |= _BV(5) //D5 -#define SDI_off PORTD &= ~_BV(5) //D5 - -#define SDI_1 (PIND & (1< Reserved 0 - Flysky 1 - Hubsan 2 - Frsky 3 - Hisky 4 - V2x2 5 - DSM2 6 - Devo 7 - YD717 8 - KN 9 - SymaX 10 - SLT 11 - CX10 12 - CG023 13 - Bayang 14 - FrskyX 15 - ESky 16 - MT99XX 17 - MJXQ 18 - SHENQI 19 - BindBit=> 0x80 1=Bind/0=No - AutoBindBit=> 0x40 1=Yes /0=No - RangeCheck=> 0x20 1=Yes /0=No - Stream[2] = RxNum | Power | Type; - RxNum value is 0..15 (bits 0..3) - Type is 0..7 <<4 (bit 4..6) - sub_protocol==Flysky - Flysky 0 - V9x9 1 - V6x6 2 - V912 3 - sub_protocol==Hisky - Hisky 0 - HK310 1 - sub_protocol==DSM2 - DSM2 0 - DSMX 1 - sub_protocol==YD717 - YD717 0 - SKYWLKR 1 - SYMAX4 2 - XINXUN 3 - NIHUI 4 - sub_protocol==KN - WLTOYS 0 - FEILUN 1 - sub_protocol==SYMAX - SYMAX 0 - SYMAX5C 1 - sub_protocol==CX10 - CX10_GREEN 0 - CX10_BLUE 1 // also compatible with CX10-A, CX12 - DM007 2 - Q282 3 - JC3015_1 4 - JC3015_2 5 - MK33041 6 - Q242 7 - sub_protocol==CG023 - CG023 0 - YD829 1 - H8_3D 2 - sub_protocol==MT99XX - MT99 0 - H7 1 - YZ 2 - sub_protocol==MJXQ - WLH08 0 - X600 1 - X800 2 - H26D 3 - Power value => 0x80 0=High/1=Low - Stream[3] = option_protocol; - option_protocol value is -127..127 - Stream[4] to [25] = Channels - 16 Channels on 11 bits (0..2047) - 0 -125% - 204 -100% - 1024 0% - 1843 +100% - 2047 +125% - Channels bits are concatenated to fit in 22 bytes like in SBUS protocol -*/ - \ No newline at end of file From a025d028d4c359550758e1a0e5b3473ad6764e48 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 8 Mar 2016 22:20:49 +0100 Subject: [PATCH 073/293] Capital 'M' --- Multiprotocol/Multiprotocol.h | 487 ++++++++++++++++++++++++++++++++++ 1 file changed, 487 insertions(+) create mode 100644 Multiprotocol/Multiprotocol.h diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h new file mode 100644 index 0000000..37a8e36 --- /dev/null +++ b/Multiprotocol/Multiprotocol.h @@ -0,0 +1,487 @@ +/* + 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 . + */ + +// Check selected board type +#if not defined(ARDUINO_AVR_PRO) && not defined(ARDUINO_AVR_MINI) + #error You must select the board type "Arduino Pro or Pro Mini" or "Arduino Mini" +#endif +#if F_CPU != 16000000L || not defined(__AVR_ATmega328P__) + #error You must select the processor type "ATmega328(5V, 16MHz)" +#endif + +//****************** +// Protocols +//****************** +enum PROTOCOLS +{ + MODE_SERIAL = 0, // Serial commands + MODE_FLYSKY = 1, // =>A7105 + MODE_HUBSAN = 2, // =>A7105 + MODE_FRSKY = 3, // =>CC2500 + MODE_HISKY = 4, // =>NRF24L01 + MODE_V2X2 = 5, // =>NRF24L01 + MODE_DSM2 = 6, // =>CYRF6936 + MODE_DEVO =7, // =>CYRF6936 + MODE_YD717 = 8, // =>NRF24L01 + MODE_KN = 9, // =>NRF24L01 + MODE_SYMAX = 10, // =>NRF24L01 + MODE_SLT = 11, // =>NRF24L01 + MODE_CX10 = 12, // =>NRF24L01 + MODE_CG023 = 13, // =>NRF24L01 + MODE_BAYANG = 14, // =>NRF24L01 + MODE_FRSKYX = 15, // =>CC2500 + MODE_ESKY = 16, // =>NRF24L01 + MODE_MT99XX=17, // =>NRF24L01 + MODE_MJXQ=18, // =>NRF24L01 + MODE_SHENQI=19 // =>NRF24L01 +}; + +enum Flysky +{ + Flysky=0, + V9X9=1, + V6X6=2, + V912=3 +}; +enum Hisky +{ + Hisky=0, + HK310=1 +}; +enum DSM2{ + DSM2=0, + DSMX=1 +}; +enum YD717 +{ + YD717=0, + SKYWLKR=1, + SYMAX4=2, + XINXUN=3, + NIHUI=4 +}; +enum KN +{ + WLTOYS=0, + FEILUN=1 +}; +enum SYMAX +{ + SYMAX=0, + SYMAX5C=1 +}; +enum CX10 +{ + CX10_GREEN = 0, + CX10_BLUE=1, // also compatible with CX10-A, CX12 + DM007=2, + Q282=3, + JC3015_1=4, + JC3015_2=5, + MK33041=6, + Q242=7 +}; +enum CG023 +{ + CG023 = 0, + YD829 = 1, + H8_3D = 2 +}; +enum MT99XX +{ + MT99 = 0, + H7 = 1, + YZ = 2 +}; +enum MJXQ +{ + WLH08 = 0, + X600 = 1, + X800 = 2, + H26D = 3 +}; + +#define NONE 0 +#define P_HIGH 1 +#define P_LOW 0 +#define AUTOBIND 1 +#define NO_AUTOBIND 0 + +struct PPM_Parameters +{ + uint8_t protocol : 5; + uint8_t sub_proto : 3; + uint8_t rx_num : 4; + uint8_t power : 1; + uint8_t autobind : 1; + uint8_t option; +}; + +//******************* +//*** Pinouts *** +//******************* +//#define BIND_pin 13 +#define LED_pin 13 //Promini original led on B5 +// +#define PPM_pin 3 //PPM -D3 +#define SDI_pin 5 //SDIO-D5 +#define SCLK_pin 4 //SCK-D4 +#define CS_pin 2 //CS-D2 +#define SDO_pin 6 //D6 +// +#define CTRL1 1 //C1 (A1) +#define CTRL2 2 //C2 (A2) +// +#define CTRL1_on PORTC |= _BV(1) +#define CTRL1_off PORTC &= ~_BV(1) +// +#define CTRL2_on PORTC |= _BV(2) +#define CTRL2_off PORTC &= ~_BV(2) +// +#define CS_on PORTD |= _BV(2) //D2 +#define CS_off PORTD &= ~_BV(2) //D2 +// +#define SCK_on PORTD |= _BV(4) //D4 +#define SCK_off PORTD &= ~_BV(4) //D4 +// +#define SDI_on PORTD |= _BV(5) //D5 +#define SDI_off PORTD &= ~_BV(5) //D5 + +#define SDI_1 (PIND & (1< Reserved 0 + Flysky 1 + Hubsan 2 + Frsky 3 + Hisky 4 + V2x2 5 + DSM2 6 + Devo 7 + YD717 8 + KN 9 + SymaX 10 + SLT 11 + CX10 12 + CG023 13 + Bayang 14 + FrskyX 15 + ESky 16 + MT99XX 17 + MJXQ 18 + SHENQI 19 + BindBit=> 0x80 1=Bind/0=No + AutoBindBit=> 0x40 1=Yes /0=No + RangeCheck=> 0x20 1=Yes /0=No + Stream[2] = RxNum | Power | Type; + RxNum value is 0..15 (bits 0..3) + Type is 0..7 <<4 (bit 4..6) + sub_protocol==Flysky + Flysky 0 + V9x9 1 + V6x6 2 + V912 3 + sub_protocol==Hisky + Hisky 0 + HK310 1 + sub_protocol==DSM2 + DSM2 0 + DSMX 1 + sub_protocol==YD717 + YD717 0 + SKYWLKR 1 + SYMAX4 2 + XINXUN 3 + NIHUI 4 + sub_protocol==KN + WLTOYS 0 + FEILUN 1 + sub_protocol==SYMAX + SYMAX 0 + SYMAX5C 1 + sub_protocol==CX10 + CX10_GREEN 0 + CX10_BLUE 1 // also compatible with CX10-A, CX12 + DM007 2 + Q282 3 + JC3015_1 4 + JC3015_2 5 + MK33041 6 + Q242 7 + sub_protocol==CG023 + CG023 0 + YD829 1 + H8_3D 2 + sub_protocol==MT99XX + MT99 0 + H7 1 + YZ 2 + sub_protocol==MJXQ + WLH08 0 + X600 1 + X800 2 + H26D 3 + Power value => 0x80 0=High/1=Low + Stream[3] = option_protocol; + option_protocol value is -127..127 + Stream[4] to [25] = Channels + 16 Channels on 11 bits (0..2047) + 0 -125% + 204 -100% + 1024 0% + 1843 +100% + 2047 +125% + Channels bits are concatenated to fit in 22 bytes like in SBUS protocol +*/ + \ No newline at end of file From 799dce4b13018dd37a6489c310612fda47488151 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sun, 13 Mar 2016 09:29:25 +0100 Subject: [PATCH 074/293] DSM2: Option enables the selection of the number of channels - 0 : 4 channels @22ms - 1 : 5 channels @22ms - 2 : 6 channels @22ms - 3 : 7 channels @22ms - 4 : 4 channels @11ms - 5 : 5 channels @11ms - 6 : 6 channels @11ms - 7 : 7 channels @11ms - 8 : 8 channels @22ms - 9 : 9 channels @22ms - 10 : 10 channels @22ms - 11 : 11 channels @22ms - 12 : 12 channels @22ms --- Multiprotocol/DSM2_cyrf6936.ino | 75 +++++++++++++++++---------------- Multiprotocol/_Config.h | 4 +- Protocols_Details.md | 24 +++++++++-- README.md | 2 +- 4 files changed, 62 insertions(+), 43 deletions(-) diff --git a/Multiprotocol/DSM2_cyrf6936.ino b/Multiprotocol/DSM2_cyrf6936.ino index 0882d77..19a969e 100644 --- a/Multiprotocol/DSM2_cyrf6936.ino +++ b/Multiprotocol/DSM2_cyrf6936.ino @@ -17,7 +17,6 @@ #include "iface_cyrf6936.h" -#define DSM2_NUM_CHANNELS 7 #define RANDOM_CHANNELS 0 // disabled //#define RANDOM_CHANNELS 1 // enabled #define BIND_CHANNEL 0x0d //13 This can be any odd channel @@ -132,15 +131,11 @@ static void __attribute__((unused)) build_bind_packet() packet[8] = sum >> 8; packet[9] = sum & 0xff; packet[10] = 0x01; //??? - packet[11] = DSM2_NUM_CHANNELS; + packet[11] = option>3?option:option+4; if(sub_protocol==DSMX) //DSMX type packet[12] = 0xb2; // Telemetry off: packet[12] = num_channels < 8 && Model.proto_opts[PROTOOPTS_TELEMETRY] == TELEM_OFF ? 0xa2 : 0xb2; else -#if DSM2_NUM_CHANNELS < 8 - packet[12] = 0x01; -#else - packet[12] = 0x02; -#endif + packet[12] = option<8?0x01:0x02; packet[13] = 0x00; //??? for(i = 8; i < 14; i++) sum += packet[i]; @@ -166,34 +161,38 @@ static uint8_t __attribute__((unused)) PROTOCOL_SticksMoved(uint8_t init) static void __attribute__((unused)) build_data_packet(uint8_t upper)// { -#if DSM2_NUM_CHANNELS==4 - const uint8_t ch_map[] = {0, 1, 2, 3, 0xff, 0xff, 0xff}; //Guess -#elif DSM2_NUM_CHANNELS==5 - const uint8_t ch_map[] = {0, 1, 2, 3, 4, 0xff, 0xff}; //Guess -#elif DSM2_NUM_CHANNELS==6 - const uint8_t ch_map[] = {1, 5, 2, 3, 0, 4, 0xff}; //HP6DSM -#elif DSM2_NUM_CHANNELS==7 - const uint8_t ch_map[] = {1, 5, 2, 4, 3, 6, 0}; //DX6i -#elif DSM2_NUM_CHANNELS==8 - const uint8_t ch_map[] = {1, 5, 2, 3, 6, 0xff, 0xff, 4, 0, 7, 0xff, 0xff, 0xff, 0xff}; //DX8 -#elif DSM2_NUM_CHANNELS==9 - const uint8_t ch_map[] = {3, 2, 1, 5, 0, 4, 6, 7, 8, 0xff, 0xff, 0xff, 0xff, 0xff}; //DM9 -#elif DSM2_NUM_CHANNELS==10 - const uint8_t ch_map[] = {3, 2, 1, 5, 0, 4, 6, 7, 8, 9, 0xff, 0xff, 0xff, 0xff}; -#elif DSM2_NUM_CHANNELS==11 - const uint8_t ch_map[] = {3, 2, 1, 5, 0, 4, 6, 7, 8, 9, 10, 0xff, 0xff, 0xff}; -#elif DSM2_NUM_CHANNELS==12 - const uint8_t ch_map[] = {3, 2, 1, 5, 0, 4, 6, 7, 8, 9, 10, 11, 0xff, 0xff}; -#endif - uint8_t i; uint8_t bits; + + uint8_t ch_map[] = {3, 2, 1, 5, 0, 4, 6, 7, 8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //9 Channels - DM9 TX + switch(option>3?option:option+4) // Create channel map based on number of channels + { + case 12: + ch_map[11]=11; // 12 channels + case 11: + ch_map[10]=10; // 11 channels + case 10: + ch_map[9]=9; // 10 channels + break; + case 8: + memcpy(ch_map,"\x01\x05\x02\x03\x06\xFF\xFF\x04\x00\x07",10); // 8 channels - DX8 TX + break; + case 7: + memcpy(ch_map,"\x01\x05\x02\x04\x03\x06\x00",7); // 7 channels - DX6i TX + break; + case 6: + memcpy(ch_map,"\x01\x05\x02\x03\x00\x04\xFF",7); // 6 channels - HP6DSM TX + break; + case 4: + case 5: + memcpy(ch_map,"\x00\x01\x02\x03\xFF\xFF\xFF",7); // 4 channels - Guess + if(option&0x01) + ch_map[4]=4; // 5 channels - Guess + break; + } // if( binding && PROTOCOL_SticksMoved(0) ) - { - //BIND_DONE; binding = 0; - } if (sub_protocol==DSMX) { packet[0] = cyrfmfg_id[2]; @@ -463,12 +462,16 @@ uint16_t ReadDsm2() set_sop_data_crc(); if (cyrf_state == DSM2_CH2_CHECK_A) { - #if DSM2_NUM_CHANNELS < 8 - cyrf_state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper) - return 11000 - CH1_CH2_DELAY - WRITE_DELAY ; // Original is 22000 from deviation but it works better this way - #else - cyrf_state = DSM2_CH1_WRITE_B; // change from CH2_CHECK_A to CH1_WRITE_A (to transmit upper) - #endif + if(option < 8) + { + cyrf_state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper) + if(option>3) + return 11000 - CH1_CH2_DELAY - WRITE_DELAY ; // force 11ms if option>3 ie 4,5,6,7 channels @11ms + else + return 22000 - CH1_CH2_DELAY - WRITE_DELAY ; // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms + } + else + cyrf_state = DSM2_CH1_WRITE_B; // change from CH2_CHECK_A to CH1_WRITE_A (to transmit upper) } else cyrf_state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_B to CH1_WRITE_A (upper already transmitted so transmit lower) diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 46226bc..3d4ba8b 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -64,10 +64,10 @@ const PPM_Parameters PPM_prot[15]= { // Dial Protocol Sub protocol RX_Num Power Auto Bind Option /* 1 */ {MODE_FLYSKY, Flysky , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 2 */ {MODE_HUBSAN, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, -/* 3 */ {MODE_FRSKY , 0 , 0 , P_HIGH , NO_AUTOBIND , 0xD7 }, +/* 3 */ {MODE_FRSKY , 0 , 0 , P_HIGH , NO_AUTOBIND , 0xD7 }, // D7 fine tuning /* 4 */ {MODE_HISKY , Hisky , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 5 */ {MODE_V2X2 , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, -/* 6 */ {MODE_DSM2 , DSM2 , 0 , P_HIGH , NO_AUTOBIND , 0 }, +/* 6 */ {MODE_DSM2 , DSM2 , 0 , P_HIGH , NO_AUTOBIND , 6 }, // 6 channels @ 11ms /* 7 */ {MODE_DEVO , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 8 */ {MODE_YD717 , YD717 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 9 */ {MODE_KN , WLTOYS , 0 , P_HIGH , NO_AUTOBIND , 0 }, diff --git a/Protocols_Details.md b/Protocols_Details.md index 2596082..5541503 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -83,11 +83,27 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ##DSM2 Extended limits supported -7 channels @11ms +option=number of channels and frame rate: + - 0 : 4 channels @22ms + - 1 : 5 channels @22ms + - 2 : 6 channels @22ms + - 3 : 7 channels @22ms -CH1|CH2|CH3|CH4|CH5|CH6|CH7 ----|---|---|---|---|---|--- -A|E|T|R|CH5|CH6|CH7 + - 4 : 4 channels @11ms + - 5 : 5 channels @11ms + - 6 : 6 channels @11ms + - 7 : 7 channels @11ms + + - 8 : 8 channels @22ms + - 9 : 9 channels @22ms + - 10 : 10 channels @22ms + - 11 : 11 channels @22ms + - 12 : 12 channels @22ms +6 is usually giving the best results with most of the RX. + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 +---|---|---|---|---|---|---|---|---|----|----|---- +A|E|T|R|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 ###Sub_protocol DSMX Same as above diff --git a/README.md b/README.md index 38fb112..e490efc 100644 --- a/README.md +++ b/README.md @@ -124,7 +124,7 @@ Dial|Protocol|Sub_protocol|RX Num|Power|Auto Bind|Option|RF Module 3|FRSKY|-|0|High|No|-41|CC2500 4|HISKY|Hisky|0|High|No|0|NRF24L01 5|V2X2|-|0|High|No|0|NRF24L01 -6|DSM2|DSM2|0|High|No|0|CYRF6936 +6|DSM2|DSM2|0|High|No|6|CYRF6936 7|DEVO|-|0|High|No|0|CYRF6936 8|YD717|YD717|0|High|No|0|NRF24L01 9|KN|WLTOYS|0|High|No|0|NRF24L01 From f4d6f88e5c28f20501b0b761ab88920fa61d24f3 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sun, 13 Mar 2016 09:30:30 +0100 Subject: [PATCH 075/293] Update Protocols_Details.md --- Protocols_Details.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index 5541503..da11f9f 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -99,6 +99,7 @@ option=number of channels and frame rate: - 10 : 10 channels @22ms - 11 : 11 channels @22ms - 12 : 12 channels @22ms + 6 is usually giving the best results with most of the RX. CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 From d90e698a1576922f8243fdc3eda375269302da72 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sun, 13 Mar 2016 09:39:34 +0100 Subject: [PATCH 076/293] Update Protocols_Details.md --- Protocols_Details.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index da11f9f..c4ae3d6 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -269,10 +269,12 @@ Only one model can be flown at the same time since the ID is hardcoded. ##Shenqi Autobind protocol + Model: Shenqiwei 1/20 Mini Motorcycle + CH1|CH2|CH3|CH4 ---|---|---|--- -||T|R + | |T|R Throttle +100%=full forward,0%=stop,-100%=full backward. From def28df4dd8c1e5a719b0fa7eb5ddb60865e41d5 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 15 Mar 2016 13:36:51 +0100 Subject: [PATCH 077/293] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index e490efc..988bbdb 100644 --- a/README.md +++ b/README.md @@ -92,9 +92,11 @@ Once the TX is telemetry enabled, it just needs to be configured on the model (s ##Protocols ###TX ID -The multiprotocol TX module is using a 32bits ID generated randomly at first power up. This global ID is used by all protocols. +The multiprotocol TX module is using a 32bits ID generated randomly at first power up. This global ID is used by nearly all protocols. There are little chances to get a duplicated ID. +For DSM2/X and Devo the CYRF6936 unique manufacturer ID is used. + It's possible to generate a new ID using bind button on the Hubsan protocol during power up. ###Bind From 3d287a28273b5869d79ce25a01a3a87817a03699 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 18 Mar 2016 17:11:27 +0100 Subject: [PATCH 078/293] New FY326 protocol --- Multiprotocol/FY326_nrf24l01.ino | 167 +++++++++++++++++++++++++++++++ Multiprotocol/Multiprotocol.h | 7 +- Multiprotocol/Multiprotocol.ino | 8 +- Multiprotocol/_Config.h | 3 + 4 files changed, 182 insertions(+), 3 deletions(-) create mode 100644 Multiprotocol/FY326_nrf24l01.ino diff --git a/Multiprotocol/FY326_nrf24l01.ino b/Multiprotocol/FY326_nrf24l01.ino new file mode 100644 index 0000000..ccd640f --- /dev/null +++ b/Multiprotocol/FY326_nrf24l01.ino @@ -0,0 +1,167 @@ +/* + 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 . + */ +// Last sync with hexfet new_protocols/fy326_nrf24l01.c dated 2015-07-29 + +#if defined(FY326_NRF24L01_INO) + +#include "iface_nrf24l01.h" + +#define FY326_INITIAL_WAIT 500 +#define FY326_PACKET_PERIOD 1500 +#define FY326_PACKET_CHKTIME 300 +#define FY326_PACKET_SIZE 15 +#define FY326_BIND_COUNT 16 +#define FY326_RF_BIND_CHANNEL 0x17 +#define FY326_NUM_RF_CHANNELS 5 + +enum { + FY326_BIND1=0, + FY326_BIND2, + FY326_DATA +}; + +#define rxid channel + +#define CHAN_TO_TRIM(chanval) ((chanval/10)-10) +static void __attribute__((unused)) FY326_send_packet(uint8_t bind) +{ + packet[0] = rx_tx_addr[3]; + if(bind) + packet[1] = 0x55; + else + packet[1] = GET_FLAG(Servo_AUX3, 0x80) // Headless + | GET_FLAG(Servo_AUX2, 0x40) // RTH + | GET_FLAG(Servo_AUX1, 0x02) // Flip + | GET_FLAG(Servo_AUX5, 0x01) // Calibrate + | GET_FLAG(Servo_AUX4, 0x04); // Expert + packet[2] = 200 - convert_channel_8b_scale(AILERON, 0, 200); // aileron + packet[3] = convert_channel_8b_scale(ELEVATOR, 0, 200); // elevator + packet[4] = 200 - convert_channel_8b_scale(RUDDER, 0, 200); // rudder + packet[5] = convert_channel_8b_scale(THROTTLE, 0, 200); // throttle + packet[6] = rx_tx_addr[0]; + packet[7] = rx_tx_addr[1]; + packet[8] = rx_tx_addr[2]; + packet[9] = CHAN_TO_TRIM(packet[2]); // aileron_trim; + packet[10] = CHAN_TO_TRIM(packet[3]); // elevator_trim; + packet[11] = CHAN_TO_TRIM(packet[4]); // rudder_trim; + packet[12] = 0; // throttle_trim; + packet[13] = rxid; + packet[14] = rx_tx_addr[4]; + + if (bind) + NRF24L01_WriteReg(NRF24L01_05_RF_CH, FY326_RF_BIND_CHANNEL); + else + { + NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]); + hopping_frequency_no %= FY326_NUM_RF_CHANNELS; + } + + // clear packet status bits and TX FIFO + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); + NRF24L01_FlushTx(); + + NRF24L01_WritePayload(packet, FY326_PACKET_SIZE); + + NRF24L01_SetPower(); // Set tx_power +} + +static void __attribute__((unused)) FY326_init() +{ + NRF24L01_Initialize(); + NRF24L01_SetTxRxMode(TX_EN); + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x01); // Three-byte rx/tx address + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x15\x59\x23\xc6\x29", 5); + NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t *)"\x15\x59\x23\xc6\x29", 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 Acknowledgement on all data pipes + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only + NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, FY326_PACKET_SIZE); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, FY326_RF_BIND_CHANNEL); + NRF24L01_SetBitrate(NRF24L01_BR_250K); + NRF24L01_SetPower(); + + NRF24L01_Activate(0x73); + NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3f); + NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07); + NRF24L01_Activate(0x73); +} + +uint16_t FY326_callback() +{ + switch (phase) + { + case FY326_BIND1: + if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR)) + { // RX fifo data ready + NRF24L01_ReadPayload(packet, FY326_PACKET_SIZE); + rxid = packet[13]; + rx_tx_addr[0] = 0xAA; + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_SetTxRxMode(TX_EN); + BIND_DONE; + phase = FY326_DATA; + } + else + if (bind_counter-- == 0) + { + bind_counter = FY326_BIND_COUNT; + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_SetTxRxMode(TX_EN); + FY326_send_packet(1); + phase = FY326_BIND2; + return FY326_PACKET_CHKTIME; + } + break; + case FY326_BIND2: + if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_TX_DS)) + { // TX data sent -> switch to RX mode + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_FlushRx(); + NRF24L01_SetTxRxMode(RX_EN); + phase = FY326_BIND1; + } + else + return FY326_PACKET_CHKTIME; + break; + case FY326_DATA: + FY326_send_packet(0); + break; + } + return FY326_PACKET_PERIOD; +} + +static void __attribute__((unused)) FY326_initialize_txid() +{ + hopping_frequency[0] = (rx_tx_addr[0]&0x0f); + hopping_frequency[1] = 0x10 + (rx_tx_addr[0] >> 4); + hopping_frequency[2] = 0x20 + (rx_tx_addr[1]&0x0f); + hopping_frequency[3] = 0x30 + (rx_tx_addr[1] >> 4); + hopping_frequency[4] = 0x40 + (rx_tx_addr[2] >> 4); +} + +uint16_t initFY326(void) +{ + BIND_IN_PROGRESS; // autobind protocol + rxid = 0xAA; + bind_counter = 0; + FY326_initialize_txid(); + FY326_init(); + phase=FY326_BIND1; + return FY326_INITIAL_WAIT; +} + +#endif diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 37a8e36..41d3ac9 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -45,7 +45,8 @@ enum PROTOCOLS MODE_ESKY = 16, // =>NRF24L01 MODE_MT99XX=17, // =>NRF24L01 MODE_MJXQ=18, // =>NRF24L01 - MODE_SHENQI=19 // =>NRF24L01 + MODE_SHENQI=19, // =>NRF24L01 + MODE_FY326=20 // =>NRF24L01 }; enum Flysky @@ -305,7 +306,8 @@ enum NRF_POWER // CC2500 power enum CC2500_POWER { - CC2500_POWER_0 = 0xC5, // -12dbm + CC2500_POWER_0 = 0x50, // -30dbm + //CC2500_POWER_0 = 0xC5, // -12dbm CC2500_POWER_1 = 0x97, // -10dbm CC2500_POWER_2 = 0x6E, // -8dbm CC2500_POWER_3 = 0x7F, // -6dbm @@ -421,6 +423,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- MT99XX 17 MJXQ 18 SHENQI 19 + FY326 20 BindBit=> 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 5dc6e62..cd62a62 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -440,6 +440,12 @@ static void protocol_init() next_callback=initSHENQI(); remote_callback = SHENQI_callback; break; +#endif +#if defined(FY326_NRF24L01_INO) + case MODE_FY326: + next_callback=initFY326(); + remote_callback = FY326_callback; + break; #endif } @@ -522,7 +528,7 @@ static void module_reset() case MODE_DEVO: CYRF_Reset(); break; - default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY, MODE_MT99XX, MODE_MJXQ, MODE_SHENQI + default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY, MODE_MT99XX, MODE_MJXQ, MODE_SHENQI, MODE_FY326 NRF24L01_Reset(); break; } diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 3d4ba8b..fb40ddd 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -57,6 +57,7 @@ #define MT99XX_NRF24L01_INO #define MJXQ_NRF24L01_INO #define SHENQI_NRF24L01_INO + #define FY326_NRF24L01_INO #endif //Update this table to set which protocol and all associated settings are called for the corresponding dial number @@ -142,6 +143,8 @@ const PPM_Parameters PPM_prot[15]= { H26D MODE_SHENQI NONE + MODE_FY326 + NONE RX_Num value between 0 and 15 From 24747355ce5cab5640ef043f8d07b949c0695d0c Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 18 Mar 2016 17:13:20 +0100 Subject: [PATCH 079/293] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 988bbdb..53826e7 100644 --- a/README.md +++ b/README.md @@ -213,6 +213,7 @@ MJXQ| |X800 |H26D Shenqi| +FY326| Note: - The dial should be set to 0 for serial. Which means all protocol selection pins should be left unconnected. From 59f307bdb3251f445aa5307cb7d1c99a6e02c0ae Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 18 Mar 2016 17:16:39 +0100 Subject: [PATCH 080/293] Update Protocols_Details.md --- Protocols_Details.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index c4ae3d6..f953365 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -215,6 +215,12 @@ CH1|CH2|CH3|CH4|CH5|CH6 ---|---|---|---|---|--- A|E|T|R|GYRO|PITCH +##FY326 + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP|RTH|HEADLESS|EXPERT|CALIBRATE + ##HISKY CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- From 6199dec82ffc9b791ece74e709eb5650b2ba82df Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 18 Mar 2016 17:20:15 +0100 Subject: [PATCH 081/293] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 53826e7..5dcd06f 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Settings per selection are located in _Config.h: - Autobind: Yes or No. At the model selection (or power applied to the TX) a bind sequence will be initiated ###Using a serial output -The multiprotocol TX module takes full advantage of being used on a Turnigy 9X, 9XR, 9XR Pro, Taranis, 9Xtreme, AR9X, ... running [er9x or ersky9X](https://github.com/MikeBland/mbtx/tree/next). (A version for OpenTX is being looked at) +The multiprotocol TX module takes full advantage of being used on a Turnigy 9X, 9XR, 9XR Pro, Taranis, 9Xtreme, AR9X, ... running [er9x or ersky9X](https://github.com/MikeBland/mbtx/tree/next). An OpenTX version for Taranis is being developped and available has a beta version for now. This enables full integration using the radio GUI to setup models with all the available protocols options. From 1ee646e1ceaed1791d22accb403fe37b01eb3c65 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 6 Apr 2016 12:32:14 +0200 Subject: [PATCH 082/293] Update README.md --- README.md | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index 5dcd06f..666fc06 100644 --- a/README.md +++ b/README.md @@ -66,24 +66,27 @@ Notes: ###Telemetry -There are 3 protocols supporting telemetry: Hubsan, FrSky and FrSkyX. +There are 4 protocols supporting telemetry: Hubsan, DSM, FrSky and FrSkyX. Hubsan displays the battery voltage and TX RSSI. +DSM displays TX RSSI and full telemetry. + FrSky displays full telemetry (A0, A1, RX RSSI, TX RSSI and Hub). -FrSkyX displays basic telemetry (A1, A2 and RX RSSI). +FrSkyX displays full telemetry (A1, A2, RX RSSI, TX RSSI and Hub). ### If used in PPM mode -Telemetry is available as a serial 9600 8 n 1 output on the TX pin of the Atmega328p using the FRSky hub format. +Telemetry is available as a serial 9600 8 n 1 output on the TX pin of the Atmega328p using the FRSky hub format for Hubsan, FrSky, FrSkyX and DSM format for DSM2/X. You can connect it to your TX if it is telemetry enabled or use a bluetooth adapter (HC05/HC06) along with an app on your phone/tablet ([app example](https://play.google.com/store/apps/details?id=biz.onomato.frskydash&hl=fr)) to display telemetry information and setup alerts. ### If used in Serial mode - Telemetry is built in for er9x and ersky9x TXs. +Telemetry is built in for er9x and ersky9x TXs. To enable telemetry on a Turnigy 9X or 9XR you need to modify your TX following one of the Frsky mod like this [one](http://blog.oscarliang.net/turnigy-9x-advance-mod/). +Note: DSM telemetry is not available on er9x due to alack of flash space. Enabling telemetry on a 9XR PRO and may be other TXs does not require any hardware modifications. The additional required serial pin is already available on the TX back module pins. @@ -158,6 +161,7 @@ Protocol|Sub_protocol --------|------------ FrSky| FrSkyX| +SFHSS| #####CYRF6936 RF module Protocol|Sub_protocol @@ -226,7 +230,7 @@ Note: ###RF modules Up to 4 RF modules can be installed: - [A7105](http://www.banggood.com/XL7105-D03-A7105-Modification-Module-Support-Deviation-Galee-Flysky-p-922603.html) for Flysky, Hubsan -- [CC2500](http://www.banggood.com/CC2500-PA-LNA-Romote-Wireless-Module-CC2500-SI4432-NRF24L01-p-922595.html) for Frsky +- [CC2500](http://www.banggood.com/CC2500-PA-LNA-Romote-Wireless-Module-CC2500-SI4432-NRF24L01-p-922595.html) for FrSky, FrSkyX and SFHSS - [CYRF6936](http://www.ehirobo.com/walkera-wk-devo-s-mod-devo-8-or-12-to-devo-8s-or-12s-upgrade-module.html) for DSM2, DSMX, DEVO, Walkera - [NRF24L01](http://www.banggood.com/2_4G-NRF24L01-PA-LNA-Wireless-Module-1632mm-Without-Antenna-p-922601.html) for Hisky, V2x2, CX-10, SYMAX and plenty other protocols From cee78b4ae3127b0d0eae3ada48bbeb4731486a62 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 6 Apr 2016 12:33:43 +0200 Subject: [PATCH 083/293] Update README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 666fc06..20c873f 100644 --- a/README.md +++ b/README.md @@ -161,6 +161,8 @@ Protocol|Sub_protocol --------|------------ FrSky| FrSkyX| + |CH_16 + |CH_8 SFHSS| #####CYRF6936 RF module From 6c3535951fca694b6c86d3bd8286b1ca50707abd Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 6 Apr 2016 12:44:04 +0200 Subject: [PATCH 084/293] Added SFHSS, DSM telemetry, FrSkyX telemetry and sub_protocols --- Protocols_Details.md | 19 ++++++++++++++++++- 1 file changed, 18 insertions(+), 1 deletion(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index f953365..e6fa761 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -62,14 +62,29 @@ Models: FrSky receivers X4R, X6R and X8R. Extended limits supported -Telemetry enabled for A1 (RxBatt), A2, RSSI +Telemetry enabled for A1 (RxBatt), A2, RSSI, TSSI and Hub Option=fine frequency tuning, usually 0 or -41 based on the manufacturer boards +###Sub_protocol CH_16 CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16 ---|---|---|---|---|---|---|---|---|----|----|----|----|----|----|---- CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16 +###Sub_protocol CH_8 +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +---|---|---|---|---|---|---|--- +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 + +##SFHSS +Models: Futaba RXs and XK models. + +Option=fine frequency tuning, usually 0 or -41 based on the manufacturer boards + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +---|---|---|---|---|---|---|--- +A|E|T|R|CH5|CH6|CH7|CH8 + *** #CYRF6936 RF Module @@ -83,6 +98,8 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ##DSM2 Extended limits supported +Telemetry enabled for TSSI and plugins + option=number of channels and frame rate: - 0 : 4 channels @22ms - 1 : 5 channels @22ms From d938f2ea5055e556ab7b88983269c95fe3bb5893 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 6 Apr 2016 12:57:42 +0200 Subject: [PATCH 085/293] Multi core fixes, DSM2/X fixes and telemetry, SFHSS addition, Flysky fixes, FrSkyX full telemetry and sub protocols Many things since last commit... --- Multiprotocol/CC2500_SPI.ino | 62 +-- Multiprotocol/CYRF6936_SPI.ino | 27 +- Multiprotocol/DSM2_cyrf6936.ino | 159 ++++-- Multiprotocol/FlySky_a7105.ino | 57 ++- Multiprotocol/FrSkyX_cc2500.ino | 566 +++++++++++----------- Multiprotocol/FrSky_cc2500.ino | 48 +- Multiprotocol/Makefile.xmega | 624 ++++++++++++++++++++++++ Multiprotocol/Multiprotocol.cpp.xmega | 476 ++++++++++++++++++ Multiprotocol/Multiprotocol.h | 91 +++- Multiprotocol/Multiprotocol.ino | 246 ++++++++-- Multiprotocol/SFHSS_cc2500.ino | 265 ++++++++++ Multiprotocol/Telemetry.ino | 664 +++++++++++++++----------- Multiprotocol/WMath.cpp.xmega | 60 +++ Multiprotocol/_Config.h | 6 +- 14 files changed, 2608 insertions(+), 743 deletions(-) create mode 100644 Multiprotocol/Makefile.xmega create mode 100644 Multiprotocol/Multiprotocol.cpp.xmega create mode 100644 Multiprotocol/SFHSS_cc2500.ino create mode 100644 Multiprotocol/WMath.cpp.xmega diff --git a/Multiprotocol/CC2500_SPI.ino b/Multiprotocol/CC2500_SPI.ino index afcd8bb..34f1b73 100644 --- a/Multiprotocol/CC2500_SPI.ino +++ b/Multiprotocol/CC2500_SPI.ino @@ -19,18 +19,18 @@ //------------------------------- #include "iface_cc2500.h" -void cc2500_readFifo(uint8_t *dpbuffer, uint8_t len) +void CC2500_ReadData(uint8_t *dpbuffer, uint8_t len) { - ReadRegisterMulti(CC2500_3F_RXFIFO | CC2500_READ_BURST, dpbuffer, len); + CC2500_ReadRegisterMulti(CC2500_3F_RXFIFO | CC2500_READ_BURST, dpbuffer, len); } //---------------------- -static void ReadRegisterMulti(uint8_t address, uint8_t data[], uint8_t length) +static void CC2500_ReadRegisterMulti(uint8_t address, uint8_t data[], uint8_t length) { CC25_CSN_off; - cc2500_spi_write(address); + CC2500_SPI_Write(address); for(uint8_t i = 0; i < length; i++) - data[i] = cc2500_spi_read(); + data[i] = CC2500_SPI_Read(); CC25_CSN_on; } @@ -39,21 +39,21 @@ static void ReadRegisterMulti(uint8_t address, uint8_t data[], uint8_t length) static void CC2500_WriteRegisterMulti(uint8_t address, const uint8_t data[], uint8_t length) { CC25_CSN_off; - cc2500_spi_write(CC2500_WRITE_BURST | address); + CC2500_SPI_Write(CC2500_WRITE_BURST | address); for(uint8_t i = 0; i < length; i++) - cc2500_spi_write(data[i]); + CC2500_SPI_Write(data[i]); CC25_CSN_on; } -void cc2500_writeFifo(uint8_t *dpbuffer, uint8_t len) +void CC2500_WriteData(uint8_t *dpbuffer, uint8_t len) { - cc2500_strobe(CC2500_SFTX);//0x3B + CC2500_Strobe(CC2500_SFTX);//0x3B CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, dpbuffer, len); - cc2500_strobe(CC2500_STX);//0x35 + CC2500_Strobe(CC2500_STX);//0x35 } //-------------------------------------- -static void cc2500_spi_write(uint8_t command) { +static void CC2500_SPI_Write(uint8_t command) { uint8_t n=8; SCK_off;//SCK start low @@ -73,15 +73,15 @@ static void cc2500_spi_write(uint8_t command) { } //---------------------------- -void cc2500_writeReg(uint8_t address, uint8_t data) {//same as 7105 +void CC2500_WriteReg(uint8_t address, uint8_t data) {//same as 7105 CC25_CSN_off; - cc2500_spi_write(address); + CC2500_SPI_Write(address); NOP(); - cc2500_spi_write(data); + CC2500_SPI_Write(data); CC25_CSN_on; } -static uint8_t cc2500_spi_read(void) +static uint8_t CC2500_SPI_Read(void) { uint8_t result; uint8_t i; @@ -101,21 +101,21 @@ static uint8_t cc2500_spi_read(void) } //-------------------------------------------- -static uint8_t cc2500_readReg(uint8_t address) +static uint8_t CC2500_ReadReg(uint8_t address) { uint8_t result; CC25_CSN_off; address |=0x80; //bit 7 =1 for reading - cc2500_spi_write(address); - result = cc2500_spi_read(); + CC2500_SPI_Write(address); + result = CC2500_SPI_Read(); CC25_CSN_on; return(result); } //------------------------ -void cc2500_strobe(uint8_t address) +void CC2500_Strobe(uint8_t address) { CC25_CSN_off; - cc2500_spi_write(address); + CC2500_SPI_Write(address); CC25_CSN_on; } //------------------------ @@ -128,16 +128,16 @@ void cc2500_strobe(uint8_t address) _delay_us(30); CC25_CSN_on; _delay_us(45); - cc2500_strobe(CC2500_SRES); + CC2500_Strobe(CC2500_SRES); _delay_ms(100); } */ uint8_t CC2500_Reset() { - cc2500_strobe(CC2500_SRES); + CC2500_Strobe(CC2500_SRES); _delay_us(1000); CC2500_SetTxRxMode(TXRX_OFF); - return cc2500_readReg(CC2500_0E_FREQ1) == 0xC4;//check if reset + return CC2500_ReadReg(CC2500_0E_FREQ1) == 0xC4;//check if reset } /* static void CC2500_SetPower_Value(uint8_t power) @@ -154,7 +154,7 @@ static void CC2500_SetPower_Value(uint8_t power) }; if (power > 7) power = 7; - cc2500_writeReg(CC2500_3E_PATABLE, patable[power]); + CC2500_WriteReg(CC2500_3E_PATABLE, patable[power]); } */ void CC2500_SetPower() @@ -164,25 +164,25 @@ void CC2500_SetPower() power=IS_POWER_FLAG_on?CC2500_HIGH_POWER:CC2500_LOW_POWER; if(IS_RANGE_FLAG_on) power=CC2500_RANGE_POWER; - cc2500_writeReg(CC2500_3E_PATABLE, power); + CC2500_WriteReg(CC2500_3E_PATABLE, power); } void CC2500_SetTxRxMode(uint8_t mode) { if(mode == TX_EN) {//from deviation firmware - cc2500_writeReg(CC2500_02_IOCFG0, 0x2F | 0x40); - cc2500_writeReg(CC2500_00_IOCFG2, 0x2F); + CC2500_WriteReg(CC2500_02_IOCFG0, 0x2F | 0x40); + CC2500_WriteReg(CC2500_00_IOCFG2, 0x2F); } else if (mode == RX_EN) { - cc2500_writeReg(CC2500_02_IOCFG0, 0x2F); - cc2500_writeReg(CC2500_00_IOCFG2, 0x2F | 0x40); + CC2500_WriteReg(CC2500_02_IOCFG0, 0x2F); + CC2500_WriteReg(CC2500_00_IOCFG2, 0x2F | 0x40); } else { - cc2500_writeReg(CC2500_02_IOCFG0, 0x2F); - cc2500_writeReg(CC2500_00_IOCFG2, 0x2F); + CC2500_WriteReg(CC2500_02_IOCFG0, 0x2F); + CC2500_WriteReg(CC2500_00_IOCFG2, 0x2F); } } diff --git a/Multiprotocol/CYRF6936_SPI.ino b/Multiprotocol/CYRF6936_SPI.ino index 9880233..bb4cc23 100644 --- a/Multiprotocol/CYRF6936_SPI.ino +++ b/Multiprotocol/CYRF6936_SPI.ino @@ -14,20 +14,32 @@ */ #include "iface_cyrf6936.h" +#ifdef XMEGA +#define XNOP() NOP() +#else +#define XNOP() +#endif + static void cyrf_spi_write(uint8_t command) { uint8_t n=8; SCK_off;//SCK start low + XNOP() ; SDI_off; + XNOP() ; while(n--) { if(command&0x80) SDI_on; else SDI_off; + XNOP() ; SCK_on; NOP(); + XNOP() ; + XNOP() ; SCK_off; command = command << 1; + XNOP() ; } SDI_on; } @@ -39,13 +51,16 @@ static uint8_t cyrf_spi_read() result=0; for(i=0;i<8;i++) { + result<<=1; if(SDO_1) /// - result=(result<<1)|0x01; - else - result=result<<1; + result|=0x01; SCK_on; + XNOP() ; + XNOP() ; NOP(); SCK_off; + XNOP() ; + XNOP() ; NOP(); } return result; @@ -215,11 +230,11 @@ static void CYRF_StartReceive() CYRF_ReadRegisterMulti(CYRF_21_RX_BUFFER, dpbuffer, 0x10); } */ -/*static void CYRF_ReadDataPacketLen(uint8_t dpbuffer[], uint8_t length) +void CYRF_ReadDataPacketLen(uint8_t dpbuffer[], uint8_t length) { - ReadRegisterMulti(CYRF_21_RX_BUFFER, dpbuffer, length); + CYRF_ReadRegisterMulti(CYRF_21_RX_BUFFER, dpbuffer, length); } -*/ + static void CYRF_WriteDataPacketLen(const uint8_t dpbuffer[], uint8_t len) { CYRF_WriteRegister(CYRF_01_TX_LENGTH, len); diff --git a/Multiprotocol/DSM2_cyrf6936.ino b/Multiprotocol/DSM2_cyrf6936.ino index 19a969e..9a2b018 100644 --- a/Multiprotocol/DSM2_cyrf6936.ino +++ b/Multiprotocol/DSM2_cyrf6936.ino @@ -20,7 +20,6 @@ #define RANDOM_CHANNELS 0 // disabled //#define RANDOM_CHANNELS 1 // enabled #define BIND_CHANNEL 0x0d //13 This can be any odd channel -#define NUM_WAIT_LOOPS (100 / 5) //each loop is ~5us. Do not wait more than 100us //During binding we will send BIND_COUNT/2 packets //One packet each 10msec @@ -107,21 +106,19 @@ static void __attribute__((unused)) read_code(uint8_t *buf, uint8_t row, uint8_t } // -uint8_t chidx; uint8_t sop_col; uint8_t data_col; uint16_t cyrf_state; -uint8_t crcidx; uint8_t binding; static void __attribute__((unused)) build_bind_packet() { uint8_t i; uint16_t sum = 384 - 0x10;// - packet[0] = crc >> 8; - packet[1] = crc & 0xff; + packet[0] = 0xff ^ cyrfmfg_id[0]; + packet[1] = 0xff ^ cyrfmfg_id[1]; packet[2] = 0xff ^ cyrfmfg_id[2]; - packet[3] = (0xff ^ cyrfmfg_id[3]) + RX_num; + packet[3] = 0xff ^ cyrfmfg_id[3]; packet[4] = packet[0]; packet[5] = packet[1]; packet[6] = packet[2]; @@ -133,7 +130,11 @@ static void __attribute__((unused)) build_bind_packet() packet[10] = 0x01; //??? packet[11] = option>3?option:option+4; if(sub_protocol==DSMX) //DSMX type - packet[12] = 0xb2; // Telemetry off: packet[12] = num_channels < 8 && Model.proto_opts[PROTOOPTS_TELEMETRY] == TELEM_OFF ? 0xa2 : 0xb2; +#if defined DSM_TELEMETRY + packet[12] = 0xb2; // Telemetry on +#else + packet[12] = option<8? 0xa2 : 0xb2; // Telemetry off +#endif else packet[12] = option<8?0x01:0x02; packet[13] = 0x00; //??? @@ -196,13 +197,13 @@ static void __attribute__((unused)) build_data_packet(uint8_t upper)// if (sub_protocol==DSMX) { packet[0] = cyrfmfg_id[2]; - packet[1] = cyrfmfg_id[3] + RX_num; + packet[1] = cyrfmfg_id[3]; bits=11; } else { packet[0] = (0xff ^ cyrfmfg_id[2]); - packet[1] = (0xff ^ cyrfmfg_id[3]) + RX_num; + packet[1] = (0xff ^ cyrfmfg_id[3]); bits=10; } // @@ -251,6 +252,18 @@ static void __attribute__((unused)) build_data_packet(uint8_t upper)// case 7: value=Servo_data[AUX4]; break; + case 8: + value=Servo_data[AUX5]; + break; + case 9: + value=Servo_data[AUX6]; + break; + case 10: + value=Servo_data[AUX7]; + break; + case 11: + value=Servo_data[AUX8]; + break; } value=map(value,PPM_MIN,PPM_MAX,0,max-1); } @@ -267,7 +280,7 @@ static uint8_t __attribute__((unused)) get_pn_row(uint8_t channel) } const uint8_t init_vals[][2] = { - {CYRF_02_TX_CTRL, 0x00}, + {CYRF_02_TX_CTRL, 0x02}, //0x00 in deviation but needed to know when transmit is over {CYRF_05_RX_CTRL, 0x00}, {CYRF_28_CLK_EN, 0x02}, {CYRF_32_AUTO_CAL_TIME, 0x3c}, @@ -314,7 +327,7 @@ static void __attribute__((unused)) initialize_bind_state() CYRF_ConfigSOPCode(code); read_code(code,pn_row,data_col,16); read_code(code+16,0,8,8); - memcpy(code + 24, "\xc6\x94\x22\xfe\x48\xe6\x57\x4e", 8); + memcpy(code + 24, (void *)"\xc6\x94\x22\xfe\x48\xe6\x57\x4e", 8); CYRF_ConfigDataCode(code, 32); build_bind_packet(); @@ -347,10 +360,11 @@ static void __attribute__((unused)) cyrf_configdata() static void __attribute__((unused)) set_sop_data_crc() { uint8_t code[16]; - uint8_t pn_row = get_pn_row(hopping_frequency[chidx]); - //printf("Ch: %d Row: %d SOP: %d Data: %d\n", ch[chidx], pn_row, sop_col, data_col); - CYRF_ConfigRFChannel(hopping_frequency[chidx]); - CYRF_ConfigCRCSeed(crcidx ? ~crc : crc); + uint8_t pn_row = get_pn_row(hopping_frequency[hopping_frequency_no]); + //printf("Ch: %d Row: %d SOP: %d Data: %d\n", ch[hopping_frequency_no], pn_row, sop_col, data_col); + CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]); + CYRF_ConfigCRCSeed(crc); + crc=~crc; read_code(code,pn_row,sop_col,8); CYRF_ConfigSOPCode(code); @@ -358,10 +372,9 @@ static void __attribute__((unused)) set_sop_data_crc() CYRF_ConfigDataCode(code, 16); if(sub_protocol == DSMX) - chidx = (chidx + 1) % 23; + hopping_frequency_no = (hopping_frequency_no + 1) % 23; else - chidx = (chidx + 1) % 2; - crcidx = !crcidx; + hopping_frequency_no = (hopping_frequency_no + 1) % 2; } static void __attribute__((unused)) calc_dsmx_channel() @@ -375,7 +388,7 @@ static void __attribute__((unused)) calc_dsmx_channel() uint8_t count_3_27 = 0, count_28_51 = 0, count_52_76 = 0; id_tmp = id_tmp * 0x0019660D + 0x3C6EF35F; // Randomization uint8_t next_ch = ((id_tmp >> 8) % 0x49) + 3; // Use least-significant byte and must be larger than 3 - if (((next_ch ^ id) & 0x01 )== 0) + if ( (next_ch ^ cyrfmfg_id[3]) & 0x01 ) continue; for (i = 0; i < idx; i++) { @@ -400,10 +413,10 @@ static void __attribute__((unused)) calc_dsmx_channel() uint16_t ReadDsm2() { -#define CH1_CH2_DELAY 4010 // Time between write of channel 1 and channel 2 -#define WRITE_DELAY 1650 // 1550 original, Time after write to verify write complete -#define READ_DELAY 400 // Time before write to check read state, and switch channels - uint8_t i = 0; +#define DSM_CH1_CH2_DELAY 4010 // Time between write of channel 1 and channel 2 +#define DSM_WRITE_DELAY 1550 // Time after write to verify write complete +#define DSM_READ_DELAY 600 // Time before write to check read state, and switch channels. Was 400 but 500 seems what the 328p needs to read a packet + uint32_t start; switch(cyrf_state) { @@ -413,8 +426,7 @@ uint16_t ReadDsm2() if(cyrf_state & 1) { //Send packet on even states - //Note state has already incremented, - // so this is actually 'even' state + //Note state has already incremented, so this is actually 'even' state CYRF_WriteDataPacket(packet); return 8500; } @@ -430,35 +442,81 @@ uint16_t ReadDsm2() //CYRF_FindBestChannels(ch, 2, 10, 1, 79); cyrf_configdata(); CYRF_SetTxRxMode(TX_EN); - chidx = 0; - crcidx = 0; - cyrf_state = DSM2_CH1_WRITE_A; // in fact cyrf_state++ + hopping_frequency_no = 0; + cyrf_state = DSM2_CH1_WRITE_A; // in fact cyrf_state++ set_sop_data_crc(); return 10000; case DSM2_CH1_WRITE_A: case DSM2_CH1_WRITE_B: - build_data_packet(cyrf_state == DSM2_CH1_WRITE_B);//compare state and DSM2_CH1_WRITE_B return 0 or 1 case DSM2_CH2_WRITE_A: case DSM2_CH2_WRITE_B: + build_data_packet(cyrf_state == DSM2_CH1_WRITE_B);// build lower or upper channels + CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS); // clear IRQ flags CYRF_WriteDataPacket(packet); - cyrf_state++; // change from WRITE to CHECK mode - return WRITE_DELAY; + cyrf_state++; // change from WRITE to CHECK mode + return DSM_WRITE_DELAY; case DSM2_CH1_CHECK_A: case DSM2_CH1_CHECK_B: - while (! (CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02)) - if(++i > NUM_WAIT_LOOPS) + start=micros(); + while (micros()-start < 500) // Wait max 500µs + if(CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02) break; set_sop_data_crc(); - cyrf_state++; // change from CH1_CHECK to CH2_WRITE - return CH1_CH2_DELAY - WRITE_DELAY; + cyrf_state++; // change from CH1_CHECK to CH2_WRITE + return DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY; case DSM2_CH2_CHECK_A: case DSM2_CH2_CHECK_B: - while (! (CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02)) - if(++i > NUM_WAIT_LOOPS) + start=micros(); + while (micros()-start < 500) // Wait max 500µs + if(CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02) break; if (cyrf_state == DSM2_CH2_CHECK_A) - CYRF_SetPower(0x28); //Keep transmit power in sync - // No telemetry... + CYRF_SetPower(0x28); //Keep transmit power in sync +#if defined DSM_TELEMETRY + cyrf_state++; // change from CH2_CHECK to CH2_READ + if(option<=3 || option>7) + { // disable telemetry for option between 4 and 7 ie 4,5,6,7 channels @11ms since it does not work... + CYRF_SetTxRxMode(RX_EN); //Receive mode + CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive + } + return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY; + case DSM2_CH2_READ_A: + case DSM2_CH2_READ_B: + //Read telemetry + uint8_t rx_state = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS); + if((rx_state & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing) + rx_state |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS); + if((rx_state & 0x07) == 0x02) + { // good data (complete with no errors) + CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // need to set RXOW before data read + uint8_t len=CYRF_ReadRegister(CYRF_09_RX_COUNT); + if(len>MAX_PKT-2) + len=MAX_PKT-2; + CYRF_ReadDataPacketLen(pkt+1, len); + pkt[0]=CYRF_ReadRegister(CYRF_13_RSSI)&0x1F; // store RSSI of the received telemetry signal + telemetry_link=1; + } + if (cyrf_state == DSM2_CH2_READ_A && option <= 3) // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms + { + //Force end read state + CYRF_WriteRegister(CYRF_0F_XACT_CFG, (CYRF_ReadRegister(CYRF_0F_XACT_CFG) | 0x20)); // Force end state + start=micros(); + while (micros()-start < 100) // Wait max 100 µs + if((CYRF_ReadRegister(CYRF_0F_XACT_CFG) & 0x20) == 0) + break; + cyrf_state = DSM2_CH2_READ_B; + CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive + return 11000; + } + if (cyrf_state == DSM2_CH2_READ_A && option>7) + cyrf_state = DSM2_CH1_WRITE_B; //Transmit upper + else + cyrf_state = DSM2_CH1_WRITE_A; //Force 11ms if option>3 ie 4,5,6,7 channels @11ms + CYRF_SetTxRxMode(TX_EN); //Write mode + set_sop_data_crc(); + return DSM_READ_DELAY; +#else + // No telemetry set_sop_data_crc(); if (cyrf_state == DSM2_CH2_CHECK_A) { @@ -466,16 +524,17 @@ uint16_t ReadDsm2() { cyrf_state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper) if(option>3) - return 11000 - CH1_CH2_DELAY - WRITE_DELAY ; // force 11ms if option>3 ie 4,5,6,7 channels @11ms + return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ; // force 11ms if option>3 ie 4,5,6,7 channels @11ms else - return 22000 - CH1_CH2_DELAY - WRITE_DELAY ; // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms + return 22000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ; // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms } else cyrf_state = DSM2_CH1_WRITE_B; // change from CH2_CHECK_A to CH1_WRITE_A (to transmit upper) } else cyrf_state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_B to CH1_WRITE_A (upper already transmitted so transmit lower) - return 11000 - CH1_CH2_DELAY - WRITE_DELAY; + return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY; +#endif } return 0; } @@ -484,10 +543,12 @@ uint16_t initDsm2() { CYRF_Reset(); CYRF_GetMfgData(cyrfmfg_id);// - + //Model match + cyrfmfg_id[3]+=RX_num; + cyrf_config(); - if (sub_protocol ==DSMX) + if (sub_protocol == DSMX) calc_dsmx_channel(); else { @@ -511,12 +572,12 @@ uint16_t initDsm2() #endif } - ///} - crc = ~((cyrfmfg_id[0] << 8) + cyrfmfg_id[1]); //The crc for channel 'a' is NOT(mfgid[1] << 8 + mfgid[0]) - crcidx = 0;//The crc for channel 'b' is (mfgid[1] << 8 + mfgid[0]) + //The crc for channel '1' is NOT(mfgid[0] << 8 + mfgid[1]) + //The crc for channel '2' is (mfgid[0] << 8 + mfgid[1]) + crc = ~((cyrfmfg_id[0] << 8) + cyrfmfg_id[1]); // - sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07;//Ok - data_col = 7 - sop_col;//ok + sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07; + data_col = 7 - sop_col; CYRF_SetTxRxMode(TX_EN); // diff --git a/Multiprotocol/FlySky_a7105.ino b/Multiprotocol/FlySky_a7105.ino index 84fa3df..ac6fddf 100644 --- a/Multiprotocol/FlySky_a7105.ino +++ b/Multiprotocol/FlySky_a7105.ino @@ -21,25 +21,6 @@ //FlySky constants & variables #define FLYSKY_BIND_COUNT 2500 -const uint8_t PROGMEM tx_channels[] = { - 0x0a, 0x5a, 0x14, 0x64, 0x1e, 0x6e, 0x28, 0x78, 0x32, 0x82, 0x3c, 0x8c, 0x46, 0x96, 0x50, 0xa0, - 0xa0, 0x50, 0x96, 0x46, 0x8c, 0x3c, 0x82, 0x32, 0x78, 0x28, 0x6e, 0x1e, 0x64, 0x14, 0x5a, 0x0a, - 0x0a, 0x5a, 0x50, 0xa0, 0x14, 0x64, 0x46, 0x96, 0x1e, 0x6e, 0x3c, 0x8c, 0x28, 0x78, 0x32, 0x82, - 0x82, 0x32, 0x78, 0x28, 0x8c, 0x3c, 0x6e, 0x1e, 0x96, 0x46, 0x64, 0x14, 0xa0, 0x50, 0x5a, 0x0a, - 0x28, 0x78, 0x0a, 0x5a, 0x50, 0xa0, 0x14, 0x64, 0x1e, 0x6e, 0x3c, 0x8c, 0x32, 0x82, 0x46, 0x96, - 0x96, 0x46, 0x82, 0x32, 0x8c, 0x3c, 0x6e, 0x1e, 0x64, 0x14, 0xa0, 0x50, 0x5a, 0x0a, 0x78, 0x28, - 0x50, 0xa0, 0x28, 0x78, 0x0a, 0x5a, 0x1e, 0x6e, 0x3c, 0x8c, 0x32, 0x82, 0x46, 0x96, 0x14, 0x64, - 0x64, 0x14, 0x96, 0x46, 0x82, 0x32, 0x8c, 0x3c, 0x6e, 0x1e, 0x5a, 0x0a, 0x78, 0x28, 0xa0, 0x50, - 0x50, 0xa0, 0x46, 0x96, 0x3c, 0x8c, 0x28, 0x78, 0x0a, 0x5a, 0x32, 0x82, 0x1e, 0x6e, 0x14, 0x64, - 0x64, 0x14, 0x6e, 0x1e, 0x82, 0x32, 0x5a, 0x0a, 0x78, 0x28, 0x8c, 0x3c, 0x96, 0x46, 0xa0, 0x50, - 0x46, 0x96, 0x3c, 0x8c, 0x50, 0xa0, 0x28, 0x78, 0x0a, 0x5a, 0x1e, 0x6e, 0x32, 0x82, 0x14, 0x64, - 0x64, 0x14, 0x82, 0x32, 0x6e, 0x1e, 0x5a, 0x0a, 0x78, 0x28, 0xa0, 0x50, 0x8c, 0x3c, 0x96, 0x46, - 0x46, 0x96, 0x0a, 0x5a, 0x3c, 0x8c, 0x14, 0x64, 0x50, 0xa0, 0x28, 0x78, 0x1e, 0x6e, 0x32, 0x82, - 0x82, 0x32, 0x6e, 0x1e, 0x78, 0x28, 0xa0, 0x50, 0x64, 0x14, 0x8c, 0x3c, 0x5a, 0x0a, 0x96, 0x46, - 0x46, 0x96, 0x0a, 0x5a, 0x50, 0xa0, 0x3c, 0x8c, 0x28, 0x78, 0x1e, 0x6e, 0x32, 0x82, 0x14, 0x64, - 0x64, 0x14, 0x82, 0x32, 0x6e, 0x1e, 0x78, 0x28, 0x8c, 0x3c, 0xa0, 0x50, 0x5a, 0x0a, 0x96, 0x46 -}; - enum { // flags going to byte 10 FLAG_V9X9_VIDEO = 0x40, @@ -164,12 +145,31 @@ static void __attribute__((unused)) flysky_build_packet(uint8_t init) const uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4}; for(i = 0; i < 8; i++) { - packet[5+2*i]=lowByte(Servo_data[ch[i]]); //low byte of servo timing(1000-2000us) - packet[6+2*i]=highByte(Servo_data[ch[i]]); //high byte of servo timing(1000-2000us) + packet[5 + i*2]=Servo_data[ch[i]]&0xFF; //low byte of servo timing(1000-2000us) + packet[6 + i*2]=(Servo_data[ch[i]]>>8)&0xFF; //high byte of servo timing(1000-2000us) } flysky_apply_extension_flags(); } +const uint8_t PROGMEM tx_channels[16][16] = { + {0x0a, 0x5a, 0x14, 0x64, 0x1e, 0x6e, 0x28, 0x78, 0x32, 0x82, 0x3c, 0x8c, 0x46, 0x96, 0x50, 0xa0}, + {0xa0, 0x50, 0x96, 0x46, 0x8c, 0x3c, 0x82, 0x32, 0x78, 0x28, 0x6e, 0x1e, 0x64, 0x14, 0x5a, 0x0a}, + {0x0a, 0x5a, 0x50, 0xa0, 0x14, 0x64, 0x46, 0x96, 0x1e, 0x6e, 0x3c, 0x8c, 0x28, 0x78, 0x32, 0x82}, + {0x82, 0x32, 0x78, 0x28, 0x8c, 0x3c, 0x6e, 0x1e, 0x96, 0x46, 0x64, 0x14, 0xa0, 0x50, 0x5a, 0x0a}, + {0x28, 0x78, 0x0a, 0x5a, 0x50, 0xa0, 0x14, 0x64, 0x1e, 0x6e, 0x3c, 0x8c, 0x32, 0x82, 0x46, 0x96}, + {0x96, 0x46, 0x82, 0x32, 0x8c, 0x3c, 0x6e, 0x1e, 0x64, 0x14, 0xa0, 0x50, 0x5a, 0x0a, 0x78, 0x28}, + {0x50, 0xa0, 0x28, 0x78, 0x0a, 0x5a, 0x1e, 0x6e, 0x3c, 0x8c, 0x32, 0x82, 0x46, 0x96, 0x14, 0x64}, + {0x64, 0x14, 0x96, 0x46, 0x82, 0x32, 0x8c, 0x3c, 0x6e, 0x1e, 0x5a, 0x0a, 0x78, 0x28, 0xa0, 0x50}, + {0x50, 0xa0, 0x46, 0x96, 0x3c, 0x8c, 0x28, 0x78, 0x0a, 0x5a, 0x32, 0x82, 0x1e, 0x6e, 0x14, 0x64}, + {0x64, 0x14, 0x6e, 0x1e, 0x82, 0x32, 0x5a, 0x0a, 0x78, 0x28, 0x8c, 0x3c, 0x96, 0x46, 0xa0, 0x50}, + {0x46, 0x96, 0x3c, 0x8c, 0x50, 0xa0, 0x28, 0x78, 0x0a, 0x5a, 0x1e, 0x6e, 0x32, 0x82, 0x14, 0x64}, + {0x64, 0x14, 0x82, 0x32, 0x6e, 0x1e, 0x5a, 0x0a, 0x78, 0x28, 0xa0, 0x50, 0x8c, 0x3c, 0x96, 0x46}, + {0x46, 0x96, 0x0a, 0x5a, 0x3c, 0x8c, 0x14, 0x64, 0x50, 0xa0, 0x28, 0x78, 0x1e, 0x6e, 0x32, 0x82}, + {0x82, 0x32, 0x6e, 0x1e, 0x78, 0x28, 0xa0, 0x50, 0x64, 0x14, 0x8c, 0x3c, 0x5a, 0x0a, 0x96, 0x46}, + {0x46, 0x96, 0x0a, 0x5a, 0x50, 0xa0, 0x3c, 0x8c, 0x28, 0x78, 0x1e, 0x6e, 0x32, 0x82, 0x14, 0x64}, + {0x64, 0x14, 0x82, 0x32, 0x6e, 0x1e, 0x78, 0x28, 0x8c, 0x3c, 0xa0, 0x50, 0x5a, 0x0a, 0x96, 0x46}, +}; + uint16_t ReadFlySky() { if (bind_counter) @@ -182,26 +182,25 @@ uint16_t ReadFlySky() } else { - flysky_build_packet(0); - A7105_WriteData(21, pgm_read_byte_near(&tx_channels[chanrow*16+chancol])-chanoffset); + flysky_build_packet(0); + A7105_WriteData(21, pgm_read_byte_near(&tx_channels[chanrow][chancol])-chanoffset); chancol = (chancol + 1) % 16; if (! chancol) //Keep transmit power updated A7105_SetPower(); } - return 1460; + return 1510; //1460 on deviation but not working with the latest V911 bricks... Turnigy 9X v2 is 1533, Flysky TX for 9XR/9XR Pro is 1510, V911 TX is 1490. } uint16_t initFlySky() { //A7105_Reset(); A7105_Init(INIT_FLYSKY); //flysky_init(); - if (rx_tx_addr[3] > 0x90) // limit offset to 9 as higher values don't work with some RX (ie V912) - rx_tx_addr[3] = rx_tx_addr[3] - 0x70; - chanrow=rx_tx_addr[3] % 16; + if ((rx_tx_addr[3]&0xF0) > 0x90) // limit offset to 9 as higher values don't work with some RX (ie V912) + rx_tx_addr[3]=rx_tx_addr[3]-0x70; + chanrow=rx_tx_addr[3] & 0x0F; chancol=0; - chanoffset=rx_tx_addr[3] / 16; + chanoffset=rx_tx_addr[3]/16; - if(IS_AUTOBIND_FLAG_on) bind_counter = FLYSKY_BIND_COUNT; else diff --git a/Multiprotocol/FrSkyX_cc2500.ino b/Multiprotocol/FrSkyX_cc2500.ino index dc6e2f2..5e29950 100644 --- a/Multiprotocol/FrSkyX_cc2500.ino +++ b/Multiprotocol/FrSkyX_cc2500.ino @@ -17,293 +17,319 @@ */ #if defined(FRSKYX_CC2500_INO) - - #include "iface_cc2500.h" - - uint8_t chanskip; - uint8_t calData[48][3]; - uint8_t channr; - uint8_t pass_ = 1 ; - uint8_t counter_rst; - uint8_t ctr; - uint8_t FS_flag=0; - // uint8_t ptr[4]={0x01,0x12,0x23,0x30}; - //uint8_t ptr[4]={0x00,0x11,0x22,0x33}; - - const PROGMEM uint8_t hop_data[]={ - 0x02, 0xD4, 0xBB, 0xA2, 0x89, - 0x70, 0x57, 0x3E, 0x25, 0x0C, - 0xDE, 0xC5, 0xAC, 0x93, 0x7A, - 0x61, 0x48, 0x2F, 0x16, 0xE8, - 0xCF, 0xB6, 0x9D, 0x84, 0x6B, - 0x52, 0x39, 0x20, 0x07, 0xD9, - 0xC0, 0xA7, 0x8E, 0x75, 0x5C, - 0x43, 0x2A, 0x11, 0xE3, 0xCA, - 0xB1, 0x98, 0x7F, 0x66, 0x4D, - 0x34, 0x1B, 0x00, 0x1D, 0x03 - }; - static uint8_t __attribute__((unused)) hop(uint8_t byte) - { - return pgm_read_byte_near(&hop_data[byte]); - } +#include "iface_cc2500.h" - static void __attribute__((unused)) set_start(uint8_t ch ) - { - cc2500_strobe(CC2500_SIDLE); - cc2500_writeReg(CC2500_23_FSCAL3, calData[ch][0]); - cc2500_writeReg(CC2500_24_FSCAL2, calData[ch][1]); - cc2500_writeReg(CC2500_25_FSCAL1, calData[ch][2]); - cc2500_writeReg(CC2500_0A_CHANNR, ch==47?0:pgm_read_word(&hop_data[ch])); - } +uint8_t chanskip; +uint8_t channr; +uint8_t counter_rst; +uint8_t ctr; +uint8_t FS_flag=0; +uint8_t seq_last_sent; +uint8_t seq_last_rcvd; + +const PROGMEM uint8_t hop_data[]={ + 0x02, 0xD4, 0xBB, 0xA2, 0x89, + 0x70, 0x57, 0x3E, 0x25, 0x0C, + 0xDE, 0xC5, 0xAC, 0x93, 0x7A, + 0x61, 0x48, 0x2F, 0x16, 0xE8, + 0xCF, 0xB6, 0x9D, 0x84, 0x6B, + 0x52, 0x39, 0x20, 0x07, 0xD9, + 0xC0, 0xA7, 0x8E, 0x75, 0x5C, + 0x43, 0x2A, 0x11, 0xE3, 0xCA, + 0xB1, 0x98, 0x7F, 0x66, 0x4D, + 0x34, 0x1B, 0x00, 0x1D, 0x03 +}; + +static uint8_t __attribute__((unused)) hop(uint8_t byte) +{ + return pgm_read_byte_near(&hop_data[byte]); +} + +static void __attribute__((unused)) set_start(uint8_t ch ) +{ + CC2500_Strobe(CC2500_SIDLE); + CC2500_WriteReg(CC2500_23_FSCAL3, calData[ch][0]); + CC2500_WriteReg(CC2500_24_FSCAL2, calData[ch][1]); + CC2500_WriteReg(CC2500_25_FSCAL1, calData[ch][2]); + CC2500_WriteReg(CC2500_0A_CHANNR, ch==47? 0:pgm_read_word(&hop_data[ch])); +} + +static void __attribute__((unused)) frskyX_init() +{ + CC2500_Reset(); - static void __attribute__((unused)) frskyX_init() + for(uint8_t i=0;i<36;i++) { - CC2500_Reset(); + uint8_t reg=pgm_read_byte_near(&cc2500_conf[i][0]); + uint8_t val=pgm_read_byte_near(&cc2500_conf[i][1]); - for(uint8_t i=0;i<36;i++) - { - uint8_t reg=pgm_read_byte_near(&cc2500_conf[i][0]); - uint8_t val=pgm_read_byte_near(&cc2500_conf[i][1]); - - if(reg==CC2500_06_PKTLEN) - val=0x1E; - else - if(reg==CC2500_08_PKTCTRL0) - val=0x01; - else - if(reg==CC2500_0B_FSCTRL1) - val=0x0A; - else - if(reg==CC2500_10_MDMCFG4) - val=0x7B; - else - if(reg==CC2500_11_MDMCFG3) - val=0x61; - else - if(reg==CC2500_12_MDMCFG2) - val=0x13; - else - if(reg==CC2500_15_DEVIATN) - val=0x51; - - cc2500_writeReg(reg,val); - } + if(reg==CC2500_06_PKTLEN) + val=0x1E; + else + if(reg==CC2500_08_PKTCTRL0) + val=0x01; + else + if(reg==CC2500_0B_FSCTRL1) + val=0x0A; + else + if(reg==CC2500_10_MDMCFG4) + val=0x7B; + else + if(reg==CC2500_11_MDMCFG3) + val=0x61; + else + if(reg==CC2500_12_MDMCFG2) + val=0x13; + else + if(reg==CC2500_15_DEVIATN) + val=0x51; + + CC2500_WriteReg(reg,val); + } - cc2500_writeReg(CC2500_07_PKTCTRL1, 0x04); - cc2500_writeReg(CC2500_0C_FSCTRL0, option); - cc2500_strobe(CC2500_SIDLE); - // - for(uint8_t c=0;c < 47;c++){//calibrate hop channels - cc2500_strobe(CC2500_SIDLE); - cc2500_writeReg(CC2500_0A_CHANNR,pgm_read_word(&hop_data[c])); - cc2500_strobe(CC2500_SCAL); - delayMicroseconds(900);// - calData[c][0] = cc2500_readReg(CC2500_23_FSCAL3); - calData[c][1] = cc2500_readReg(CC2500_24_FSCAL2); - calData[c][2] = cc2500_readReg(CC2500_25_FSCAL1); - } - cc2500_strobe(CC2500_SIDLE); - cc2500_writeReg(CC2500_0A_CHANNR,0x00); - cc2500_strobe(CC2500_SCAL); - delayMicroseconds(900); - calData[47][0] = cc2500_readReg(CC2500_23_FSCAL3); - calData[47][1] = cc2500_readReg(CC2500_24_FSCAL2); - calData[47][2] = cc2500_readReg(CC2500_25_FSCAL1); - //#######END INIT######## + CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x04); + CC2500_WriteReg(CC2500_0C_FSCTRL0, option); + CC2500_Strobe(CC2500_SIDLE); + // + for(uint8_t c=0;c < 47;c++) + {//calibrate hop channels + CC2500_Strobe(CC2500_SIDLE); + CC2500_WriteReg(CC2500_0A_CHANNR,pgm_read_word(&hop_data[c])); + CC2500_Strobe(CC2500_SCAL); + delayMicroseconds(900);// + calData[c][0] = CC2500_ReadReg(CC2500_23_FSCAL3); + calData[c][1] = CC2500_ReadReg(CC2500_24_FSCAL2); + calData[c][2] = CC2500_ReadReg(CC2500_25_FSCAL1); } - - static void __attribute__((unused)) initialize_data(uint8_t adr) - { - cc2500_writeReg(CC2500_0C_FSCTRL0,option); // Frequency offset hack - cc2500_writeReg(CC2500_18_MCSM0, 0x8); - cc2500_writeReg(CC2500_09_ADDR, adr ? 0x03 : rx_tx_addr[3]); - cc2500_writeReg(CC2500_07_PKTCTRL1,0x05); - } - + CC2500_Strobe(CC2500_SIDLE); + CC2500_WriteReg(CC2500_0A_CHANNR,0x00); + CC2500_Strobe(CC2500_SCAL); + delayMicroseconds(900); + calData[47][0] = CC2500_ReadReg(CC2500_23_FSCAL3); + calData[47][1] = CC2500_ReadReg(CC2500_24_FSCAL2); + calData[47][2] = CC2500_ReadReg(CC2500_25_FSCAL1); + //#######END INIT######## +} + +static void __attribute__((unused)) initialize_data(uint8_t adr) +{ + CC2500_WriteReg(CC2500_0C_FSCTRL0,option); // Frequency offset hack + CC2500_WriteReg(CC2500_18_MCSM0, 0x8); + CC2500_WriteReg(CC2500_09_ADDR, adr ? 0x03 : rx_tx_addr[3]); + CC2500_WriteReg(CC2500_07_PKTCTRL1,0x05); +} +/* static uint8_t __attribute__((unused)) crc_Byte( uint8_t byte ) { crc = (crc<<8) ^ pgm_read_word(&CRCTable[((uint8_t)(crc>>8) ^ byte) & 0xFF]); return byte; } - - static uint16_t __attribute__((unused)) scaleForPXX( uint8_t i ) - { //mapped 860,2140(125%) range to 64,1984(PXX values); - return (uint16_t)(((Servo_data[i]-PPM_MIN)*3)>>1)+64; - } +*/ +static uint16_t __attribute__((unused)) crc_x(uint8_t *data, uint8_t len) +{ + uint16_t crc = 0; + for(uint8_t i=0; i < len; i++) + crc = (crc<<8) ^ pgm_read_word(&CRCTable[((uint8_t)(crc>>8) ^ *data++) & 0xFF]); + return crc; +} + + // 0-2047, 0 = 817, 1024 = 1500, 2047 = 2182 + //64=860,1024=1500,1984=2140//Taranis 125% + +static uint16_t __attribute__((unused)) scaleForPXX( uint8_t i ) +{ //mapped 860,2140(125%) range to 64,1984(PXX values); + return (uint16_t)(((Servo_data[i]-PPM_MIN)*3)>>1)+64; +} + +static void __attribute__((unused)) frskyX_build_bind_packet() +{ + packet[0] = 0x1D; + packet[1] = 0x03; + packet[2] = 0x01; + // + packet[3] = rx_tx_addr[3]; + packet[4] = rx_tx_addr[2]; + int idx = ((state -FRSKY_BIND) % 10) * 5; + packet[5] = idx; + packet[6] = pgm_read_word(&hop_data[idx++]); + packet[7] = pgm_read_word(&hop_data[idx++]); + packet[8] = pgm_read_word(&hop_data[idx++]); + packet[9] = pgm_read_word(&hop_data[idx++]); + packet[10] = pgm_read_word(&hop_data[idx++]); + packet[11] = 0x02; + packet[12] = RX_num; + // + memset(&packet[13], 0, 15); + uint16_t lcrc = crc_x(&packet[3], 25); + // + packet[28] = lcrc >> 8; + packet[29] = lcrc; + // +} + +static void __attribute__((unused)) frskyX_data_frame() +{ + //0x1D 0xB3 0xFD 0x02 0x56 0x07 0x15 0x00 0x00 0x00 0x04 0x40 0x00 0x04 0x40 0x00 0x04 0x40 0x00 0x04 0x40 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x96 0x12 + // + static uint8_t lpass; + uint16_t chan_0 ; + uint16_t chan_1 ; + uint8_t startChan = 0; + // + packet[0] = 0x1D; + packet[1] = rx_tx_addr[3]; + packet[2] = rx_tx_addr[2]; + packet[3] = 0x02; + // + packet[4] = (ctr<<6)+channr; + packet[5] = counter_rst; + packet[6] = RX_num; + //FLAGS 00 - standard packet + //10, 12, 14, 16, 18, 1A, 1C, 1E - failsafe packet + //20 - range check packet + packet[7] = FS_flag; + packet[8] = 0; + // + if ( lpass & 1 ) + startChan += 8 ; - static void __attribute__((unused)) frskyX_build_bind_packet() - { - crc=0; - packet[0] = 0x1D; - packet[1] = 0x03; - packet[2] = 0x01; - // - packet[3] = crc_Byte(rx_tx_addr[3]); - packet[4] = crc_Byte(rx_tx_addr[2]); - int idx = ((state -FRSKY_BIND) % 10) * 5; - packet[5] = crc_Byte(idx); - packet[6] = crc_Byte(pgm_read_word(&hop_data[idx++])); - packet[7] = crc_Byte(pgm_read_word(&hop_data[idx++])); - packet[8] = crc_Byte(pgm_read_word(&hop_data[idx++])); - packet[9] = crc_Byte(pgm_read_word(&hop_data[idx++])); - packet[10] = crc_Byte(pgm_read_word(&hop_data[idx++])); - packet[11] = crc_Byte(0x02); - packet[12] = crc_Byte(RX_num); + for(uint8_t i = 0; i <12 ; i+=3) + {//12 bytes + chan_0 = scaleForPXX(startChan); + if(lpass & 1 ) + chan_0+=2048; + startChan+=1; // - for(uint8_t i=13;i<28;i++) - packet[i]=crc_Byte(0); + chan_1 = scaleForPXX(startChan); + if(lpass & 1 ) + chan_1+= 2048; + startChan+=1; // - packet[28]=highByte(crc); - packet[29]=lowByte(crc); - // - } - - static void __attribute__((unused)) frskyX_data_frame() - { - //0x1D 0xB3 0xFD 0x02 0x56 0x07 0x15 0x00 0x00 0x00 0x04 0x40 0x00 0x04 0x40 0x00 0x04 0x40 0x00 0x04 0x40 0x08 0x00 0x00 0x00 0x00 0x00 0x00 0x96 0x12 - // - uint8_t lpass = pass_ ; - uint16_t chan_0 ; - uint16_t chan_1 ; - uint8_t flag2 = 0; - uint8_t startChan = 0; - crc = 0; - //static uint8_t p = 0; - // - packet[0] = 0x1D; - packet[1] = rx_tx_addr[3]; - packet[2] = rx_tx_addr[2]; - packet[3] = crc_Byte(0x02); - // - packet[4] = crc_Byte((ctr<<6)+channr); //*64 - packet[5] = crc_Byte(counter_rst); - packet[6] = crc_Byte(RX_num); - // FLAGS 00 - standard packet - //10, 12, 14, 16, 18, 1A, 1C, 1E - failsafe packet - //20 - range check packet - packet[7] = crc_Byte(FS_flag); - packet[8] = crc_Byte(flag2); - // - if ( lpass & 1 ) - startChan += 8 ; - - for(uint8_t i = 0; i <12 ; i+=3) - {//12 bytes - chan_0 = scaleForPXX(startChan); - if(lpass & 1 ) - chan_0+=2048; - - packet[9+i] = crc_Byte(lowByte(chan_0));//3 bytes*4 - startChan++; - chan_1 = scaleForPXX(startChan); - if(lpass & 1 ) - chan_1+= 2048; - - startChan++; - packet[9+i+1]=crc_Byte((((chan_0>>8) & 0x0F)|(chan_1 << 4))); - packet[9+i+2]=crc_Byte(chan_1>>4); - } - //packet[21]=crc_Byte(0x08);//first - packet[21]=crc_Byte(0x80);//??? when received first telemetry frame is changed to 0x80 - //packet[21]=crc_Byte(ptr[p]);//??? - //p=(p+1)%4;//repeating 4 bytes sequence pattern every 4th frame. - - pass_=lpass+1; - - for (uint8_t i=22;i<28;i++) - packet[i]=crc_Byte(0); - - packet[28]=highByte(crc); - packet[29]=lowByte(crc); + packet[9+i] = lowByte(chan_0);//3 bytes*4 + packet[9+i+1]=(((chan_0>>8) & 0x0F)|(chan_1 << 4)); + packet[9+i+2]=chan_1>>4; } - uint16_t ReadFrSkyX() - { - switch(state) - { - default: - set_start(47); - CC2500_SetPower(); - cc2500_strobe(CC2500_SFRX); - // - frskyX_build_bind_packet(); - cc2500_strobe(CC2500_SIDLE); - cc2500_writeFifo(packet, packet[0]+1); - state++; - return 9000; - case FRSKY_BIND_DONE: - initialize_data(0); - channr=0; - BIND_DONE; - state++; - break; - case FRSKY_DATA1: - LED_ON; - CC2500_SetTxRxMode(TX_EN); - set_start(channr); - CC2500_SetPower(); - cc2500_strobe(CC2500_SFRX); - channr = (channr+chanskip)%47; - cc2500_strobe(CC2500_SIDLE); - cc2500_writeFifo(packet, packet[0]+1); - // - frskyX_data_frame(); - state++; - return 5500; - case FRSKY_DATA2: - CC2500_SetTxRxMode(RX_EN); - cc2500_strobe(CC2500_SIDLE); - state++; - return 200; - case FRSKY_DATA3: - cc2500_strobe(CC2500_SRX); - state++; - return 3000; - case FRSKY_DATA4: - len = cc2500_readReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F; - if (len &&(len>8;//high byte + packet[29]=lcrc;//low byte +} - uint16_t initFrSkyX() - { - while(!chanskip) - { - randomSeed((uint32_t)analogRead(A6) << 10 | analogRead(A7)); - chanskip=random(0xfefefefe)%47; - } - while((chanskip-ctr)%4) - ctr=(ctr+1)%4; - - counter_rst=(chanskip-ctr)>>2; - //for test*************** - //rx_tx_addr[3]=0xB3; - //rx_tx_addr[2]=0xFD; - //************************ - frskyX_init(); - // - if(IS_AUTOBIND_FLAG_on) - { - state = FRSKY_BIND; - initialize_data(1); - } - else - { - state = FRSKY_DATA1; +uint16_t ReadFrSkyX() +{ + switch(state) + { + default: + set_start(47); + CC2500_SetPower(); + CC2500_Strobe(CC2500_SFRX); + // + frskyX_build_bind_packet(); + CC2500_Strobe(CC2500_SIDLE); + CC2500_WriteData(packet, packet[0]+1); + state++; + return 9000; + case FRSKY_BIND_DONE: initialize_data(0); - } - return 10000; - } + channr=0; + BIND_DONE; + state++; + break; + case FRSKY_DATA1: + LED_ON; + CC2500_SetTxRxMode(TX_EN); + set_start(channr); + CC2500_SetPower(); + CC2500_Strobe(CC2500_SFRX); + channr = (channr+chanskip)%47; + CC2500_Strobe(CC2500_SIDLE); + CC2500_WriteData(packet, packet[0]+1); + // + frskyX_data_frame(); + state++; + return 5500; + case FRSKY_DATA2: + CC2500_SetTxRxMode(RX_EN); + CC2500_Strobe(CC2500_SIDLE); + state++; + return 200; + case FRSKY_DATA3: + CC2500_Strobe(CC2500_SRX); + state++; + return 3000; + case FRSKY_DATA4: + len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F; + if (len && (len100) + {//~1sec + seq_last_sent = 0; + seq_last_rcvd = 8; + counter=0; + } + } + state = FRSKY_DATA1; + return 300; + } + return 1; +} + +uint16_t initFrSkyX() +{ + while(!chanskip) + { + randomSeed((uint32_t)analogRead(A6) << 10 | analogRead(A7)); + chanskip=random(0xfefefefe)%47; + } + while((chanskip-ctr)%4) + ctr=(ctr+1)%4; + + counter_rst=(chanskip-ctr)>>2; + //for test*************** + //rx_tx_addr[3]=0xB3; + //rx_tx_addr[2]=0xFD; + //************************ + frskyX_init(); + CC2500_SetTxRxMode(TX_EN); + // + if(IS_AUTOBIND_FLAG_on) + { + state = FRSKY_BIND; + initialize_data(1); + } + else + { + state = FRSKY_DATA1; + initialize_data(0); + } + seq_last_sent = 0; + seq_last_rcvd = 8; + return 10000; +} #endif \ No newline at end of file diff --git a/Multiprotocol/FrSky_cc2500.ino b/Multiprotocol/FrSky_cc2500.ino index ec17450..85f468e 100644 --- a/Multiprotocol/FrSky_cc2500.ino +++ b/Multiprotocol/FrSky_cc2500.ino @@ -48,21 +48,21 @@ static void __attribute__((unused)) frsky2way_init(uint8_t bind) else if(reg==CC2500_1B_AGCCTRL2) val=bind ? 0x43 : 0x03; - cc2500_writeReg(reg,val); + CC2500_WriteReg(reg,val); } CC2500_SetTxRxMode(TX_EN); CC2500_SetPower(); - cc2500_strobe(CC2500_SIDLE); + CC2500_Strobe(CC2500_SIDLE); - cc2500_writeReg(CC2500_09_ADDR, bind ? 0x03 : rx_tx_addr[3]); - cc2500_writeReg(CC2500_07_PKTCTRL1, 0x05); - cc2500_strobe(CC2500_SIDLE); // Go to idle... + CC2500_WriteReg(CC2500_09_ADDR, bind ? 0x03 : rx_tx_addr[3]); + CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x05); + CC2500_Strobe(CC2500_SIDLE); // Go to idle... // - cc2500_writeReg(CC2500_0A_CHANNR, 0x00); - cc2500_writeReg(CC2500_23_FSCAL3, 0x89); - cc2500_strobe(CC2500_SFRX); + CC2500_WriteReg(CC2500_0A_CHANNR, 0x00); + CC2500_WriteReg(CC2500_23_FSCAL3, 0x89); + CC2500_Strobe(CC2500_SFRX); //#######END INIT######## } @@ -158,11 +158,11 @@ uint16_t ReadFrSky_2way() if (state < FRSKY_BIND_DONE) { frsky2way_build_bind_packet(); - cc2500_strobe(CC2500_SIDLE); - cc2500_writeReg(CC2500_0A_CHANNR, 0x00); - cc2500_writeReg(CC2500_23_FSCAL3, 0x89); - cc2500_strobe(CC2500_SFRX);//0x3A - cc2500_writeFifo(packet, packet[0]+1); + CC2500_Strobe(CC2500_SIDLE); + CC2500_WriteReg(CC2500_0A_CHANNR, 0x00); + CC2500_WriteReg(CC2500_23_FSCAL3, 0x89); + CC2500_Strobe(CC2500_SFRX);//0x3A + CC2500_WriteData(packet, packet[0]+1); state++; return 9000; } @@ -176,7 +176,7 @@ uint16_t ReadFrSky_2way() else if (state == FRSKY_DATA5) { - cc2500_strobe(CC2500_SRX);//0x34 RX enable + CC2500_Strobe(CC2500_SRX);//0x34 RX enable state = FRSKY_DATA1; return 9200; } @@ -184,9 +184,9 @@ uint16_t ReadFrSky_2way() if (state == FRSKY_DATA4) { //telemetry receive CC2500_SetTxRxMode(RX_EN); - cc2500_strobe(CC2500_SIDLE); - cc2500_writeReg(CC2500_0A_CHANNR, get_chan_num(counter % 47)); - cc2500_writeReg(CC2500_23_FSCAL3, 0x89); + CC2500_Strobe(CC2500_SIDLE); + CC2500_WriteReg(CC2500_0A_CHANNR, get_chan_num(counter % 47)); + CC2500_WriteReg(CC2500_23_FSCAL3, 0x89); state++; return 1300; } @@ -194,10 +194,10 @@ uint16_t ReadFrSky_2way() { if (state == FRSKY_DATA1) { - len = cc2500_readReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F; + len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F; if (len<=MAX_PKT)//27 bytes { - cc2500_readFifo(pkt, len); //received telemetry packets + CC2500_ReadData(pkt, len); //received telemetry packets #if defined(TELEMETRY) //parse telemetry packet here frsky_check_telemetry(pkt,len); //check if valid telemetry packets and buffer them. @@ -206,12 +206,12 @@ uint16_t ReadFrSky_2way() CC2500_SetTxRxMode(TX_EN); CC2500_SetPower(); // Set tx_power } - cc2500_strobe(CC2500_SIDLE); - cc2500_writeReg(CC2500_0A_CHANNR, get_chan_num(counter % 47)); - cc2500_writeReg(CC2500_23_FSCAL3, 0x89); - cc2500_strobe(CC2500_SFRX); + CC2500_Strobe(CC2500_SIDLE); + CC2500_WriteReg(CC2500_0A_CHANNR, get_chan_num(counter % 47)); + CC2500_WriteReg(CC2500_23_FSCAL3, 0x89); + CC2500_Strobe(CC2500_SFRX); frsky2way_data_frame(); - cc2500_writeFifo(packet, packet[0]+1); + CC2500_WriteData(packet, packet[0]+1); state++; } return state == FRSKY_DATA4 ? 7500 : 9000; diff --git a/Multiprotocol/Makefile.xmega b/Multiprotocol/Makefile.xmega new file mode 100644 index 0000000..3c596b7 --- /dev/null +++ b/Multiprotocol/Makefile.xmega @@ -0,0 +1,624 @@ +# Hey Emacs, this is a -*- makefile -*- +#---------------------------------------------------------------------------- +# WinAVR Makefile +# +# On command line: +# +# make all = Make software. +# +# make clean = Clean out built project files. +# +# make coff = Convert ELF to AVR COFF. +# +# make extcoff = Convert ELF to AVR Extended COFF. +# +# make program = Download the hex file to the device, using avrdude. +# Please customize the avrdude settings below first! +# +# make debug = Start either simulavr or avarice as specified for debugging, +# with avr-gdb or avr-insight as the front end for debugging. +# +# make filename.s = Just compile filename.c into the assembler code only. +# +# make filename.i = Create a preprocessed source file for use in submitting +# bug reports to the GCC project. +# +# To rebuild project do "make clean" then "make all". +#---------------------------------------------------------------------------- + + +# MCU name +MCU = atxmega32d4 + + +# Processor frequency. +# This will define a symbol, F_CPU, in all source code files equal to the +# processor frequency. You can then use this symbol in your source code to +# calculate timings. Do NOT tack on a 'UL' at the end, this will be done +# automatically to create a 32-bit value in your source code. +# Typical values are: +# F_CPU = 1000000 +# F_CPU = 1843200 +# F_CPU = 2000000 +# F_CPU = 3686400 +# F_CPU = 4000000 +# F_CPU = 7372800 +# F_CPU = 8000000 +# F_CPU = 11059200 +# F_CPU = 14745600 +# F_CPU = 16000000 +# F_CPU = 18432000 +# F_CPU = 20000000 +F_CPU = 32000000 + + +# Output format. (can be srec, ihex, binary) +FORMAT = ihex + + +# Target file name (without extension). +TARGET = MultiOrange + + +# Object files directory +# To put object files in current directory, use a dot (.), do NOT make +# this an empty or blank macro! +OBJDIR = . + + +# List C source files here. (C dependencies are automatically generated.) +SRC = + + +# List C++ source files here. (C dependencies are automatically generated.) +CPPSRC = $(TARGET).cpp +CPPSRC += Wmath.cpp +#CPPSRC += DSM2_cyrf6936.cpp + +# List Assembler source files here. +# Make them always end in a capital .S. Files ending in a lowercase .s +# will not be considered source files but generated files (assembler +# output from the compiler), and will be deleted upon "make clean"! +# Even though the DOS/Win* filesystem matches both .s and .S the same, +# it will preserve the spelling of the filenames, and gcc itself does +# care about how the name is spelled on its command-line. +ASRC = + + +# Optimization level, can be [0, 1, 2, 3, s]. +# 0 = turn off optimization. s = optimize for size. +# (Note: 3 is not always the best optimization level. See avr-libc FAQ.) +OPT = s + + +# Debugging format. +# Native formats for AVR-GCC's -g are dwarf-2 [default] or stabs. +# AVR Studio 4.10 requires dwarf-2. +# AVR [Extended] COFF format requires stabs, plus an avr-objcopy run. +#DEBUG = stabs +DEBUG = dwarf-2 + + +# List any extra directories to look for include files here. +# Each directory must be seperated by a space. +# Use forward slashes for directory separators. +# For a directory that has spaces, enclose it in quotes. +EXTRAINCDIRS = + + +# Compiler flag to set the C Standard level. +# c89 = "ANSI" C +# gnu89 = c89 plus GCC extensions +# c99 = ISO C99 standard (not yet fully implemented) +# gnu99 = c99 plus GCC extensions +CSTANDARD = -std=gnu99 + + +# Place -D or -U options here for C sources +CDEFS = -DF_CPU=$(F_CPU)UL + + +# Place -D or -U options here for ASM sources +ADEFS = -DF_CPU=$(F_CPU) + + +# Place -D or -U options here for C++ sources +CPPDEFS = -DF_CPU=$(F_CPU)UL +#CPPDEFS += -D__STDC_LIMIT_MACROS +#CPPDEFS += -D__STDC_CONSTANT_MACROS + + + +#---------------- Compiler Options C ---------------- +# -g*: generate debugging information +# -O*: optimization level +# -f...: tuning, see GCC manual and avr-libc documentation +# -Wall...: warning level +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns...: create assembler listing +CFLAGS = -g$(DEBUG) +CFLAGS += $(CDEFS) +CFLAGS += -O$(OPT) +CFLAGS += -funsigned-char +CFLAGS += -funsigned-bitfields +CFLAGS += -fpack-struct +CFLAGS += -fshort-enums +CFLAGS += -Wall +CFLAGS += -Wno-main +CFLAGS += -Wstrict-prototypes +#CFLAGS += -mshort-calls +#CFLAGS += -fno-unit-at-a-time +#CFLAGS += -Wundef +#CFLAGS += -Wunreachable-code +#CFLAGS += -Wsign-compare +CFLAGS += -Wa,-adlns=$(<:%.c=$(OBJDIR)/%.lst) +CFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) +CFLAGS += $(CSTANDARD) +# Next line dumps rtl file +#CFLAGS += -dr +#CFLAGS += -Wa,-adhlns=$(<:%.c=$(OBJDIR)/%.lst) + + +#---------------- Compiler Options C++ ---------------- +# -g*: generate debugging information +# -O*: optimization level +# -f...: tuning, see GCC manual and avr-libc documentation +# -Wall...: warning level +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns...: create assembler listing +CPPFLAGS = -g$(DEBUG) +CPPFLAGS += $(CPPDEFS) +CPPFLAGS += -O$(OPT) +CPPFLAGS += -funsigned-char +CPPFLAGS += -funsigned-bitfields +CPPFLAGS += -fpack-struct +CPPFLAGS += -fshort-enums +CPPFLAGS += -fno-exceptions +CPPFLAGS += -Wall +CFLAGS += -Wundef +#CPPFLAGS += -mshort-calls +#CPPFLAGS += -fno-unit-at-a-time +#CPPFLAGS += -Wstrict-prototypes +#CPPFLAGS += -Wunreachable-code +#CPPFLAGS += -Wsign-compare +CPPFLAGS += -Wa,-adlns=$(<:%.cpp=$(OBJDIR)/%.lst) +CPPFLAGS += $(patsubst %,-I%,$(EXTRAINCDIRS)) +#CPPFLAGS += $(CSTANDARD) +#CPPFLAGS += -Wa,-adhlns=$(<:%.cpp=$(OBJDIR)/%.lst) + + +#---------------- Assembler Options ---------------- +# -Wa,...: tell GCC to pass this to the assembler. +# -adhlns: create listing +# -gstabs: have the assembler create line number information; note that +# for use in COFF files, additional information about filenames +# and function names needs to be present in the assembler source +# files -- see avr-libc docs [FIXME: not yet described there] +# -listing-cont-lines: Sets the maximum number of continuation lines of hex +# dump that will be displayed for a given single line of source input. +ASFLAGS = $(ADEFS) -Wa,-adhlns=$(<:%.S=$(OBJDIR)/%.lst),-gstabs,--listing-cont-lines=100 + + +#---------------- Library Options ---------------- +# Minimalistic printf version +PRINTF_LIB_MIN = -Wl,-u,vfprintf -lprintf_min + +# Floating point printf version (requires MATH_LIB = -lm below) +PRINTF_LIB_FLOAT = -Wl,-u,vfprintf -lprintf_flt + +# If this is left blank, then it will use the Standard printf version. +PRINTF_LIB = +#PRINTF_LIB = $(PRINTF_LIB_MIN) +#PRINTF_LIB = $(PRINTF_LIB_FLOAT) + + +# Minimalistic scanf version +SCANF_LIB_MIN = -Wl,-u,vfscanf -lscanf_min + +# Floating point + %[ scanf version (requires MATH_LIB = -lm below) +SCANF_LIB_FLOAT = -Wl,-u,vfscanf -lscanf_flt + +# If this is left blank, then it will use the Standard scanf version. +SCANF_LIB = +#SCANF_LIB = $(SCANF_LIB_MIN) +#SCANF_LIB = $(SCANF_LIB_FLOAT) + + +MATH_LIB = -lm + + +# List any extra directories to look for libraries here. +# Each directory must be seperated by a space. +# Use forward slashes for directory separators. +# For a directory that has spaces, enclose it in quotes. +EXTRALIBDIRS = + + + +#---------------- External Memory Options ---------------- + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# used for variables (.data/.bss) and heap (malloc()). +#EXTMEMOPTS = -Wl,-Tdata=0x801100,--defsym=__heap_end=0x80ffff + +# 64 KB of external RAM, starting after internal RAM (ATmega128!), +# only used for heap (malloc()). +#EXTMEMOPTS = -Wl,--section-start,.data=0x801100,--defsym=__heap_end=0x80ffff + +EXTMEMOPTS = + + + +#---------------- Linker Options ---------------- +# -Wl,...: tell GCC to pass this to linker. +# -Map: create map file +# --cref: add cross reference to map file +LDFLAGS = -Wl,-Map=$(TARGET).map,--cref +LDFLAGS += $(EXTMEMOPTS) +LDFLAGS += $(patsubst %,-L%,$(EXTRALIBDIRS)) +LDFLAGS += $(PRINTF_LIB) $(SCANF_LIB) $(MATH_LIB) +#LDFLAGS += -Wl,--section-start=.text=0x00D0 +#LDFLAGS += -Wl,--section-start=.vectors=0x0080 +#LDFLAGS += -T avr3-167.ld +LDFLAGS += -N + + + +#---------------- Programming Options (avrdude) ---------------- + +# Programming hardware: alf avr910 avrisp bascom bsd +# dt006 pavr picoweb pony-stk200 sp12 stk200 stk500 +# +# Type: avrdude -c ? +# to get a full listing. +# +AVRDUDE_PROGRAMMER = stk500 + +# com1 = serial port. Use lpt1 to connect to parallel port. +AVRDUDE_PORT = com3 + +AVRDUDE_WRITE_FLASH = -U flash:w:$(TARGET).hex +#AVRDUDE_WRITE_EEPROM = -U eeprom:w:$(TARGET).eep + + +# Uncomment the following if you want avrdude's erase cycle counter. +# Note that this counter needs to be initialized first using -Yn, +# see avrdude manual. +#AVRDUDE_ERASE_COUNTER = -y + +# Uncomment the following if you do /not/ wish a verification to be +# performed after programming the device. +#AVRDUDE_NO_VERIFY = -V + +# Increase verbosity level. Please use this when submitting bug +# reports about avrdude. See +# to submit bug reports. +#AVRDUDE_VERBOSE = -v -v + +AVRDUDE_FLAGS = -p $(MCU) -P $(AVRDUDE_PORT) -c $(AVRDUDE_PROGRAMMER) +AVRDUDE_FLAGS += $(AVRDUDE_NO_VERIFY) +AVRDUDE_FLAGS += $(AVRDUDE_VERBOSE) +AVRDUDE_FLAGS += $(AVRDUDE_ERASE_COUNTER) + + + +#---------------- Debugging Options ---------------- + +# For simulavr only - target MCU frequency. +DEBUG_MFREQ = $(F_CPU) + +# Set the DEBUG_UI to either gdb or insight. +# DEBUG_UI = gdb +DEBUG_UI = insight + +# Set the debugging back-end to either avarice, simulavr. +DEBUG_BACKEND = avarice +#DEBUG_BACKEND = simulavr + +# GDB Init Filename. +GDBINIT_FILE = __avr_gdbinit + +# When using avarice settings for the JTAG +JTAG_DEV = /dev/com1 + +# Debugging port used to communicate between GDB / avarice / simulavr. +DEBUG_PORT = 4242 + +# Debugging host used to communicate between GDB / avarice / simulavr, normally +# just set to localhost unless doing some sort of crazy debugging when +# avarice is running on a different computer. +DEBUG_HOST = localhost + + + +#============================================================================ + + +# Define programs and commands. +SHELL = sh +CC = avr-gcc +OBJCOPY = avr-objcopy +OBJDUMP = avr-objdump +SIZE = avr-size +AR = avr-ar rcs +NM = avr-nm +AVRDUDE = avrdude +REMOVE = rm -f +REMOVEDIR = rm -rf +COPY = cp +WINSHELL = cmd + + +# Define Messages +# English +MSG_ERRORS_NONE = Errors: none +MSG_BEGIN = -------- begin -------- +MSG_END = -------- end -------- +MSG_SIZE_BEFORE = Size before: +MSG_SIZE_AFTER = Size after: +MSG_COFF = Converting to AVR COFF: +MSG_EXTENDED_COFF = Converting to AVR Extended COFF: +MSG_FLASH = Creating load file for Flash: +MSG_EEPROM = Creating load file for EEPROM: +MSG_EXTENDED_LISTING = Creating Extended Listing: +MSG_SYMBOL_TABLE = Creating Symbol Table: +MSG_LINKING = Linking: +MSG_COMPILING = Compiling C: +MSG_COMPILING_CPP = Compiling C++: +MSG_ASSEMBLING = Assembling: +MSG_CLEANING = Cleaning project: +MSG_CREATING_LIBRARY = Creating library: + + + + +# Define all object files. +OBJ = $(SRC:%.c=$(OBJDIR)/%.o) $(CPPSRC:%.cpp=$(OBJDIR)/%.o) $(ASRC:%.S=$(OBJDIR)/%.o) + +# Define all listing files. +LST = $(SRC:%.c=$(OBJDIR)/%.lst) $(CPPSRC:%.cpp=$(OBJDIR)/%.lst) $(ASRC:%.S=$(OBJDIR)/%.lst) + + +# Compiler flags to generate dependency files. +GENDEPFLAGS = -MMD -MP -MF .dep/$(@F).d + + +# Combine all necessary flags and optional flags. +# Add target processor to flags. +ALL_CFLAGS = -mmcu=$(MCU) -I. $(CFLAGS) $(GENDEPFLAGS) +ALL_CPPFLAGS = -mmcu=$(MCU) -I. -x c++ $(CPPFLAGS) $(GENDEPFLAGS) +ALL_ASFLAGS = -mmcu=$(MCU) -I. -x assembler-with-cpp $(ASFLAGS) + + + + + +# Default target. +all: begin gccversion sizebefore build sizeafter end + +# Change the build target to build a HEX file or a library. +build: elf hex eep lss sym bin +#build: lib + + +elf: $(TARGET).elf +hex: $(TARGET).hex +bin: $(TARGET).bin +eep: $(TARGET).eep +lss: $(TARGET).lss +sym: $(TARGET).sym +LIBNAME=lib$(TARGET).a +lib: $(LIBNAME) + + + +# Eye candy. +# AVR Studio 3.x does not check make's exit code but relies on +# the following magic strings to be generated by the compile job. +begin: + @echo + @echo $(MSG_BEGIN) + +end: + @echo $(MSG_END) + @echo + + +# Display size of file. +HEXSIZE = $(SIZE) --target=$(FORMAT) $(TARGET).hex +ELFSIZE = $(SIZE) --mcu=$(MCU) --format=avr $(TARGET).elf + +sizebefore: + @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_BEFORE); $(ELFSIZE); \ + 2>/dev/null; echo; fi + +sizeafter: + @if test -f $(TARGET).elf; then echo; echo $(MSG_SIZE_AFTER); $(ELFSIZE); \ + 2>/dev/null; echo; fi + + + +# Display compiler version information. +gccversion : + @$(CC) --version + + + +# Program the device. +program: $(TARGET).hex $(TARGET).eep + $(AVRDUDE) $(AVRDUDE_FLAGS) $(AVRDUDE_WRITE_FLASH) $(AVRDUDE_WRITE_EEPROM) + + +# Generate avr-gdb config/init file which does the following: +# define the reset signal, load the target file, connect to target, and set +# a breakpoint at main(). +gdb-config: + @$(REMOVE) $(GDBINIT_FILE) + @echo define reset >> $(GDBINIT_FILE) + @echo SIGNAL SIGHUP >> $(GDBINIT_FILE) + @echo end >> $(GDBINIT_FILE) + @echo file $(TARGET).elf >> $(GDBINIT_FILE) + @echo target remote $(DEBUG_HOST):$(DEBUG_PORT) >> $(GDBINIT_FILE) +ifeq ($(DEBUG_BACKEND),simulavr) + @echo load >> $(GDBINIT_FILE) +endif + @echo break main >> $(GDBINIT_FILE) + +debug: gdb-config $(TARGET).elf +ifeq ($(DEBUG_BACKEND), avarice) + @echo Starting AVaRICE - Press enter when "waiting to connect" message displays. + @$(WINSHELL) /c start avarice --jtag $(JTAG_DEV) --erase --program --file \ + $(TARGET).elf $(DEBUG_HOST):$(DEBUG_PORT) + @$(WINSHELL) /c pause + +else + @$(WINSHELL) /c start simulavr --gdbserver --device $(MCU) --clock-freq \ + $(DEBUG_MFREQ) --port $(DEBUG_PORT) +endif + @$(WINSHELL) /c start avr-$(DEBUG_UI) --command=$(GDBINIT_FILE) + + + + +# Convert ELF to COFF for use in debugging / simulating in AVR Studio or VMLAB. +COFFCONVERT = $(OBJCOPY) --debugging +COFFCONVERT += --change-section-address .data-0x800000 +COFFCONVERT += --change-section-address .bss-0x800000 +COFFCONVERT += --change-section-address .noinit-0x800000 +COFFCONVERT += --change-section-address .eeprom-0x810000 + + + +coff: $(TARGET).elf + @echo + @echo $(MSG_COFF) $(TARGET).cof + $(COFFCONVERT) -O coff-avr $< $(TARGET).cof + + +extcoff: $(TARGET).elf + @echo + @echo $(MSG_EXTENDED_COFF) $(TARGET).cof + $(COFFCONVERT) -O coff-ext-avr $< $(TARGET).cof + + + +# Create final output files (.hex, .eep) from ELF output file. +%.hex: %.elf + @echo + @echo $(MSG_FLASH) $@ + $(OBJCOPY) -O $(FORMAT) -R .eeprom $< $@ + +%.bin: %.elf + $(OBJCOPY) -O binary $< $@ + +%.eep: %.elf + @echo + @echo $(MSG_EEPROM) $@ + -$(OBJCOPY) -j .eeprom --set-section-flags=.eeprom="alloc,load" \ + --change-section-lma .eeprom=0 --no-change-warnings -O $(FORMAT) $< $@ || exit 0 + +# Create extended listing file from ELF output file. +%.lss: %.elf + @echo + @echo $(MSG_EXTENDED_LISTING) $@ + $(OBJDUMP) -h -S $< > $@ + +# Create a symbol table from ELF output file. +%.sym: %.elf + @echo + @echo $(MSG_SYMBOL_TABLE) $@ + $(NM) -n $< > $@ + + + +# Create library from object files. +.SECONDARY : $(TARGET).a +.PRECIOUS : $(OBJ) +%.a: $(OBJ) + @echo + @echo $(MSG_CREATING_LIBRARY) $@ + $(AR) $@ $(OBJ) + + +# Link: create ELF output file from object files. +.SECONDARY : $(TARGET).elf +.PRECIOUS : $(OBJ) +%.elf: $(OBJ) + @echo + @echo $(MSG_LINKING) $@ + $(CC) $(ALL_CFLAGS) $^ --output $@ $(LDFLAGS) + + +# Compile: create object files from C source files. +$(OBJDIR)/%.o : %.c + @echo + @echo $(MSG_COMPILING) $< + $(CC) -c $(ALL_CFLAGS) $< -o $@ + + +# Compile: create object files from C++ source files. +$(OBJDIR)/%.o : %.cpp + @echo + @echo $(MSG_COMPILING_CPP) $< + $(CC) -c $(ALL_CPPFLAGS) $< -o $@ + + +# Compile: create assembler files from C source files. +%.s : %.c + $(CC) -S $(ALL_CFLAGS) $< -o $@ + + +# Compile: create assembler files from C++ source files. +%.s : %.cpp + $(CC) -S $(ALL_CPPFLAGS) $< -o $@ + + +# Assemble: create object files from assembler source files. +$(OBJDIR)/%.o : %.S + @echo + @echo $(MSG_ASSEMBLING) $< + $(CC) -c $(ALL_ASFLAGS) $< -o $@ + + +# Create preprocessed source for use in sending a bug report. +%.i : %.c + $(CC) -E -mmcu=$(MCU) -I. $(CFLAGS) $< -o $@ + + +# Target: clean project. +clean: begin clean_list end + +clean_list : + @echo + @echo $(MSG_CLEANING) + $(REMOVE) $(TARGET).hex + $(REMOVE) $(TARGET).eep + $(REMOVE) $(TARGET).cof + $(REMOVE) $(TARGET).elf + $(REMOVE) $(TARGET).map + $(REMOVE) $(TARGET).sym + $(REMOVE) $(TARGET).lss + $(REMOVE) $(SRC:%.c=$(OBJDIR)/%.o) + $(REMOVE) $(SRC:%.c=$(OBJDIR)/%.lst) + $(REMOVE) $(SRC:.c=.s) + $(REMOVE) $(SRC:.c=.d) + $(REMOVE) $(SRC:.c=.i) + $(REMOVEDIR) .dep + + +# Create object files directory +$(shell mkdir $(OBJDIR) 2>/dev/null) + + +# Include the dependency files. +-include $(shell mkdir .dep 2>/dev/null) $(wildcard .dep/*) + + +# Listing of phony targets. +.PHONY : all begin finish end sizebefore sizeafter gccversion \ +build elf hex eep lss sym coff extcoff \ +clean clean_list program debug gdb-config + + + + diff --git a/Multiprotocol/Multiprotocol.cpp.xmega b/Multiprotocol/Multiprotocol.cpp.xmega new file mode 100644 index 0000000..87ebf73 --- /dev/null +++ b/Multiprotocol/Multiprotocol.cpp.xmega @@ -0,0 +1,476 @@ +#define ARDUINO_AVR_PRO 1 +//#define __AVR_ATmega328P__ 1 + +#define XMEGA 1 + +#include +#include +#include + +static void protocol_init(void) ; +static void update_aux_flags(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) ; + + +extern void NRF24L01_Reset(void ) ; +extern void A7105_Reset(void ) ; +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 void randomSeed(unsigned int seed) ; +extern long random(long howbig) ; +extern long map(long x, long in_min, long in_max, long out_min, long out_max) ; + +extern uint32_t millis(void) ; +extern uint32_t micros(void) ; +extern void delayMicroseconds(uint16_t x) ; +extern void init(void) ; + +extern int analogRead(uint8_t pin) ; + +#define A6 20 +#define A7 21 + +#define yield() + +//void _delay_us( uint16_t x ) +//{ +// delayMicroseconds( x ) ; +//} + +#define clockCyclesPerMicrosecond() ( F_CPU / 1000000L ) +#define clockCyclesToMicroseconds(a) ( (a) / clockCyclesPerMicrosecond() ) + +// the prescaler is set so that timer0 ticks every 64 clock cycles, and the +// the overflow handler is called every 256 ticks. +#define MICROSECONDS_PER_TIMER0_OVERFLOW (clockCyclesToMicroseconds(64 * 256)) + +// the whole number of milliseconds per timer0 overflow +#define MILLIS_INC (MICROSECONDS_PER_TIMER0_OVERFLOW / 1000) + +// the fractional number of milliseconds per timer0 overflow. we shift right +// by three to fit these numbers into a byte. (for the clock speeds we care +// about - 8 and 16 MHz - this doesn't lose precision.) +#define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3) +#define FRACT_MAX (1000 >> 3) + +volatile unsigned long timer0_overflow_count = 0; +volatile unsigned long timer0_millis = 0; +static unsigned char timer0_fract = 0; + + + +//void chipInit() +//{ +// PR.PRGEN = 0 ; // RTC and event system active +// PR.PRPC = 0 ; // No power reduction port C +// PR.PRPD = 0 ; // No power reduction port D +// PMIC.CTRL = 7 ; +// OSC.CTRL = 0xC3 ; // unclear +// OSC.CTRL |= 0x08 ; // Enable external oscillator +// while( ( OSC.STATUS & 0x08 ) == 0 ) ; // Wait for ext osc to be ready +// OSC.PLLCTRL = 0xC2 ; // Ext. Osc times 2 +// OSC.CTRL |= 0x10 ; // Enable PLL +// while( ( OSC.STATUS & 0x10 ) == 0 ) ; // Wait PLL ready +// CPU_CCP = 0xD8 ; // 0x34 +// CLK.CTRL = 0 ; // Select 2MHz internal clock +// CPU_CCP = 0xD8 ; // 0x34 +// CLK.CTRL = 0x04 ; // Select PLL as clock (32MHz) +// PORTD.OUTSET = 0x17 ; +// PORTD.DIRSET = 0xB2 ; +// PORTD.DIRCLR = 0x4D ; +// PORTD.PIN0CTRL = 0x18 ; +// PORTD.PIN2CTRL = 0x18 ; +// PORTE.DIRSET = 0x01 ; +// PORTE.DIRCLR = 0x02 ; +// PORTE.OUTSET = 0x01 ; +// PORTA.DIRCLR = 0xFF ; +// PORTA.PIN0CTRL = 0x18 ; +// PORTA.PIN1CTRL = 0x18 ; +// PORTA.PIN2CTRL = 0x18 ; +// PORTA.PIN3CTRL = 0x18 ; +// PORTA.PIN4CTRL = 0x18 ; +// PORTA.PIN5CTRL = 0x18 ; +// PORTA.PIN6CTRL = 0x18 ; +// PORTA.PIN7CTRL = 0x18 ; +// PORTC.DIRSET = 0x20 ; +// PORTC.OUTCLR = 0x20 ; +// SPID.CTRL = 0x51 ; +// PORTC.OUTSET = 0x08 ; +// PORTC.DIRSET = 0x08 ; +// PORTC.PIN3CTRL = 0x18 ; +// PORTC.PIN2CTRL = 0x18 ; +// USARTC0.BAUDCTRLA = 19 ; +// USARTC0.BAUDCTRLB = 0 ; +// USARTC0.CTRLB = 0x18 ; +// USARTC0.CTRLA = (USARTC0.CTRLA & 0xCF) | 0x10 ; +// USARTC0.CTRLC = 0x03 ; + +// TCC0.CTRLB = 0 ; +// TCC0.CTRLC = 0 ; +// TCC0.CTRLD = 0 ; +// TCC0.CTRLE = 0 ; +// TCC0.INTCTRLA = 0x01 ; +// TCC0.INTCTRLB = 0 ; +// TCC0.PER = 0x00FF ; +// TCC0.CTRLA = 4 ; + +// TCC1.CTRLB = 0 ; +// TCC1.CTRLC = 0 ; +// TCC1.CTRLD = 0 ; +// TCC1.CTRLE = 0 ; +// TCC1.INTCTRLA = 0x03 ; +// TCC1.INTCTRLB = 0 ; +// TCC1.PER = 0xFFFF ; +// TCC1.CNT = 0 ; +// TCC1.CTRLA = 4 ; + +// TCD0.CTRLA = 4 ; +// TCD0.INTCTRLA = 0x03 ; +// TCD0.PER = 0x02ED ; + +//// L0EDB() ; + +// NVM.CTRLB &= 0xF7 ; // No EEPROM mapping +//} + + + +ISR(TCC0_OVF_vect) +{ + // copy these to local variables so they can be stored in registers + // (volatile variables must be read from memory on every access) + unsigned long m = timer0_millis; + unsigned char f = timer0_fract; + + m += MILLIS_INC; + f += FRACT_INC; + if (f >= FRACT_MAX) { + f -= FRACT_MAX; + m += 1; + } + + timer0_fract = f; + timer0_millis = m; + timer0_overflow_count++; +} + +unsigned long millis() +{ + unsigned long m; + uint8_t oldSREG = SREG; + + // disable interrupts while we read timer0_millis or we might get an + // inconsistent value (e.g. in the middle of a write to timer0_millis) + cli(); + m = timer0_millis; + SREG = oldSREG; + + return m; +} + +unsigned long micros() +{ + unsigned long m; + uint8_t oldSREG = SREG, t; + + cli(); + m = timer0_overflow_count; + t = TCC0.CNT ; + + if ((TCC0.INTFLAGS & TC0_OVFIF_bm) && (t < 255)) + m++; + + SREG = oldSREG; + + return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond()); +} + +void delay(unsigned long ms) +{ + uint16_t start = (uint16_t)micros(); + + while (ms > 0) { + yield(); + if (((uint16_t)micros() - start) >= 1000) { + ms--; + start += 1000; + } + } +} + +/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */ +void delayMicroseconds(unsigned int us) +{ + // calling avrlib's delay_us() function with low values (e.g. 1 or + // 2 microseconds) gives delays longer than desired. + //delay_us(us); +#if F_CPU >= 20000000L + // for the 20 MHz clock on rare Arduino boards + + // for a one-microsecond delay, simply wait 2 cycle and return. The overhead + // of the function call yields a delay of exactly a one microsecond. + __asm__ __volatile__ ( + "nop" "\n\t" + "nop"); //just waiting 2 cycle + if (--us == 0) + return; + + // the following loop takes a 1/5 of a microsecond (4 cycles) + // per iteration, so execute it five times for each microsecond of + // delay requested. + us = (us<<2) + us; // x5 us + + // account for the time taken in the preceeding commands. + us -= 2; + +#elif F_CPU >= 16000000L + // for the 16 MHz clock on most Arduino boards + + // for a one-microsecond delay, simply return. the overhead + // of the function call yields a delay of approximately 1 1/8 us. + if (--us == 0) + return; + + // the following loop takes a quarter of a microsecond (4 cycles) + // per iteration, so execute it four times for each microsecond of + // delay requested. + us <<= 2; + + // account for the time taken in the preceeding commands. + us -= 2; +#else + // for the 8 MHz internal clock on the ATmega168 + + // for a one- or two-microsecond delay, simply return. the overhead of + // the function calls takes more than two microseconds. can't just + // subtract two, since us is unsigned; we'd overflow. + if (--us == 0) + return; + if (--us == 0) + return; + + // the following loop takes half of a microsecond (4 cycles) + // per iteration, so execute it twice for each microsecond of + // delay requested. + us <<= 1; + + // partially compensate for the time taken by the preceeding commands. + // we can't subtract any more than this or we'd overflow w/ small delays. + us--; +#endif + + // busy wait + __asm__ __volatile__ ( + "1: sbiw %0,1" "\n\t" // 2 cycles + "brne 1b" : "=w" (us) : "0" (us) // 2 cycles + ); +} + +#ifndef cbi +#define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) +#endif +#ifndef sbi +#define sbi(sfr, bit) (_SFR_BYTE(sfr) |= _BV(bit)) +#endif + + +void init() +{ + // this needs to be called before setup() or some functions won't + // work there + + // Enable external oscillator (16MHz) + OSC.XOSCCTRL = OSC_FRQRANGE_12TO16_gc | OSC_XOSCSEL_XTAL_256CLK_gc ; + OSC.CTRL |= OSC_XOSCEN_bm ; + while( ( OSC.STATUS & OSC_XOSCRDY_bm ) == 0 ) + /* wait */ ; + // Enable PLL (*2 = 32MHz) + OSC.PLLCTRL = OSC_PLLSRC_XOSC_gc | 2 ; + OSC.CTRL |= OSC_PLLEN_bm ; + while( ( OSC.STATUS & OSC_PLLRDY_bm ) == 0 ) + /* wait */ ; + // Switch to PLL clock + CPU_CCP = 0xD8 ; + CLK.CTRL = CLK_SCLKSEL_RC2M_gc ; + CPU_CCP = 0xD8 ; + CLK.CTRL = CLK_SCLKSEL_PLL_gc ; + + PMIC.CTRL = 7 ; // Enable all interrupt levels + sei(); + + // on the ATmega168, timer 0 is also used for fast hardware pwm + // (using phase-correct PWM would mean that timer 0 overflowed half as often + // resulting in different millis() behavior on the ATmega8 and ATmega168) +//#if defined(TCCR0A) && defined(WGM01) +// sbi(TCCR0A, WGM01); +// sbi(TCCR0A, WGM00); +//#endif + + +// TCC0 counts 0-255 at 4uS clock rate + EVSYS.CH2MUX = 0x80 + 0x07 ; // Prescaler of 128 + TCC0.CTRLB = 0 ; + TCC0.CTRLC = 0 ; + TCC0.CTRLD = 0 ; + TCC0.CTRLE = 0 ; + TCC0.INTCTRLA = 0x01 ; + TCC0.INTCTRLB = 0 ; + TCC0.PER = 0x00FF ; + TCC0.CTRLA = 0x0A ; + + +#if defined(ADCSRA) + // set a2d prescale factor to 128 + // 16 MHz / 128 = 125 KHz, inside the desired 50-200 KHz range. + // XXX: this will not work properly for other clock speeds, and + // this code should use F_CPU to determine the prescale factor. + sbi(ADCSRA, ADPS2); + sbi(ADCSRA, ADPS1); + sbi(ADCSRA, ADPS0); + + // enable a2d conversions + sbi(ADCSRA, ADEN); +#endif + + // the bootloader connects pins 0 and 1 to the USART; disconnect them + // here so they can be used as normal digital i/o; they will be + // reconnected in Serial.begin() +#if defined(UCSRB) + UCSRB = 0; +#elif defined(UCSR0B) + UCSR0B = 0; +#endif + + // PPM 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 ; + PORTA.PIN0CTRL = 0x18 ; + PORTA.PIN1CTRL = 0x18 ; + PORTA.PIN2CTRL = 0x18 ; + PORTA.PIN3CTRL = 0x18 ; + PORTA.PIN4CTRL = 0x18 ; + PORTA.PIN5CTRL = 0x18 ; + PORTA.PIN6CTRL = 0x18 ; + PORTA.PIN7CTRL = 0x18 ; +} + +#define DEFAULT 1 + +uint8_t analog_reference = DEFAULT; + +void analogReference(uint8_t mode) +{ + // can't actually set the register here because the default setting + // will connect AVCC and the AREF pin, which would cause a short if + // there's something connected to AREF. + analog_reference = mode; +} + +int analogRead(uint8_t pin) +{ + uint8_t low, high; + +#if defined(analogPinToChannel) +#if defined(__AVR_ATmega32U4__) + if (pin >= 18) pin -= 18; // allow for channel or pin numbers +#endif + pin = analogPinToChannel(pin); +#elif defined(__AVR_ATmega1280__) || defined(__AVR_ATmega2560__) + if (pin >= 54) pin -= 54; // allow for channel or pin numbers +#elif defined(__AVR_ATmega32U4__) + if (pin >= 18) pin -= 18; // allow for channel or pin numbers +#elif defined(__AVR_ATmega1284__) || defined(__AVR_ATmega1284P__) || defined(__AVR_ATmega644__) || defined(__AVR_ATmega644A__) || defined(__AVR_ATmega644P__) || defined(__AVR_ATmega644PA__) + if (pin >= 24) pin -= 24; // allow for channel or pin numbers +#else + if (pin >= 14) pin -= 14; // allow for channel or pin numbers +#endif + +#if defined(ADCSRB) && defined(MUX5) + // the MUX5 bit of ADCSRB selects whether we're reading from channels + // 0 to 7 (MUX5 low) or 8 to 15 (MUX5 high). + ADCSRB = (ADCSRB & ~(1 << MUX5)) | (((pin >> 3) & 0x01) << MUX5); +#endif + + // set the analog reference (high two bits of ADMUX) and select the + // channel (low 4 bits). this also sets ADLAR (left-adjust result) + // to 0 (the default). +#if defined(ADMUX) + ADMUX = (analog_reference << 6) | (pin & 0x07); +#endif + + // without a delay, we seem to read from the wrong channel + //delay(1); + +#if defined(ADCSRA) && defined(ADCL) + // start the conversion + sbi(ADCSRA, ADSC); + + // ADSC is cleared when the conversion finishes + while (bit_is_set(ADCSRA, ADSC)); + + // we have to read ADCL first; doing so locks both ADCL + // and ADCH until ADCH is read. reading ADCL second would + // cause the results of each conversion to be discarded, + // as ADCL and ADCH would be locked when it completed. + low = ADCL; + high = ADCH; +#else + // we dont have an ADC, return 0 + low = 0; + high = 0; +#endif + + // combine the two bytes + return (high << 8) | low; +} + + + + +void A7105_Reset() +{ +} +void CC2500_Reset() +{ +} +void NRF24L01_Reset() +{ +} + + +#include "Multiprotocol.ino" + +#include "cyrf6936_SPI.ino" +#include "DSM2_cyrf6936.ino" + +#include "Telemetry.ino" + + +int main(void) +{ + init() ; + setup() ; + for(;;) + { + loop() ; + } +} + diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 41d3ac9..721ae05 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -14,12 +14,14 @@ */ // Check selected board type +#ifndef XMEGA #if not defined(ARDUINO_AVR_PRO) && not defined(ARDUINO_AVR_MINI) #error You must select the board type "Arduino Pro or Pro Mini" or "Arduino Mini" #endif #if F_CPU != 16000000L || not defined(__AVR_ATmega328P__) #error You must select the processor type "ATmega328(5V, 16MHz)" #endif +#endif //****************** // Protocols @@ -46,7 +48,8 @@ enum PROTOCOLS MODE_MT99XX=17, // =>NRF24L01 MODE_MJXQ=18, // =>NRF24L01 MODE_SHENQI=19, // =>NRF24L01 - MODE_FY326=20 // =>NRF24L01 + MODE_FY326=20, // =>NRF24L01 + MODE_SFHSS=21 // =>CC2500 }; enum Flysky @@ -114,6 +117,12 @@ enum MJXQ H26D = 3 }; +enum FRSKYX +{ + CH_16 = 0, + CH_8 = 1, +}; + #define NONE 0 #define P_HIGH 1 #define P_LOW 0 @@ -137,7 +146,11 @@ struct PPM_Parameters #define LED_pin 13 //Promini original led on B5 // #define PPM_pin 3 //PPM -D3 +#ifdef XMEGA +#define SDI_pin 6 //SDIO-D6 +#else #define SDI_pin 5 //SDIO-D5 +#endif #define SCLK_pin 4 //SCK-D4 #define CS_pin 2 //CS-D2 #define SDO_pin 6 //D6 @@ -145,23 +158,51 @@ struct PPM_Parameters #define CTRL1 1 //C1 (A1) #define CTRL2 2 //C2 (A2) // +#ifdef XMEGA +#define CTRL1_on +#define CTRL1_off +// +#define CTRL2_on +#define CTRL2_off +#else #define CTRL1_on PORTC |= _BV(1) #define CTRL1_off PORTC &= ~_BV(1) // #define CTRL2_on PORTC |= _BV(2) #define CTRL2_off PORTC &= ~_BV(2) +#endif // +#ifdef XMEGA +#define CS_on PORTD.OUTSET = _BV(4) //D4 +#define CS_off PORTD.OUTCLR = _BV(4) //D4 +#else #define CS_on PORTD |= _BV(2) //D2 #define CS_off PORTD &= ~_BV(2) //D2 +#endif // +#ifdef XMEGA +#define SCK_on PORTD.OUTSET = _BV(7) //D7 +#define SCK_off PORTD.OUTCLR = _BV(7) //D7 +#else #define SCK_on PORTD |= _BV(4) //D4 #define SCK_off PORTD &= ~_BV(4) //D4 +#endif // +#ifdef XMEGA +#define SDI_on PORTD.OUTSET = _BV(5) //D5 +#define SDI_off PORTD.OUTCLR = _BV(5) //D5 +#else #define SDI_on PORTD |= _BV(5) //D5 #define SDI_off PORTD &= ~_BV(5) //D5 +#endif +#ifdef XMEGA +#define SDI_1 (PORTD.IN & (1< 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No @@ -475,6 +551,9 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- X600 1 X800 2 H26D 3 + sub_protocol==FRSKYX + CH_16 0 + CH_8 1 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 cd62a62..d9be20b 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -4,7 +4,7 @@ http://www.rcgroups.com/forums/showthread.php?t=2165676 https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/edit/master/README.md - Thanks to PhracturedBlue, Hexfet, Goebish and all protocol developers + Thanks to PhracturedBlue, Hexfet, Goebish, Victzh and all protocol developers Ported from deviation firmware This project is free software: you can redistribute it and/or modify @@ -25,6 +25,8 @@ #include #include "Multiprotocol.h" +//#define DEBUG_TX + //Multiprotocol module configuration file #include "_Config.h" @@ -68,6 +70,10 @@ uint32_t state; uint8_t len; uint8_t RX_num; +#if defined(FRSKYX_CC2500_INO) || defined(SFHSS_CC2500_INO) +uint8_t calData[48][3]; +#endif + // Mode_select variables uint8_t mode_select; uint8_t protocol_flags=0,protocol_flags2=0; @@ -77,7 +83,7 @@ volatile uint16_t PPM_data[NUM_CHN]; // Serial variables #define RXBUFFER_SIZE 25 -#define TXBUFFER_SIZE 12 +#define TXBUFFER_SIZE 20 volatile uint8_t rx_buff[RXBUFFER_SIZE]; volatile uint8_t rx_ok_buff[RXBUFFER_SIZE]; volatile uint8_t tx_buff[TXBUFFER_SIZE]; @@ -94,8 +100,8 @@ uint8_t prev_protocol=0; uint8_t pkt[MAX_PKT];//telemetry receiving packets #if defined(TELEMETRY) uint8_t pktt[MAX_PKT];//telemetry receiving packets - volatile uint8_t tx_head; - volatile uint8_t tx_tail; + volatile uint8_t tx_head=0; + volatile uint8_t tx_tail=0; uint8_t v_lipo; int16_t RSSI_dBm; //const uint8_t RSSI_offset=72;//69 71.72 values db @@ -111,6 +117,20 @@ static void CheckTimer(uint16_t (*cb)(void)); // Init void setup() { +#ifdef XMEGA + PORTD.OUTSET = 0x17 ; + PORTD.DIRSET = 0xB2 ; + PORTD.DIRCLR = 0x4D ; + PORTD.PIN0CTRL = 0x18 ; + PORTD.PIN2CTRL = 0x18 ; + PORTE.DIRSET = 0x01 ; + PORTE.DIRCLR = 0x02 ; + PORTE.OUTSET = 0x01 ; + + for ( uint8_t count = 0 ; count < 20 ; count += 1 ) + asm("nop") ; + PORTE.OUTCLR = 0x01 ; +#else // General pinout DDRD = (1<B2,B3,B4,C0 + mode_select = MODE_SERIAL ; +#else mode_select=0x0F - ( ( (PINB>>2)&0x07 ) | ( (PINC<<3)&0x08) );//encoder dip switches 1,2,4,8=>B2,B3,B4,C0 +#endif //********************************** //mode_select=1; // here to test PPM //********************************** @@ -179,9 +224,12 @@ void setup() protocol_init(); +#ifndef XMEGA //Configure PPM interrupt EICRA |=(1< micros()) - { // Callback did not took more than requested time for next callback - if(next_callback>32000) - { // next_callback should not be more than 32767 so we will wait here... - delayMicroseconds(next_callback-2000); - cli(); // disable global int - OCR1A=TCNT1+4000; - sei(); // enable global int +#endif + do + { + next_callback=cb(); + while(next_callback>4000) + { // start to wait here as much as we can... + next_callback=next_callback-2000; + cli(); // disable global int +#ifdef XMEGA + TCC1.CCA +=2000*2; // set compare A for callback + TCC1.INTFLAGS = TC1_CCAIF_bm ; // clear compare A=callback flag + sei(); // enable global int + while((TCC1.INTFLAGS & TC1_CCAIF_bm) == 0); // wait 2ms... +#else + OCR1A+=2000*2; // set compare A for callback + TIFR1=(1<=TXBUFFER_SIZE) tx_head=0; tx_buff[tx_head]=data; - sei(); // enable global int +#ifdef XMEGA + USARTC0.CTRLA = (USARTC0.CTRLA & 0xFC) | 0x01 ; +#else UCSR0B |= (1< UBRR0H = UBRRH_VALUE; UBRR0L = UBRRL_VALUE; @@ -610,12 +717,25 @@ static void Mprotocol_serial_init() UDR0; //enable reception and RC complete interrupt UCSR0B = (1<RXBUFFER_SIZE) { // A full frame has been received - TIMSK1 &=~(1<=TXBUFFER_SIZE)//head - t=0; - UDR0=tx_buff[t]; - tx_tail=t; + if(++tx_tail>=TXBUFFER_SIZE)//head + tx_tail=0; +#ifdef XMEGA + USARTC0.DATA = tx_buff[tx_tail] ; +#else + UDR0=tx_buff[tx_tail]; +#endif } - if (t == tx_head) + if (tx_tail == tx_head) +#ifdef XMEGA + USARTC0.CTRLA &= ~0x03 ; +#else UCSR0B &= ~(1<. + */ +// Last sync with main deviation/sfhss_cc2500.c dated 2016-03-23 + +#if defined(SFHSS_CC2500_INO) + +#include "iface_cc2500.h" + +//#define SFHSS_USE_TUNE_FREQ +#define SFHSS_COARSE 0 + +#define SFHSS_PACKET_LEN 13 +#define SFHSS_TX_ID_LEN 2 + +uint8_t fhss_code; // 0-27 + +enum { + SFHSS_START = 0x101, + SFHSS_CAL = 0x102, + SFHSS_TUNE = 0x103, + SFHSS_DATA1 = 0x02, + SFHSS_DATA2 = 0x0b +}; + +#define SFHSS_FREQ0_VAL 0xC4 + +// Some important initialization parameters, all others are either default, +// or not important in the context of transmitter +// IOCFG2 2F - GDO2_INV=0 GDO2_CFG=2F - HW0 +// IOCFG1 2E - GDO1_INV=0 GDO1_CFG=2E - High Impedance +// IOCFG0 2F - GDO0 same as GDO2, TEMP_SENSOR_ENABLE=off +// FIFOTHR 07 - 33 decimal TX threshold +// SYNC1 D3 +// SYNC0 91 +// PKTLEN 0D - Packet length, 0D bytes +// PKTCTRL1 04 - APPEND_STATUS on, all other are receive parameters - irrelevant +// PKTCTRL0 0C - No whitening, use FIFO, CC2400 compatibility on, use CRC, fixed packet length +// ADDR 29 +// CHANNR 10 +// FSCTRL1 06 - IF 152343.75Hz, see page 65 +// FSCTRL0 00 - zero freq offset +// FREQ2 5C - synthesizer frequency 2399999633Hz for 26MHz crystal, ibid +// FREQ1 4E +// FREQ0 C4 +// MDMCFG4 7C - CHANBW_E - 01, CHANBW_M - 03, DRATE_E - 0C. Filter bandwidth = 232142Hz +// MDMCFG3 43 - DRATE_M - 43. Data rate = 128143bps +// MDMCFG2 83 - disable DC blocking, 2-FSK, no Manchester code, 15/16 sync bits detected (irrelevant for TX) +// MDMCFG1 23 - no FEC, 4 preamble bytes, CHANSPC_E - 03 +// MDMCFG0 3B - CHANSPC_M - 3B. Channel spacing = 249938Hz (each 6th channel used, resulting in spacing of 1499628Hz) +// DEVIATN 44 - DEVIATION_E - 04, DEVIATION_M - 04. Deviation = 38085.9Hz +// MCSM2 07 - receive parameters, default, irrelevant +// MCSM1 0C - no CCA (transmit always), when packet received stay in RX, when sent go to IDLE +// MCSM0 08 - no autocalibration, PO_TIMEOUT - 64, no pin radio control, no forcing XTAL to stay in SLEEP +// FOCCFG 1D - not interesting, Frequency Offset Compensation +// FREND0 10 - PA_POWER = 0 +const PROGMEM uint8_t SFHSS_init_values[] = { + /* 00 */ 0x2F, 0x2E, 0x2F, 0x07, 0xD3, 0x91, 0x0D, 0x04, + /* 08 */ 0x0C, 0x29, 0x10, 0x06, 0x00, 0x5C, 0x4E, SFHSS_FREQ0_VAL + SFHSS_COARSE, + /* 10 */ 0x7C, 0x43, 0x83, 0x23, 0x3B, 0x44, 0x07, 0x0C, + /* 18 */ 0x08, 0x1D, 0x1C, 0x43, 0x40, 0x91, 0x57, 0x6B, + /* 20 */ 0xF8, 0xB6, 0x10, 0xEA, 0x0A, 0x11, 0x11 +}; + +static void __attribute__((unused)) SFHSS_tune_chan() +{ + CC2500_Strobe(CC2500_SIDLE); + CC2500_WriteReg(CC2500_0A_CHANNR, rf_ch_num*6+16); + CC2500_Strobe(CC2500_SCAL); +} + +static void __attribute__((unused)) SFHSS_tune_chan_fast() +{ + CC2500_Strobe(CC2500_SIDLE); + CC2500_WriteReg(CC2500_0A_CHANNR, rf_ch_num*6+16); + CC2500_WriteRegisterMulti(CC2500_23_FSCAL3, calData[rf_ch_num], 3); + _delay_us(6); +} + +#ifdef USE_SFHSS_TUNE_FREQ +static void __attribute__((unused)) SFHSS_tune_freq() { +// May be we'll need this tuning routine - some receivers are more sensitive to +// frequency impreciseness, and though CC2500 has a procedure to handle it it +// may not be applied in receivers, so we need to compensate for it on TX + CC2500_WriteReg(CC2500_0C_FSCTRL0, option); + CC2500_WriteReg(CC2500_0F_FREQ0, SFHSS_FREQ0_VAL + SFHSS_COARSE); +} +#endif + +static void __attribute__((unused)) SFHSS_rf_init() +{ + CC2500_Reset(); + CC2500_Strobe(CC2500_SIDLE); + + for (uint8_t i = 0; i < 39; ++i) + CC2500_WriteReg(i, pgm_read_byte_near(&SFHSS_init_values[i])); + //CC2500_WriteRegisterMulti(CC2500_00_IOCFG2, init_values, sizeof(init_values)); + + CC2500_SetTxRxMode(TX_EN); + CC2500_SetPower(); +} + +static void __attribute__((unused)) SFHSS_calc_next_chan() +{ + rf_ch_num += fhss_code + 2; + if (rf_ch_num > 29) { + if (rf_ch_num < 31) rf_ch_num += fhss_code + 2; + rf_ch_num -= 31; + } +} + +// Channel values are 10-bit values between 86 and 906, 496 is the middle. +static uint16_t __attribute__((unused)) SFHSS_convert_channel(uint8_t num) +{ + return (uint16_t) (map(limit_channel_100(num),PPM_MIN_100,PPM_MAX_100,86,906)); +} + + +static void __attribute__((unused)) SFHSS_build_data_packet() +{ +#define spacer1 0b10 +#define spacer2 (spacer1 << 4) + uint8_t ch_offset = state == SFHSS_DATA1 ? 0 : 4; + const uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4}; + + u16 ch1 = SFHSS_convert_channel(ch[ch_offset+0]); + u16 ch2 = SFHSS_convert_channel(ch[ch_offset+1]); + u16 ch3 = SFHSS_convert_channel(ch[ch_offset+2]); + u16 ch4 = SFHSS_convert_channel(ch[ch_offset+3]); + + packet[0] = 0x81; // can be 80, 81, 81 for Orange, only 81 for XK + packet[1] = rx_tx_addr[0]; + packet[2] = rx_tx_addr[1]; + packet[3] = 0; + packet[4] = 0; + packet[5] = (rf_ch_num << 3) | spacer1 | ((ch1 >> 9) & 0x01); + packet[6] = (ch1 >> 1); + packet[7] = (ch1 << 7) | spacer2 | ((ch2 >> 5) & 0b11111); + packet[8] = (ch2 << 3) | spacer1 | ((ch3 >> 9) & 0x01); + packet[9] = (ch3 >> 1); + packet[10] = (ch3 << 7) | spacer2 | ((ch4 >> 5) & 0b11111); + packet[11] = (ch4 << 3) | ((fhss_code >> 2) & 0b111); + packet[12] = (fhss_code << 6) | state; +} + +static void __attribute__((unused)) SFHSS_send_packet() +{ + SFHSS_tune_chan_fast(); + CC2500_WriteData(packet, SFHSS_PACKET_LEN); +} + +uint16_t ReadSFHSS() +{ + switch(state) + { + case SFHSS_START: + rf_ch_num = 0; + SFHSS_tune_chan(); + state = SFHSS_CAL; + return 2000; + case SFHSS_CAL: + CC2500_ReadRegisterMulti(CC2500_23_FSCAL3, calData[rf_ch_num], 3); + if (++rf_ch_num < 30) + SFHSS_tune_chan(); + else + { + rf_ch_num = 0; + state = SFHSS_DATA1; + } + return 2000; + + /* Work cycle, 6.8ms, second packet 1.65ms after first */ + case SFHSS_DATA1: + SFHSS_build_data_packet(); + SFHSS_send_packet(); + state = SFHSS_DATA2; + return 1650; + case SFHSS_DATA2: + SFHSS_build_data_packet(); + SFHSS_send_packet(); + SFHSS_calc_next_chan(); + state = SFHSS_TUNE; + return 2000; + case SFHSS_TUNE: + CC2500_SetPower(); + state = SFHSS_DATA1; + return 3150; + /* + case SFHSS_DATA1: + SFHSS_build_data_packet(); + SFHSS_send_packet(); + state = SFHSS_DATA2; + return 1650; + case SFHSS_DATA2: + SFHSS_build_data_packet(); + SFHSS_send_packet(); + state = SFHSS_CAL2; + return 500; + case SFHSS_CAL2: + SFHSS_tune_freq(); + // CC2500_SetPower(); + SFHSS_calc_next_chan(); + SFHSS_tune_chan(); + state = SFHSS_DATA1; + return 4650; + */ + } + return 0; +} + +// Generate internal id +static void __attribute__((unused)) SFHSS_get_tx_id() +{ + uint32_t fixed_id; + // Some receivers (Orange) behaves better if they tuned to id that has + // no more than 6 consequtive zeos and ones + uint8_t run_count = 0; + // add guard for bit count + fixed_id = 1 ^ (MProtocol_id & 1); + for (uint8_t i = 0; i < 16; ++i) + { + fixed_id = (fixed_id << 1) | (MProtocol_id & 1); + MProtocol_id >>= 1; + // If two LS bits are the same + if ((fixed_id & 3) == 0 || (fixed_id & 3) == 3) + { + if (++run_count > 6) + { + fixed_id ^= 1; + run_count = 0; + } + } + else + run_count = 0; + } + // fixed_id = 0xBC11; + rx_tx_addr[0] = fixed_id >> 8; + rx_tx_addr[1] = fixed_id; +} + +uint16_t initSFHSS() +{ + SFHSS_get_tx_id(); + + randomSeed((uint32_t)analogRead(A6) << 10 | analogRead(A7)); + fhss_code=random(0xfefefefe)%28; // Initialize it to random 0-27 inclusive + + SFHSS_rf_init(); + state = SFHSS_START; + + return 10000; +} + +#endif \ No newline at end of file diff --git a/Multiprotocol/Telemetry.ino b/Multiprotocol/Telemetry.ino index 50553b4..1b90ceb 100644 --- a/Multiprotocol/Telemetry.ino +++ b/Multiprotocol/Telemetry.ino @@ -4,173 +4,216 @@ //************************************* #if defined TELEMETRY - #if defined FRSKYX_CC2500_INO - #define SPORT_TELEMETRY - #endif - #if defined FRSKY_CC2500_INO - #define HUB_TELEMETRY - #endif - #if defined SPORT_TELEMETRY - #define SPORT_TELEMETRY - #define SPORT_TIME 12000 - uint32_t last=0; - uint8_t sport_counter=0; - uint8_t RxBt=0; - uint8_t rssi; - uint8_t ADC2; - #endif - #if defined HUB_TELEMETRY - #define MAX_PKTX 10 - uint8_t pktx[MAX_PKTX]; - uint8_t index; - uint8_t prev_index; - uint8_t pass = 0; - #endif + +#if defined DSM2_CYRF6936_INO + #define DSM_TELEMETRY +#endif +#if defined FRSKYX_CC2500_INO + #define SPORT_TELEMETRY +#endif +#if defined FRSKY_CC2500_INO + #define HUB_TELEMETRY +#endif +#if defined SPORT_TELEMETRY + #define SPORT_TIME 12000 + #define FRSKY_SPORT_PACKET_SIZE 8 + uint32_t last = 0; + uint8_t sport_counter=0; + uint8_t RxBt = 0; + uint8_t rssi; + uint8_t sport = 0; +#endif +#if defined HUB_TELEMETRY #define USER_MAX_BYTES 6 - uint8_t frame[18]; - - void frskySendStuffed() + uint8_t prev_index; +#endif + +#define START_STOP 0x7e +#define BYTESTUFF 0x7d +#define STUFF_MASK 0x20 +#define MAX_PKTX 10 +uint8_t pktx[MAX_PKTX]; +uint8_t index; +uint8_t pass = 0; +uint8_t frame[18]; + +#if defined DSM_TELEMETRY +void DSM2_frame() +{ + Serial_write(0xAA); // Start + for (uint8_t i = 0; i < 17; i++) // RSSI value followed by 16 bytes of telemetry data + Serial_write(pkt[i]); +} +#endif + +void frskySendStuffed() +{ + Serial_write(START_STOP); + for (uint8_t i = 0; i < 9; i++) { - Serial_write(0x7E); - for (uint8_t i = 0; i < 9; i++) + if ((frame[i] == START_STOP) || (frame[i] == BYTESTUFF)) { - if ((frame[i] == 0x7e) || (frame[i] == 0x7d)) - { - Serial_write(0x7D); - frame[i] ^= 0x20; - } - Serial_write(frame[i]); + Serial_write(BYTESTUFF); + frame[i] ^= STUFF_MASK; } - Serial_write(0x7E); + Serial_write(frame[i]); } + Serial_write(START_STOP); +} + +void compute_RSSIdbm() +{ - void compute_RSSIdbm(){ - - RSSI_dBm = (((uint16_t)(pktt[len-2])*18)>>5); - if(pktt[len-2] >=128) - RSSI_dBm -= 82; - else - RSSI_dBm += 65; - } + RSSI_dBm = (((uint16_t)(pktt[len-2])*18)>>5); + if(pktt[len-2] >=128) + RSSI_dBm -= 82; + else + RSSI_dBm += 65; +} - void frsky_check_telemetry(uint8_t *pkt,uint8_t len) - { - if(pkt[1] != rx_tx_addr[3] || pkt[2] != rx_tx_addr[2] || len != pkt[0] + 3) - {//only packets with the required id and packet length - for(uint8_t i=3;i<6;i++) - pktt[i]=0; - return; - } - else - { - for (uint8_t i=3;i0) - telemetry_counter=(telemetry_counter+1)%32; - } - } - - void frsky_link_frame() - { - frame[0] = 0xFE; - if ((cur_protocol[0]&0x1F)==MODE_FRSKY) - { - compute_RSSIdbm(); - frame[1] = pktt[3]; - frame[2] = pktt[4]; - frame[3] = (uint8_t)RSSI_dBm; - frame[4] = pktt[5]*2; - } - else - if ((cur_protocol[0]&0x1F)==MODE_HUBSAN) - { - frame[1] = v_lipo*2; //v_lipo; common 0x2A=42/10=4.2V - frame[2] = frame[1]; - frame[3] = 0x00; - frame[4] = (uint8_t)RSSI_dBm; +void frsky_check_telemetry(uint8_t *pkt,uint8_t len) +{ + if(pkt[1] == rx_tx_addr[3] || pkt[2] == rx_tx_addr[2] || len ==(pkt[0] + 3)) + { + for (uint8_t i=3;i> 4 & 0x0f) == 0x08) + { + seq_last_sent = 8; + seq_last_rcvd = 0; + pass=0; + } + else + { + if ((pktt[5] >> 4 & 0x03) == (seq_last_rcvd + 1) % 4) + seq_last_rcvd = (seq_last_rcvd + 1) % 4; + else + pass=0;//reset if sequence wrong } - frame[5] = frame[6] = frame[7] = frame[8] = 0; + } +#endif + } +} + +void frsky_link_frame() +{ + frame[0] = 0xFE; + if ((cur_protocol[0]&0x1F)==MODE_FRSKY) + { + compute_RSSIdbm(); + frame[1] = pktt[3]; + frame[2] = pktt[4]; + frame[3] = (uint8_t)RSSI_dBm; + frame[4] = pktt[5]*2; + } + else + if ((cur_protocol[0]&0x1F)==MODE_HUBSAN) + { + frame[1] = v_lipo*2; //v_lipo; common 0x2A=42/10=4.2V + frame[2] = frame[1]; + frame[3] = 0x00; + frame[4] = (uint8_t)RSSI_dBm; + } + frame[5] = frame[6] = frame[7] = frame[8] = 0; + frskySendStuffed(); +} + +#if defined HUB_TELEMETRY +void frsky_user_frame() +{ + uint8_t indexx = 0, c=0, j=8, n=0, i; + + if(pktt[6]>0 && pktt[6]<=10) + {//only valid hub frames + frame[0] = 0xFD; + frame[2] = pktt[7]; + switch(pass) + { + case 0: + indexx=pktt[6]; + for(i=0;i0 && pktt[6]<=MAX_PKTX) - {//only valid hub frames - frame[0] = 0xFD; - frame[1] = 0; - frame[2] = pktt[7]; - - switch(pass) - { - case 0: - indexx=pktt[6]; - for(i=0;i0) - { - crc_s += p[i]; //0-1FF - crc_s += crc_s >> 8; //0-100 - crc_s &= 0x00ff; - } - } - } - - void sportIdle() - { - Serial_write(0x7e); - } + [13] CHKSUM1 --|2 CRC bytes sent by RX (calculated on RX side crc16/table) + [14] CHKSUM2 --| + +2 appended bytes automatically RSSI and LQI/CRC bytes(len=0x0E+3); + +0x06 0x06 0x06 0x06 0x06 - void sportSendFrame() - { - //at the moment only SWR RSSI,RxBt and A2. - sport_counter = (sport_counter + 1) %9; - - for (uint8_t i=5;i<8;i++) - frame[i]=0; - - switch (sport_counter) - { - case 0: // SWR - frame[0] = 0x98; - frame[1] = 0x10; - frame[2] = 0x05; - frame[3] = 0xf1; - frame[4] = 0x20;//dummy values if swr 20230f00 - frame[5] = 0x23; - frame[6] = 0x0F; - frame[7] = 0x00; - break; - case 1: // RSSI - frame[0] = 0x98; - frame[1] = 0x10; - frame[2] = 0x01; - frame[3] = 0xf1; - frame[4] = rssi; - break; - case 2: //BATT - frame[0] = 0x98; - frame[1] = 0x10; - frame[2] = 0x04; - frame[3] = 0xf1; - frame[4] = RxBt;//a1; - break; - case 3: //ADC2(A2) - frame[0] = 0x1A; - frame[1] = 0x10; - frame[2] = 0x03; - frame[3] = 0xf1; - frame[4] = ADC2;//a2;; - break; - default: - sportIdle(); - return; - } - sportSend(frame); - } +0x7E 0x00 0x03 0x7E 0x00 +0x1A 0x00 0xF1 0x1A 0x00 +0x10 0x00 0xD7 0x10 0x00 +0x03 0x7E 0x00 0x03 0x7E +0xF1 0x1A 0x00 0xF1 0x1A +0xD7 0x10 0x00 0xD7 0x10 + +0xE1 0x1C 0xD0 0xEE 0x33 +0x34 0x0A 0xC3 0x56 0xF3 + + */ +void sportSend(uint8_t *p) +{ + uint16_t crc_s = 0; + Serial_write(START_STOP);//+9 + for (uint8_t i = 0; i < 9; i++) + { + if (i == 8) + p[i] = 0xff - crc_s; - void process_sport_data()//only for ADC2 - { - uint8_t j=7; - if(pktt[6]>0 && pktt[6]<=USER_MAX_BYTES) - { - for(uint8_t i=0;i<6;i++) - if(pktt[j++]==0x03) - if(pktt[j]==0xF1) - { - ADC2=pktt[j+1]; - break; - } - pktt[6]=0;//new frame - } + if ((p[i] == START_STOP) || (p[i] == BYTESTUFF)) + { + Serial_write(BYTESTUFF);//stuff again + Serial_write(STUFF_MASK ^ p[i]); + } + else + Serial_write(p[i]); + + if (i>0) + { + crc_s += p[i]; //0-1FF + crc_s += crc_s >> 8; //0-100 + crc_s &= 0x00ff; } - #endif - - - void frskyUpdate() - { - if(telemetry_link && (cur_protocol[0]&0x1F) != MODE_FRSKYX ) - { - frsky_link_frame(); - telemetry_link=0; - return; - } - #if defined HUB_TELEMETRY - if(!telemetry_link && (cur_protocol[0]&0x1F) != MODE_HUBSAN && (cur_protocol[0]&0x1F) != MODE_FRSKYX) - { - frsky_user_frame(); - return; - } - #endif - #if defined SPORT_TELEMETRY - if ((cur_protocol[0]&0x1F)==MODE_FRSKYX) - { - if(telemetry_link) - { - process_sport_data(); - if(pktt[4]>0x36) - rssi=pktt[4]/2; - else - RxBt=pktt[4]; - telemetry_link=0; - } - uint32_t now = micros(); - if ((now - last) > SPORT_TIME) - { - sportSendFrame(); - last = now; - } - } - #endif } +} + +void sportIdle() +{ + Serial_write(START_STOP); +} + +void sportSendFrame() +{ + uint8_t i; + sport_counter = (sport_counter + 1) %36; + if(sport_counter<3) + { + frame[0] = 0x98; + frame[1] = 0x10; + for (i=5;i<8;i++) + frame[i]=0; + } + switch (sport_counter) + { + case 0: + frame[2] = 0x05; + frame[3] = 0xf1; + frame[4] = 0x20;//dummy values if swr 20230f00 + frame[5] = 0x23; + frame[6] = 0x0F; + break; + case 1: // RSSI + frame[2] = 0x01; + frame[3] = 0xf1; + frame[4] = rssi; + break; + case 2: //BATT + frame[2] = 0x04; + frame[3] = 0xf1; + frame[4] = RxBt;//a1; + break; + default: + if(sport) + { + for (i=0;i= FRSKY_SPORT_PACKET_SIZE) + {//8 bytes no crc + sport = 1;//ok to send + pass = 0;//reset + } +} + +#endif + +void frskyUpdate() +{ + #if defined DSM_TELEMETRY + if(telemetry_link && (cur_protocol[0]&0x1F) == MODE_DSM2 ) + { // DSM2 + DSM2_frame(); + telemetry_link=0; + return; + } + #endif + if(telemetry_link && (cur_protocol[0]&0x1F) != MODE_FRSKYX ) + { // FrSky + Hubsan + frsky_link_frame(); + telemetry_link=0; + return; + } + #if defined HUB_TELEMETRY + if(!telemetry_link && (cur_protocol[0]&0x1F) == MODE_FRSKY) + { // FrSky + frsky_user_frame(); + return; + } + #endif + #if defined SPORT_TELEMETRY + if ((cur_protocol[0]&0x1F)==MODE_FRSKYX) + { // FrSkyX + if(telemetry_link) + { + if(pktt[4]>0x36) + rssi=pktt[4]>>1; + else + RxBt=pktt[4]; + for (uint8_t i=0; i < pktt[6]; i++) + proces_sport_data(pktt[7+i]); + telemetry_link=0; + } + uint32_t now = micros(); + if ((now - last) > SPORT_TIME) + { + sportSendFrame(); + last = now; + } + } + #endif +} + #endif \ No newline at end of file diff --git a/Multiprotocol/WMath.cpp.xmega b/Multiprotocol/WMath.cpp.xmega new file mode 100644 index 0000000..42731e4 --- /dev/null +++ b/Multiprotocol/WMath.cpp.xmega @@ -0,0 +1,60 @@ +/* -*- mode: jde; c-basic-offset: 2; indent-tabs-mode: nil -*- */ + +/* + Part of the Wiring project - http://wiring.org.co + Copyright (c) 2004-06 Hernando Barragan + Modified 13 August 2006, David A. Mellis for Arduino - http://www.arduino.cc/ + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General + Public License along with this library; if not, write to the + Free Software Foundation, Inc., 59 Temple Place, Suite 330, + Boston, MA 02111-1307 USA + + $Id$ +*/ + +extern "C" { + #include "stdlib.h" +} + +void randomSeed(unsigned int seed) +{ + if (seed != 0) { + srandom(seed); + } +} + +long random(long howbig) +{ + if (howbig == 0) { + return 0; + } + return random() % howbig; +} + +//long random(long howsmall, long howbig) +//{ +// if (howsmall >= howbig) { +// return howsmall; +// } +// long diff = howbig - howsmall; +// return random(diff) + howsmall; +//} + +long map(long x, long in_min, long in_max, long out_min, long out_max) +{ + return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; +} + +unsigned int makeWord(unsigned int w) { return w; } +unsigned int makeWord(unsigned char h, unsigned char l) { return (h << 8) | l; } \ No newline at end of file diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index fb40ddd..e4fb682 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -42,6 +42,7 @@ #ifdef CC2500_INSTALLED #define FRSKY_CC2500_INO #define FRSKYX_CC2500_INO + #define SFHSS_CC2500_INO #endif #ifdef NFR24L01_INSTALLED #define BAYANG_NRF24L01_INO @@ -129,7 +130,8 @@ const PPM_Parameters PPM_prot[15]= { MODE_BAYANG NONE MODE_FRSKYX - NONE + CH_16 + CH_8 MODE_ESKY NONE MODE_MT99XX @@ -145,6 +147,8 @@ const PPM_Parameters PPM_prot[15]= { NONE MODE_FY326 NONE + MODE_SFHSS + NONE RX_Num value between 0 and 15 From e9e39cb9851494d473504343f0773708e0932165 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 6 Apr 2016 14:58:06 +0200 Subject: [PATCH 086/293] Added all CC2500 power settings --- Multiprotocol/Multiprotocol.h | 40 +++++++++++++++++++++------------- Multiprotocol/SFHSS_cc2500.ino | 2 +- 2 files changed, 26 insertions(+), 16 deletions(-) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 721ae05..a2dc5b5 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -378,23 +378,33 @@ enum NRF_POWER #define NRF_RANGE_POWER NRF_POWER_0 #define NRF_BIND_POWER NRF_POWER_0 -// CC2500 power +// CC2500 power output from the chip itself +// The numbers do not take into account any outside amplifier enum CC2500_POWER { - CC2500_POWER_0 = 0x50, // -30dbm - //CC2500_POWER_0 = 0xC5, // -12dbm - CC2500_POWER_1 = 0x97, // -10dbm - CC2500_POWER_2 = 0x6E, // -8dbm - CC2500_POWER_3 = 0x7F, // -6dbm - CC2500_POWER_4 = 0xA9, // -4dbm - CC2500_POWER_5 = 0xBB, // -2dbm - CC2500_POWER_6 = 0xFE, // 0dbm - CC2500_POWER_7 = 0xFF // 1.5dbm + CC2500_POWER_0 = 0x00, // –55dbm or less + CC2500_POWER_1 = 0x50, // -30dbm + CC2500_POWER_2 = 0x44, // –28dbm + CC2500_POWER_3 = 0xC0, // –26dbm + CC2500_POWER_4 = 0x84, // –24dbm + CC2500_POWER_5 = 0x81, // –22dbm + CC2500_POWER_6 = 0x46, // –20dbm + CC2500_POWER_7 = 0x93, // –18dbm + CC2500_POWER_8 = 0x55, // –16dbm + CC2500_POWER_9 = 0x8D, // –14dbm + CC2500_POWER_10 = 0xC6, // -12dbm + CC2500_POWER_11 = 0x97, // -10dbm + CC2500_POWER_12 = 0x6E, // -8dbm + CC2500_POWER_13 = 0x7F, // -6dbm + CC2500_POWER_14 = 0xA9, // -4dbm + CC2500_POWER_15 = 0xBB, // -2dbm + CC2500_POWER_16 = 0xFE, // 0dbm + CC2500_POWER_17 = 0xFF // +1dbm }; -#define CC2500_HIGH_POWER CC2500_POWER_6 -#define CC2500_LOW_POWER CC2500_POWER_3 -#define CC2500_RANGE_POWER CC2500_POWER_0 -#define CC2500_BIND_POWER CC2500_POWER_0 +#define CC2500_HIGH_POWER CC2500_POWER_16 +#define CC2500_LOW_POWER CC2500_POWER_13 +#define CC2500_RANGE_POWER CC2500_POWER_1 +#define CC2500_BIND_POWER CC2500_POWER_1 // CYRF power enum CYRF_POWER @@ -410,7 +420,7 @@ enum CYRF_POWER }; #define CYRF_HIGH_POWER CYRF_POWER_7 #define CYRF_LOW_POWER CYRF_POWER_3 -#define CYRF_RANGE_POWER CYRF_POWER_1 +#define CYRF_RANGE_POWER CYRF_POWER_1 // 1/30 of the full power distance #define CYRF_BIND_POWER CYRF_POWER_0 enum TXRX_State { diff --git a/Multiprotocol/SFHSS_cc2500.ino b/Multiprotocol/SFHSS_cc2500.ino index c32b891..04879ec 100644 --- a/Multiprotocol/SFHSS_cc2500.ino +++ b/Multiprotocol/SFHSS_cc2500.ino @@ -224,7 +224,7 @@ static void __attribute__((unused)) SFHSS_get_tx_id() { uint32_t fixed_id; // Some receivers (Orange) behaves better if they tuned to id that has - // no more than 6 consequtive zeos and ones + // no more than 6 consecutive zeros and ones uint8_t run_count = 0; // add guard for bit count fixed_id = 1 ^ (MProtocol_id & 1); From 9b74e19a996ef17188d5fb7eb694b2ac1d823f31 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 6 Apr 2016 15:41:42 +0200 Subject: [PATCH 087/293] Update README.md --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 20c873f..d5532c0 100644 --- a/README.md +++ b/README.md @@ -86,7 +86,8 @@ You can connect it to your TX if it is telemetry enabled or use a bluetooth adap Telemetry is built in for er9x and ersky9x TXs. To enable telemetry on a Turnigy 9X or 9XR you need to modify your TX following one of the Frsky mod like this [one](http://blog.oscarliang.net/turnigy-9x-advance-mod/). -Note: DSM telemetry is not available on er9x due to alack of flash space. + +Note: DSM telemetry is not available on er9x due to a lack of flash space. Enabling telemetry on a 9XR PRO and may be other TXs does not require any hardware modifications. The additional required serial pin is already available on the TX back module pins. From fc61753953fb46d9a82a6c28211e46c7ea5437a1 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sun, 10 Apr 2016 20:04:11 +0200 Subject: [PATCH 088/293] DSM2/X pncodes fix and FrSky RSSI&TSSI swap fix --- Multiprotocol/DSM2_cyrf6936.ino | 2 +- Multiprotocol/Multiprotocol.h | 2 +- Multiprotocol/Multiprotocol.ino | 9 +++++++++ Multiprotocol/Telemetry.ino | 19 +++++-------------- Multiprotocol/_Config.h | 19 ++++++++++++++++--- 5 files changed, 32 insertions(+), 19 deletions(-) diff --git a/Multiprotocol/DSM2_cyrf6936.ino b/Multiprotocol/DSM2_cyrf6936.ino index 9a2b018..b51279a 100644 --- a/Multiprotocol/DSM2_cyrf6936.ino +++ b/Multiprotocol/DSM2_cyrf6936.ino @@ -84,7 +84,7 @@ const uint8_t PROGMEM pncodes[5][9][8] = { /* Col 5 */ {0x9B, 0x75, 0xF7, 0xE0, 0x14, 0x8D, 0xB5, 0x80}, /* Col 6 */ {0xBF, 0x54, 0x98, 0xB9, 0xB7, 0x30, 0x5A, 0x88}, /* Col 7 */ {0x35, 0xD1, 0xFC, 0x97, 0x23, 0xD4, 0xC9, 0x88}, - /* Col 8 */ {0x88, 0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40} + /* Col 8 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93} }, { /* Row 4 */ /* Col 0 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93}, diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index a2dc5b5..4b5f8fa 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -402,7 +402,7 @@ enum CC2500_POWER CC2500_POWER_17 = 0xFF // +1dbm }; #define CC2500_HIGH_POWER CC2500_POWER_16 -#define CC2500_LOW_POWER CC2500_POWER_13 +#define CC2500_LOW_POWER CC2500_POWER_13 #define CC2500_RANGE_POWER CC2500_POWER_1 #define CC2500_BIND_POWER CC2500_POWER_1 diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index d9be20b..a5bb69d 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -99,6 +99,15 @@ uint8_t prev_protocol=0; #define MAX_PKT 27 uint8_t pkt[MAX_PKT];//telemetry receiving packets #if defined(TELEMETRY) + #if defined DSM2_CYRF6936_INO + #define DSM_TELEMETRY + #endif + #if defined FRSKYX_CC2500_INO + #define SPORT_TELEMETRY + #endif + #if defined FRSKY_CC2500_INO + #define HUB_TELEMETRY + #endif uint8_t pktt[MAX_PKT];//telemetry receiving packets volatile uint8_t tx_head=0; volatile uint8_t tx_tail=0; diff --git a/Multiprotocol/Telemetry.ino b/Multiprotocol/Telemetry.ino index 1b90ceb..a7d692a 100644 --- a/Multiprotocol/Telemetry.ino +++ b/Multiprotocol/Telemetry.ino @@ -5,15 +5,6 @@ #if defined TELEMETRY -#if defined DSM2_CYRF6936_INO - #define DSM_TELEMETRY -#endif -#if defined FRSKYX_CC2500_INO - #define SPORT_TELEMETRY -#endif -#if defined FRSKY_CC2500_INO - #define HUB_TELEMETRY -#endif #if defined SPORT_TELEMETRY #define SPORT_TIME 12000 #define FRSKY_SPORT_PACKET_SIZE 8 @@ -64,11 +55,11 @@ void frskySendStuffed() void compute_RSSIdbm() { - RSSI_dBm = (((uint16_t)(pktt[len-2])*18)>>5); + RSSI_dBm = (((uint16_t)(pktt[len-2])*18)>>4); if(pktt[len-2] >=128) - RSSI_dBm -= 82; + RSSI_dBm -= 164; else - RSSI_dBm += 65; + RSSI_dBm += 130; } void frsky_check_telemetry(uint8_t *pkt,uint8_t len) @@ -110,8 +101,8 @@ void frsky_link_frame() compute_RSSIdbm(); frame[1] = pktt[3]; frame[2] = pktt[4]; - frame[3] = (uint8_t)RSSI_dBm; - frame[4] = pktt[5]*2; + frame[3] = pktt[5]; + frame[4] = (uint8_t)RSSI_dBm; } else if ((cur_protocol[0]&0x1F)==MODE_HUBSAN) diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index e4fb682..c0942e4 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -21,9 +21,6 @@ //#define TX_SPEKTRUM //Spektrum TAER (1100<->1900µs) //#define TX_HISKY //HISKY AETR (1100<->1900µs) -//Uncomment to enable telemetry -#define TELEMETRY - //Comment if a module is not installed #define A7105_INSTALLED #define CYRF6936_INSTALLED @@ -61,6 +58,22 @@ #define FY326_NRF24L01_INO #endif +//Uncomment to enable telemetry +#define TELEMETRY + +//Comment to disable a specific telemetry +#if defined(TELEMETRY) + #if defined DSM2_CYRF6936_INO + #define DSM_TELEMETRY + #endif + #if defined FRSKYX_CC2500_INO + #define SPORT_TELEMETRY + #endif + #if defined FRSKY_CC2500_INO + #define HUB_TELEMETRY + #endif +#endif + //Update this table to set which protocol and all associated settings are called for the corresponding dial number const PPM_Parameters PPM_prot[15]= { // Dial Protocol Sub protocol RX_Num Power Auto Bind Option From e573e36aa66f52dcfb9a3fdaa48144ccaa3e892b Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 11 Apr 2016 21:17:46 +0200 Subject: [PATCH 089/293] SFHSS change --- Multiprotocol/SFHSS_cc2500.ino | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/Multiprotocol/SFHSS_cc2500.ino b/Multiprotocol/SFHSS_cc2500.ino index 04879ec..446ee23 100644 --- a/Multiprotocol/SFHSS_cc2500.ino +++ b/Multiprotocol/SFHSS_cc2500.ino @@ -88,7 +88,7 @@ static void __attribute__((unused)) SFHSS_tune_chan_fast() _delay_us(6); } -#ifdef USE_SFHSS_TUNE_FREQ +#ifdef SFHSS_USE_TUNE_FREQ static void __attribute__((unused)) SFHSS_tune_freq() { // May be we'll need this tuning routine - some receivers are more sensitive to // frequency impreciseness, and though CC2500 has a procedure to handle it it @@ -129,15 +129,15 @@ static uint16_t __attribute__((unused)) SFHSS_convert_channel(uint8_t num) static void __attribute__((unused)) SFHSS_build_data_packet() { -#define spacer1 0b10 +#define spacer1 0x02 //0b10 #define spacer2 (spacer1 << 4) uint8_t ch_offset = state == SFHSS_DATA1 ? 0 : 4; const uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4}; - u16 ch1 = SFHSS_convert_channel(ch[ch_offset+0]); - u16 ch2 = SFHSS_convert_channel(ch[ch_offset+1]); - u16 ch3 = SFHSS_convert_channel(ch[ch_offset+2]); - u16 ch4 = SFHSS_convert_channel(ch[ch_offset+3]); + uint16_t ch1 = SFHSS_convert_channel(ch[ch_offset+0]); + uint16_t ch2 = SFHSS_convert_channel(ch[ch_offset+1]); + uint16_t ch3 = SFHSS_convert_channel(ch[ch_offset+2]); + uint16_t ch4 = SFHSS_convert_channel(ch[ch_offset+3]); packet[0] = 0x81; // can be 80, 81, 81 for Orange, only 81 for XK packet[1] = rx_tx_addr[0]; @@ -146,11 +146,11 @@ static void __attribute__((unused)) SFHSS_build_data_packet() packet[4] = 0; packet[5] = (rf_ch_num << 3) | spacer1 | ((ch1 >> 9) & 0x01); packet[6] = (ch1 >> 1); - packet[7] = (ch1 << 7) | spacer2 | ((ch2 >> 5) & 0b11111); + packet[7] = (ch1 << 7) | spacer2 | ((ch2 >> 5) & 0x1F /*0b11111*/); packet[8] = (ch2 << 3) | spacer1 | ((ch3 >> 9) & 0x01); packet[9] = (ch3 >> 1); - packet[10] = (ch3 << 7) | spacer2 | ((ch4 >> 5) & 0b11111); - packet[11] = (ch4 << 3) | ((fhss_code >> 2) & 0b111); + packet[10] = (ch3 << 7) | spacer2 | ((ch4 >> 5) & 0x1F /*0b11111*/); + packet[11] = (ch4 << 3) | ((fhss_code >> 2) & 0x07 /*0b111 */); packet[12] = (fhss_code << 6) | state; } @@ -251,6 +251,7 @@ static void __attribute__((unused)) SFHSS_get_tx_id() uint16_t initSFHSS() { + BIND_DONE; // No bind procedure SFHSS_get_tx_id(); randomSeed((uint32_t)analogRead(A6) << 10 | analogRead(A7)); From a92cb848c067f4ad28f40b0729516ae7a3c4a969 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 12 Apr 2016 08:21:06 +0200 Subject: [PATCH 090/293] SFHSS change --- Multiprotocol/SFHSS_cc2500.ino | 33 ++++++++++++++++++--------------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/Multiprotocol/SFHSS_cc2500.ino b/Multiprotocol/SFHSS_cc2500.ino index 446ee23..664b96d 100644 --- a/Multiprotocol/SFHSS_cc2500.ino +++ b/Multiprotocol/SFHSS_cc2500.ino @@ -73,6 +73,20 @@ const PROGMEM uint8_t SFHSS_init_values[] = { /* 20 */ 0xF8, 0xB6, 0x10, 0xEA, 0x0A, 0x11, 0x11 }; +static void __attribute__((unused)) SFHSS_rf_init() +{ + CC2500_Reset(); + CC2500_Strobe(CC2500_SIDLE); + + for (uint8_t i = 0; i < 39; ++i) + CC2500_WriteReg(i, pgm_read_byte_near(&SFHSS_init_values[i])); + //CC2500_WriteRegisterMulti(CC2500_00_IOCFG2, init_values, sizeof(init_values)); + CC2500_WriteReg(CC2500_0C_FSCTRL0, option); + + CC2500_SetTxRxMode(TX_EN); + CC2500_SetPower(); +} + static void __attribute__((unused)) SFHSS_tune_chan() { CC2500_Strobe(CC2500_SIDLE); @@ -98,24 +112,13 @@ static void __attribute__((unused)) SFHSS_tune_freq() { } #endif -static void __attribute__((unused)) SFHSS_rf_init() -{ - CC2500_Reset(); - CC2500_Strobe(CC2500_SIDLE); - - for (uint8_t i = 0; i < 39; ++i) - CC2500_WriteReg(i, pgm_read_byte_near(&SFHSS_init_values[i])); - //CC2500_WriteRegisterMulti(CC2500_00_IOCFG2, init_values, sizeof(init_values)); - - CC2500_SetTxRxMode(TX_EN); - CC2500_SetPower(); -} - static void __attribute__((unused)) SFHSS_calc_next_chan() { rf_ch_num += fhss_code + 2; - if (rf_ch_num > 29) { - if (rf_ch_num < 31) rf_ch_num += fhss_code + 2; + if (rf_ch_num > 29) + { + if (rf_ch_num < 31) + rf_ch_num += fhss_code + 2; rf_ch_num -= 31; } } From ed027fd3cea245bd8cc01b0afa5ab3d0a8ea65a8 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 12 Apr 2016 15:00:06 +0200 Subject: [PATCH 091/293] SFHSS change --- Multiprotocol/SFHSS_cc2500.ino | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/Multiprotocol/SFHSS_cc2500.ino b/Multiprotocol/SFHSS_cc2500.ino index 664b96d..4a8b545 100644 --- a/Multiprotocol/SFHSS_cc2500.ino +++ b/Multiprotocol/SFHSS_cc2500.ino @@ -254,11 +254,10 @@ static void __attribute__((unused)) SFHSS_get_tx_id() uint16_t initSFHSS() { - BIND_DONE; // No bind procedure + BIND_DONE; // No bind protocol SFHSS_get_tx_id(); - randomSeed((uint32_t)analogRead(A6) << 10 | analogRead(A7)); - fhss_code=random(0xfefefefe)%28; // Initialize it to random 0-27 inclusive + fhss_code=rx_tx_addr[2]%28; // Initialize it to random 0-27 inclusive SFHSS_rf_init(); state = SFHSS_START; From 4486582006b1f49b59dd1f8f5c3b013eee881382 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 15 Apr 2016 15:46:32 +0200 Subject: [PATCH 092/293] LT8900 emulator address convention changed, updated Shenqi protocol accordingly. --- Multiprotocol/A7105_SPI.ino | 3 +- Multiprotocol/CG023_nrf24l01.ino | 2 +- Multiprotocol/CX10_nrf24l01.ino | 5 +- Multiprotocol/FlySky_a7105.ino | 1 - Multiprotocol/Multiprotocol.ino | 9 +++ Multiprotocol/NRF24l01_SPI.ino | 126 +++++++++++++++--------------- Multiprotocol/SHENQI_nrf24l01.ino | 42 +++++----- 7 files changed, 99 insertions(+), 89 deletions(-) diff --git a/Multiprotocol/A7105_SPI.ino b/Multiprotocol/A7105_SPI.ino index 1698725..16f5869 100644 --- a/Multiprotocol/A7105_SPI.ino +++ b/Multiprotocol/A7105_SPI.ino @@ -121,9 +121,8 @@ uint8_t A7105_Reset() { uint8_t result; - delay(10); //wait 10ms for A7105 wakeup A7105_WriteReg(0x00, 0x00); - delay(1000); + _delay_us(1000); A7105_SetTxRxMode(TXRX_OFF); //Set both GPIO as output and low result=A7105_ReadReg(0x10) == 0x9E; //check if is reset. A7105_Strobe(A7105_STANDBY); diff --git a/Multiprotocol/CG023_nrf24l01.ino b/Multiprotocol/CG023_nrf24l01.ino index 0e5c0ce..54f4a85 100644 --- a/Multiprotocol/CG023_nrf24l01.ino +++ b/Multiprotocol/CG023_nrf24l01.ino @@ -25,7 +25,7 @@ #define CG023_INITIAL_WAIT 500 #define CG023_PACKET_SIZE 15 // packets have 15-byte payload #define CG023_RF_BIND_CHANNEL 0x2D -#define CG023_BIND_COUNT 1000 // 8 seconds +#define CG023_BIND_COUNT 500 // 4 seconds #define YD829_PACKET_PERIOD 4100 // Timeout for callback in uSec #define H8_3D_PACKET_PERIOD 1800 // Timeout for callback in uSec #define H8_3D_PACKET_SIZE 20 diff --git a/Multiprotocol/CX10_nrf24l01.ino b/Multiprotocol/CX10_nrf24l01.ino index 6722fcd..f541e5f 100644 --- a/Multiprotocol/CX10_nrf24l01.ino +++ b/Multiprotocol/CX10_nrf24l01.ino @@ -182,7 +182,8 @@ static void __attribute__((unused)) CX10_init() NRF24L01_SetPower(); } -uint16_t CX10_callback() { +uint16_t CX10_callback() +{ switch (phase) { case CX10_BIND1: if (bind_counter == 0) @@ -219,7 +220,7 @@ uint16_t CX10_callback() { NRF24L01_SetTxRxMode(TXRX_OFF); NRF24L01_SetTxRxMode(TX_EN); CX10_Write_Packet(1); - delayMicroseconds(400); // 300µs in deviation but not working so using 400µs instead + _delay_us(1000); // switch to RX mode NRF24L01_SetTxRxMode(TXRX_OFF); NRF24L01_FlushRx(); diff --git a/Multiprotocol/FlySky_a7105.ino b/Multiprotocol/FlySky_a7105.ino index ac6fddf..4810b5d 100644 --- a/Multiprotocol/FlySky_a7105.ino +++ b/Multiprotocol/FlySky_a7105.ino @@ -192,7 +192,6 @@ uint16_t ReadFlySky() } uint16_t initFlySky() { - //A7105_Reset(); A7105_Init(INIT_FLYSKY); //flysky_init(); if ((rx_tx_addr[3]&0xF0) > 0x90) // limit offset to 9 as higher values don't work with some RX (ie V912) diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index a5bb69d..a1b3f3c 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -217,6 +217,15 @@ void setup() #ifdef CC2500_INSTALLED CC2500_Reset(); #endif + #ifdef A7105_INSTALLED + A7105_Reset(); + #endif + #ifdef CYRF6936_INSTALLED + CYRF_Reset(); + #endif + #ifdef NFR24L01_INSTALLED + NRF24L01_Reset(); + #endif //Protocol and interrupts initialization if(mode_select != MODE_SERIAL) diff --git a/Multiprotocol/NRF24l01_SPI.ino b/Multiprotocol/NRF24l01_SPI.ino index f95e86f..4c947bf 100644 --- a/Multiprotocol/NRF24l01_SPI.ino +++ b/Multiprotocol/NRF24l01_SPI.ino @@ -246,7 +246,8 @@ void NRF24L01_Reset() uint8_t NRF24L01_packet_ack() { - switch (NRF24L01_ReadReg(NRF24L01_07_STATUS) & (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT))) { + switch (NRF24L01_ReadReg(NRF24L01_07_STATUS) & (BV(NRF24L01_07_TX_DS) | BV(NRF24L01_07_MAX_RT))) + { case BV(NRF24L01_07_TX_DS): return PKT_ACKED; case BV(NRF24L01_07_MAX_RT): @@ -411,47 +412,47 @@ void XN297_ReadPayload(uint8_t* msg, uint8_t len) // End of XN297 emulation /////////////// -// LT8910 emulation layer -uint8_t LT8910_buffer[64]; -uint8_t LT8910_buffer_start; -uint16_t LT8910_buffer_overhead_bits; -uint8_t LT8910_addr[8]; -uint8_t LT8910_addr_size; -uint8_t LT8910_Preamble_Len; -uint8_t LT8910_Tailer_Len; -uint8_t LT8910_CRC_Initial_Data; -uint8_t LT8910_Flags; -#define LT8910_CRC_ON 6 -#define LT8910_SCRAMBLE_ON 5 -#define LT8910_PACKET_LENGTH_EN 4 -#define LT8910_DATA_PACKET_TYPE_1 3 -#define LT8910_DATA_PACKET_TYPE_0 2 -#define LT8910_FEC_TYPE_1 1 -#define LT8910_FEC_TYPE_0 0 +// LT8900 emulation layer +uint8_t LT8900_buffer[64]; +uint8_t LT8900_buffer_start; +uint16_t LT8900_buffer_overhead_bits; +uint8_t LT8900_addr[8]; +uint8_t LT8900_addr_size; +uint8_t LT8900_Preamble_Len; +uint8_t LT8900_Tailer_Len; +uint8_t LT8900_CRC_Initial_Data; +uint8_t LT8900_Flags; +#define LT8900_CRC_ON 6 +#define LT8900_SCRAMBLE_ON 5 +#define LT8900_PACKET_LENGTH_EN 4 +#define LT8900_DATA_PACKET_TYPE_1 3 +#define LT8900_DATA_PACKET_TYPE_0 2 +#define LT8900_FEC_TYPE_1 1 +#define LT8900_FEC_TYPE_0 0 -void LT8910_Config(uint8_t preamble_len, uint8_t trailer_len, uint8_t flags, uint8_t crc_init) +void LT8900_Config(uint8_t preamble_len, uint8_t trailer_len, uint8_t flags, uint8_t crc_init) { //Preamble 1 to 8 bytes - LT8910_Preamble_Len=preamble_len; + LT8900_Preamble_Len=preamble_len; //Trailer 4 to 18 bits - LT8910_Tailer_Len=trailer_len; + LT8900_Tailer_Len=trailer_len; //Flags // CRC_ON: 1 on, 0 off // SCRAMBLE_ON: 1 on, 0 off // PACKET_LENGTH_EN: 1 1st byte of payload is payload size // DATA_PACKET_TYPE: 00 NRZ, 01 Manchester, 10 8bit/10bit line code, 11 interleave data type // FEC_TYPE: 00 No FEC, 01 FEC13, 10 FEC23, 11 reserved - LT8910_Flags=flags; + LT8900_Flags=flags; //CRC init constant - LT8910_CRC_Initial_Data=crc_init; + LT8900_CRC_Initial_Data=crc_init; } -void LT8910_SetChannel(uint8_t channel) +void LT8900_SetChannel(uint8_t channel) { NRF24L01_WriteReg(NRF24L01_05_RF_CH, channel +2); //NRF24L01 is 2400+channel but LT8900 is 2402+channel } -void LT8910_SetTxRxMode(enum TXRX_State mode) +void LT8900_SetTxRxMode(enum TXRX_State mode) { if(mode == TX_EN) { @@ -477,61 +478,62 @@ void LT8910_SetTxRxMode(enum TXRX_State mode) NRF24L01_SetTxRxMode(TXRX_OFF); } -void LT8910_BuildOverhead() +void LT8900_BuildOverhead() { uint8_t pos; //Build overhead //preamble - memset(LT8910_buffer,LT8910_addr[0]&0x01?0xAA:0x55,LT8910_Preamble_Len-1); - pos=LT8910_Preamble_Len-1; + memset(LT8900_buffer,LT8900_addr[0]&0x01?0xAA:0x55,LT8900_Preamble_Len-1); + pos=LT8900_Preamble_Len-1; //address - for(uint8_t i=0;i5?5:pos; + pos+=LT8900_Tailer_Len/8; + LT8900_buffer_start=pos>5?5:pos; } -void LT8910_SetAddress(uint8_t *address,uint8_t addr_size) +void LT8900_SetAddress(uint8_t *address,uint8_t addr_size) { uint8_t addr[5]; //Address size (SyncWord) 2 to 8 bytes, 16/32/48/64 bits - LT8910_addr_size=addr_size; - memcpy(LT8910_addr,address,LT8910_addr_size); + LT8900_addr_size=addr_size; + for (uint8_t i = 0; i < addr_size; i++) + LT8900_addr[i] = address[addr_size-1-i]; //Build overhead - LT8910_BuildOverhead(); + LT8900_BuildOverhead(); //Set NRF RX&TX address based on overhead content - NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, LT8910_buffer_start-2); - for(uint8_t i=0;i>8)&0xFF; } //Check len - if(LT8910_Flags&_BV(LT8910_PACKET_LENGTH_EN)) + if(LT8900_Flags&_BV(LT8900_PACKET_LENGTH_EN)) { crc=crc16_update(crc,buffer[pos]); if(bit_reverse(len)!=buffer[pos++]) @@ -552,7 +554,7 @@ uint8_t LT8910_ReadPayload(uint8_t* msg, uint8_t len) msg[i]=bit_reverse(buffer[pos++]); } //Check CRC - if(LT8910_Flags&_BV(LT8910_CRC_ON)) + if(LT8900_Flags&_BV(LT8900_CRC_ON)) { if(buffer[pos++]!=((crc>>8)&0xFF)) return 0; // wrong CRC... if(buffer[pos]!=(crc&0xFF)) return 0; // wrong CRC... @@ -561,12 +563,12 @@ uint8_t LT8910_ReadPayload(uint8_t* msg, uint8_t len) return 1; } -void LT8910_WritePayload(uint8_t* msg, uint8_t len) +void LT8900_WritePayload(uint8_t* msg, uint8_t len) { - unsigned int crc=LT8910_CRC_Initial_Data,a,mask; + unsigned int crc=LT8900_CRC_Initial_Data,a,mask; uint8_t i, pos=0,tmp, buffer[64], pos_final,shift; //Add packet len - if(LT8910_Flags&_BV(LT8910_PACKET_LENGTH_EN)) + if(LT8900_Flags&_BV(LT8900_PACKET_LENGTH_EN)) { tmp=bit_reverse(len); buffer[pos++]=tmp; @@ -580,25 +582,25 @@ void LT8910_WritePayload(uint8_t* msg, uint8_t len) crc=crc16_update(crc,tmp); } //Add CRC - if(LT8910_Flags&_BV(LT8910_CRC_ON)) + if(LT8900_Flags&_BV(LT8900_CRC_ON)) { buffer[pos++]=crc>>8; buffer[pos++]=crc; } //Shift everything to fit behind the trailer (4 to 18 bits) - shift=LT8910_buffer_overhead_bits&0x7; - pos_final=LT8910_buffer_overhead_bits/8; + shift=LT8900_buffer_overhead_bits&0x7; + pos_final=LT8900_buffer_overhead_bits/8; mask=~(0xFF<<(8-shift)); - LT8910_buffer[pos_final+pos]=0xFF; + LT8900_buffer[pos_final+pos]=0xFF; for(i=pos-1;i!=0xFF;i--) { a=buffer[i]<<(8-shift); - LT8910_buffer[pos_final+i]=(LT8910_buffer[pos_final+i]&mask>>8)|a>>8; - LT8910_buffer[pos_final+i+1]=(LT8910_buffer[pos_final+i+1]&mask)|a; + LT8900_buffer[pos_final+i]=(LT8900_buffer[pos_final+i]&mask>>8)|a>>8; + LT8900_buffer[pos_final+i+1]=(LT8900_buffer[pos_final+i+1]&mask)|a; } if(shift) pos++; //Send everything - NRF24L01_WritePayload(LT8910_buffer+LT8910_buffer_start,pos_final+pos-LT8910_buffer_start); + NRF24L01_WritePayload(LT8900_buffer+LT8900_buffer_start,pos_final+pos-LT8900_buffer_start); } -// End of LT8910 emulation +// End of LT8900 emulation diff --git a/Multiprotocol/SHENQI_nrf24l01.ino b/Multiprotocol/SHENQI_nrf24l01.ino index 18d5037..c829f7e 100644 --- a/Multiprotocol/SHENQI_nrf24l01.ino +++ b/Multiprotocol/SHENQI_nrf24l01.ino @@ -24,10 +24,10 @@ void SHENQI_init() NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5 bytes rx/tx address - LT8910_Config(4, 8, _BV(LT8910_CRC_ON)|_BV(LT8910_PACKET_LENGTH_EN), 0xAA); - LT8910_SetChannel(2); - LT8910_SetAddress((uint8_t *)"\x9A\x9A\x9A\x9A",4); - LT8910_SetTxRxMode(RX_EN); + LT8900_Config(4, 8, _BV(LT8900_CRC_ON)|_BV(LT8900_PACKET_LENGTH_EN), 0xAA); + LT8900_SetChannel(2); + LT8900_SetAddress((uint8_t *)"\x9A\x9A\x9A\x9A",4); + LT8900_SetTxRxMode(RX_EN); } void SHENQI_send_packet() @@ -36,32 +36,32 @@ void SHENQI_send_packet() if(packet_count==0) { uint8_t bind_addr[4]; - bind_addr[0]=0x9A; - bind_addr[1]=0x9A; - bind_addr[2]=rx_tx_addr[2]; - bind_addr[3]=rx_tx_addr[3]; - LT8910_SetAddress(bind_addr,4); - LT8910_SetChannel(2); - packet[1]=rx_tx_addr[1]; - packet[2]=rx_tx_addr[0]; + bind_addr[0]=rx_tx_addr[0]; + bind_addr[1]=rx_tx_addr[1]; + bind_addr[2]=0x9A; + bind_addr[3]=0x9A; + LT8900_SetAddress(bind_addr,4); + LT8900_SetChannel(2); + packet[1]=rx_tx_addr[2]; + packet[2]=rx_tx_addr[3]; packet_period=2508; } else { - LT8910_SetAddress(rx_tx_addr,4); + LT8900_SetAddress(rx_tx_addr,4); packet[1]=255-convert_channel_8b(RUDDER); packet[2]=255-convert_channel_8b_scale(THROTTLE,0x60,0xA0); - uint8_t freq=pgm_read_byte_near(&SHENQI_Freq[hopping_frequency_no])+(rx_tx_addr[1]&0x0F); - LT8910_SetChannel(freq); + uint8_t freq=pgm_read_byte_near(&SHENQI_Freq[hopping_frequency_no])+(rx_tx_addr[2]&0x0F); + LT8900_SetChannel(freq); hopping_frequency_no++; if(hopping_frequency_no==60) hopping_frequency_no=0; packet_period=1750; } // Send packet + 1 retransmit - not sure why but needed (not present on original TX...) - LT8910_WritePayload(packet,3); + LT8900_WritePayload(packet,3); while(NRF24L01_packet_ack()!=PKT_ACKED); - LT8910_WritePayload(packet,3); + LT8900_WritePayload(packet,3); packet_count++; if(packet_count==7) @@ -81,12 +81,12 @@ uint16_t SHENQI_callback() { if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR)) { - if(LT8910_ReadPayload(packet, 3)) + if(LT8900_ReadPayload(packet, 3)) { BIND_DONE; - rx_tx_addr[3]=packet[1]; - rx_tx_addr[2]=packet[2]; - LT8910_SetTxRxMode(TX_EN); + rx_tx_addr[0]=packet[1]; + rx_tx_addr[1]=packet[2]; + LT8900_SetTxRxMode(TX_EN); packet_period=14000; } NRF24L01_FlushRx(); From 6d752acb28f7ee26138d7bd6ace8d682974dac50 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 18 Apr 2016 19:43:12 +0200 Subject: [PATCH 093/293] Fixed xn297 scramble mode affecting cx-10a and probably other xn297 based protocols... --- Multiprotocol/CX10_nrf24l01.ino | 16 +++++----------- Multiprotocol/NRF24l01_SPI.ino | 2 +- 2 files changed, 6 insertions(+), 12 deletions(-) diff --git a/Multiprotocol/CX10_nrf24l01.ino b/Multiprotocol/CX10_nrf24l01.ino index f541e5f..434f22a 100644 --- a/Multiprotocol/CX10_nrf24l01.ino +++ b/Multiprotocol/CX10_nrf24l01.ino @@ -25,7 +25,6 @@ #define Q282_PACKET_SIZE 21 #define CX10_PACKET_PERIOD 1316 // Timeout for callback in uSec #define CX10A_PACKET_PERIOD 6000 -#define CX10A_BIND_COUNT 400 // 2 seconds #define CX10_INITIAL_WAIT 500 @@ -198,12 +197,6 @@ uint16_t CX10_callback() } break; case CX10_BIND2: - bind_counter--; - if(bind_counter==0) - { // Needed for some CX-10A to properly finish the bind - CX10_init(); - bind_counter=CX10A_BIND_COUNT; - } if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR)) { // RX fifo data ready XN297_ReadPayload(packet, packet_length); @@ -211,16 +204,18 @@ uint16_t CX10_callback() NRF24L01_SetTxRxMode(TX_EN); if(packet[9] == 1) { - phase = CX10_BIND1; - bind_counter=0; + BIND_DONE; + phase = CX10_DATA; } } else { + // switch to TX mode NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_FlushTx(); NRF24L01_SetTxRxMode(TX_EN); CX10_Write_Packet(1); - _delay_us(1000); + _delay_us(400); // switch to RX mode NRF24L01_SetTxRxMode(TXRX_OFF); NRF24L01_FlushRx(); @@ -270,7 +265,6 @@ uint16_t initCX10(void) packet_period = CX10A_PACKET_PERIOD; phase = CX10_BIND2; - bind_counter=CX10A_BIND_COUNT; for(uint8_t i=0; i<4; i++) packet[5+i] = 0xff; // clear aircraft id diff --git a/Multiprotocol/NRF24l01_SPI.ino b/Multiprotocol/NRF24l01_SPI.ino index 4c947bf..ac67c06 100644 --- a/Multiprotocol/NRF24l01_SPI.ino +++ b/Multiprotocol/NRF24l01_SPI.ino @@ -258,7 +258,7 @@ uint8_t NRF24L01_packet_ack() /////////////// // XN297 emulation layer -uint8_t xn297_scramble_enabled; +uint8_t xn297_scramble_enabled=1; //enabled by default uint8_t xn297_addr_len; uint8_t xn297_tx_addr[5]; uint8_t xn297_rx_addr[5]; From a58b129503736a7064b82dd748dab21763b4f20e Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 19 Apr 2016 14:29:47 +0200 Subject: [PATCH 094/293] Orange module TAER order and Devo option --- Multiprotocol/Multiprotocol.cpp.xmega | 1 + Multiprotocol/_Config.h | 28 +++++++++++++++++++++++++-- 2 files changed, 27 insertions(+), 2 deletions(-) diff --git a/Multiprotocol/Multiprotocol.cpp.xmega b/Multiprotocol/Multiprotocol.cpp.xmega index 87ebf73..46967a0 100644 --- a/Multiprotocol/Multiprotocol.cpp.xmega +++ b/Multiprotocol/Multiprotocol.cpp.xmega @@ -460,6 +460,7 @@ void NRF24L01_Reset() #include "cyrf6936_SPI.ino" #include "DSM2_cyrf6936.ino" +#include "Devo_cyrf6936.ino" #include "Telemetry.ino" diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index c0942e4..e6d3394 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -16,7 +16,8 @@ /** Multiprotocol module configuration file ***/ //Uncomment your TX type -#define TX_ER9X //ER9X AETR (988<->2012µs) +#define TX_ER9X_AETR //ER9X AETR (988<->2012µs) +//#define TX_ER9X_TAER //ER9X TAER (988<->2012µs) //#define TX_DEVO7 //DEVO7 EATR (1120<->1920µs) //#define TX_SPEKTRUM //Spektrum TAER (1100<->1900µs) //#define TX_HISKY //HISKY AETR (1100<->1900µs) @@ -176,7 +177,7 @@ Option value between 0 and 255. 0xD7 or 0x00 for Frsky fine tuning. //TX definitions with timing endpoints and channels order // Turnigy PPM and channels -#if defined(TX_ER9X) +#if defined(TX_ER9X_AETR) #define PPM_MAX 2140 // 125% #define PPM_MIN 860 // 125% #define PPM_MAX_100 2012 // 100% @@ -198,6 +199,29 @@ enum chan_order{ }; #endif +// Turnigy PPM and channels +#if defined(TX_ER9X_TAER) +#define PPM_MAX 2140 // 125% +#define PPM_MIN 860 // 125% +#define PPM_MAX_100 2012 // 100% +#define PPM_MIN_100 988 // 100% +enum chan_order{ + THROTTLE =0, + AILERON, + ELEVATOR, + RUDDER, + AUX1, + AUX2, + AUX3, + AUX4, + AUX5, + AUX6, + AUX7, + AUX8, + AUX9 +}; +#endif + // Devo PPM and channels #if defined(TX_DEVO7) #define PPM_MAX 2100 // 125% From 9f75234daca2a64ee4db2cf028c73a0bfa5c013c Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 20 Apr 2016 17:34:28 +0200 Subject: [PATCH 095/293] Fix xmega compile issue when devo is added --- Multiprotocol/Multiprotocol.cpp.xmega | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Multiprotocol/Multiprotocol.cpp.xmega b/Multiprotocol/Multiprotocol.cpp.xmega index 46967a0..fa724a5 100644 --- a/Multiprotocol/Multiprotocol.cpp.xmega +++ b/Multiprotocol/Multiprotocol.cpp.xmega @@ -28,6 +28,8 @@ 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) ; extern void randomSeed(unsigned int seed) ; extern long random(long howbig) ; From 86d0b92a668032be660d0dc5a2bb92227a9fd386 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 20 Apr 2016 17:53:59 +0200 Subject: [PATCH 096/293] MultiOrange one more fix... --- .../{Multiprotocol.cpp.xmega => MultiOrange.cpp.xmega} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename Multiprotocol/{Multiprotocol.cpp.xmega => MultiOrange.cpp.xmega} (99%) diff --git a/Multiprotocol/Multiprotocol.cpp.xmega b/Multiprotocol/MultiOrange.cpp.xmega similarity index 99% rename from Multiprotocol/Multiprotocol.cpp.xmega rename to Multiprotocol/MultiOrange.cpp.xmega index fa724a5..eed1110 100644 --- a/Multiprotocol/Multiprotocol.cpp.xmega +++ b/Multiprotocol/MultiOrange.cpp.xmega @@ -29,7 +29,7 @@ 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) ; +extern uint16_t devo_callback(void) ; extern void randomSeed(unsigned int seed) ; extern long random(long howbig) ; From 5a5b8464fcdd35a554e911893b4376c6935667b1 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 20 Apr 2016 19:27:56 +0200 Subject: [PATCH 097/293] 4in1 module addition --- README.md | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index d5532c0..cb931df 100644 --- a/README.md +++ b/README.md @@ -245,17 +245,17 @@ You also need some [antennas](http://www.banggood.com/2_4GHz-3dBi-RP-SMA-Connect The main program is running on an ATMEGA328p running @16MHz and 3.3V. An [Arduino pro mini 16Mhz/5V](http://www.banggood.com/Wholesale-New-Ver-Pro-Mini-ATMEGA328-328p-5V-16MHz-Arduino-Compatible-Nano-Size-p-68534.html) powered at 3.3V (yes it works) can be used to build your own Multimodule. An Arduino Mini based on Atmega328p can also be used. -Using stripboard: +####Using stripboard: ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t8214655-87-thumb-uploadfromtaptalk1405598143749.jpg?d=1441459923) ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t8214656-102-thumb-uploadfromtaptalk1405598152484.jpg?d=1441459924) -Using a [home made PCB](http://www.rcgroups.com/forums/showpost.php?p=32645328&postcount=1621): +####Using a [home made PCB](http://www.rcgroups.com/forums/showpost.php?p=32645328&postcount=1621): ![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8226720-197-thumb-IMG_20150715_230603155.jpg?d=1441816457) ![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8226719-72-thumb-IMG_20150715_230024065.jpg?d=1441816456) -or build your own board using [SMD components](http://www.rcgroups.com/forums/showpost.php?p=31064232&postcount=1020) and an [associated PCB v2.3c](https://oshpark.com/shared_projects/MaGYDg0y): +####Build your own board using [SMD components](http://www.rcgroups.com/forums/showpost.php?p=31064232&postcount=1020) and an [associated PCB v2.3c](https://oshpark.com/shared_projects/MaGYDg0y): ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7566755-3-thumb-i.png?d=1423810885) ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7952726-108-thumb-image-62c29cf2.jpg?d=1433909893) @@ -274,6 +274,18 @@ lines through them. [OSH Park link](https://oshpark.com/shared_projects/Ztus1ah8) if you want to order. +####Buy a ready to use Multi module +![Screenshot](http://img.banggood.com/thumb/view/oaupload/banggood/images/1D/EB/19bb6434-4616-411e-b8fa-a4c21d9dca24.jpg) + +This module can be purchased [here](http://www.banggood.com/2_4G-CC2500-A7105-Flysky-Frsky-Devo-DSM2-Multiprotocol-TX-Module-With-Antenna-p-1048377.html) + +If you use this module and want to enable serial mode for er9x/ersky9x/Taranis/..., you have to do [this mod](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8895038-170-4in1%20module.jpg). + +There are currently some hardware issues with the first version of this 4in1 module: + - A7105 RF is forced to PA mode which prevents telemetry to work. Hubsan is the only protocol using telemetry for battery voltage display. + - NRF24L01 is forced to PA mode which prevents telemetry to work. There are currently no protocols using telemetry based on this RF chip. +Based on the Deviation forum these issues will be solved in the upcoming version. + ###Schematic ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8443844-119-multiprotocol_diagram_rotary_serial_2.jpg) From 0a845fdfa67375566bd71e608d2b6cd39a1906de Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 20 Apr 2016 19:29:05 +0200 Subject: [PATCH 098/293] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index cb931df..bf3d887 100644 --- a/README.md +++ b/README.md @@ -284,6 +284,7 @@ If you use this module and want to enable serial mode for er9x/ersky9x/Taranis/. There are currently some hardware issues with the first version of this 4in1 module: - A7105 RF is forced to PA mode which prevents telemetry to work. Hubsan is the only protocol using telemetry for battery voltage display. - NRF24L01 is forced to PA mode which prevents telemetry to work. There are currently no protocols using telemetry based on this RF chip. + Based on the Deviation forum these issues will be solved in the upcoming version. ###Schematic From 109fba828bef1bec0f3e8b51d97aeb3d8802911c Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 20 Apr 2016 19:44:34 +0200 Subject: [PATCH 099/293] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index bf3d887..1144eec 100644 --- a/README.md +++ b/README.md @@ -274,10 +274,10 @@ lines through them. [OSH Park link](https://oshpark.com/shared_projects/Ztus1ah8) if you want to order. -####Buy a ready to use Multi module +####Buy a ready to use and complete Multi module ![Screenshot](http://img.banggood.com/thumb/view/oaupload/banggood/images/1D/EB/19bb6434-4616-411e-b8fa-a4c21d9dca24.jpg) -This module can be purchased [here](http://www.banggood.com/2_4G-CC2500-A7105-Flysky-Frsky-Devo-DSM2-Multiprotocol-TX-Module-With-Antenna-p-1048377.html) +This module can be purchased [here](http://www.banggood.com/2_4G-CC2500-A7105-Flysky-Frsky-Devo-DSM2-Multiprotocol-TX-Module-With-Antenna-p-1048377.html). All the 4 RF modules are already implemented A7105, NRF24L01, CC2500 and CYRF6936. The board is also equiped with an antenna switcher which means only one antenna for all. If you use this module and want to enable serial mode for er9x/ersky9x/Taranis/..., you have to do [this mod](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8895038-170-4in1%20module.jpg). @@ -285,7 +285,7 @@ There are currently some hardware issues with the first version of this 4in1 mod - A7105 RF is forced to PA mode which prevents telemetry to work. Hubsan is the only protocol using telemetry for battery voltage display. - NRF24L01 is forced to PA mode which prevents telemetry to work. There are currently no protocols using telemetry based on this RF chip. -Based on the Deviation forum these issues will be solved in the upcoming version. +Based on the [Deviation forum](http://www.deviationtx.com/forum/7-development/5434-3in1-4in1-rf-module?start=280#46751) these issues will be solved in the upcoming version. ###Schematic ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8443844-119-multiprotocol_diagram_rotary_serial_2.jpg) From 80880f4d2a51ee80ddfb17167473d711d5a08c67 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 9 May 2016 15:37:46 +0200 Subject: [PATCH 100/293] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1144eec..8ab69db 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ Settings per selection are located in _Config.h: - Autobind: Yes or No. At the model selection (or power applied to the TX) a bind sequence will be initiated ###Using a serial output -The multiprotocol TX module takes full advantage of being used on a Turnigy 9X, 9XR, 9XR Pro, Taranis, 9Xtreme, AR9X, ... running [er9x or ersky9X](https://github.com/MikeBland/mbtx/tree/next). An OpenTX version for Taranis is being developped and available has a beta version for now. +The multiprotocol TX module takes full advantage of being used on a Turnigy 9X, 9XR, 9XR Pro, Taranis, 9Xtreme, AR9X, ... running [er9x](http://openrcforums.com/forum/viewtopic.php?f=5&t=4598) or [ersky9X](http://openrcforums.com/forum/viewtopic.php?f=7&t=4676). An OpenTX version for Taranis is available [here](http://plaisthos.de/opentx/). This enables full integration using the radio GUI to setup models with all the available protocols options. From 671a745acc03384bba8af620aac0050ec608e20a Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 9 May 2016 15:43:50 +0200 Subject: [PATCH 101/293] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 8ab69db..48a68af 100644 --- a/README.md +++ b/README.md @@ -279,7 +279,9 @@ lines through them. This module can be purchased [here](http://www.banggood.com/2_4G-CC2500-A7105-Flysky-Frsky-Devo-DSM2-Multiprotocol-TX-Module-With-Antenna-p-1048377.html). All the 4 RF modules are already implemented A7105, NRF24L01, CC2500 and CYRF6936. The board is also equiped with an antenna switcher which means only one antenna for all. -If you use this module and want to enable serial mode for er9x/ersky9x/Taranis/..., you have to do [this mod](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8895038-170-4in1%20module.jpg). +To update the firmware of this module you have to solder a 6 pin header (top left) and use an USBASP like explained [below](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#upload-the-code-using-isp-in-system-programming). + +If you want to enable serial mode for er9x/ersky9x/Taranis/..., you have to do [this mod](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8895038-170-4in1%20module.jpg). There are currently some hardware issues with the first version of this 4in1 module: - A7105 RF is forced to PA mode which prevents telemetry to work. Hubsan is the only protocol using telemetry for battery voltage display. From 487d90f260fecf55acf2e9ed02032c930259e278 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 10 May 2016 13:32:02 +0200 Subject: [PATCH 102/293] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 48a68af..6ad5e38 100644 --- a/README.md +++ b/README.md @@ -349,9 +349,9 @@ This will make sure your ATMEGA328 is well configured and the global TX ID is no ###LED status - off: program not running or a protocol selected with the associated module not installed. -- flash: invalid protocol selected (excluded from compilation or invalid protocol number) -- slow blink: serial has been selected but no valid signal has been seen on the RX pin. -- fast blink: bind in progress. +- flash(on=0.1s,off=1s): invalid protocol selected (excluded from compilation or invalid protocol number) +- slow blink(on=0.5s,off=0.5s): serial has been selected but no valid signal has been seen on the RX pin. +- fast blink(on=0.1s,off=0.1s): bind in progress. - on: normal operation. ###Protocol selection From b008f558476345e0e228bbedb97d9bf88e14d46d Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 27 Jul 2016 19:46:36 +0200 Subject: [PATCH 103/293] New BG board --- README.md | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 6ad5e38..04530c0 100644 --- a/README.md +++ b/README.md @@ -281,13 +281,9 @@ This module can be purchased [here](http://www.banggood.com/2_4G-CC2500-A7105-Fl To update the firmware of this module you have to solder a 6 pin header (top left) and use an USBASP like explained [below](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#upload-the-code-using-isp-in-system-programming). -If you want to enable serial mode for er9x/ersky9x/Taranis/..., you have to do [this mod](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8895038-170-4in1%20module.jpg). - -There are currently some hardware issues with the first version of this 4in1 module: - - A7105 RF is forced to PA mode which prevents telemetry to work. Hubsan is the only protocol using telemetry for battery voltage display. - - NRF24L01 is forced to PA mode which prevents telemetry to work. There are currently no protocols using telemetry based on this RF chip. - -Based on the [Deviation forum](http://www.deviationtx.com/forum/7-development/5434-3in1-4in1-rf-module?start=280#46751) these issues will be solved in the upcoming version. +If you want to enable serial mode for er9x/ersky9x/Taranis/... and depending on your board revision, you have to do one of these modifications: +- Add 2 resistors as shown here: ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8895038-170-4in1%20module.jpg) +- Solder pads together as shown by the yellow marks: ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a9204252-13-Taranis_serial.png) ###Schematic ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8443844-119-multiprotocol_diagram_rotary_serial_2.jpg) From 9e097be65753956445bc562a4debee71c83f5f97 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 27 Jul 2016 19:51:19 +0200 Subject: [PATCH 104/293] BG module needs to be flashed. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 04530c0..b63b803 100644 --- a/README.md +++ b/README.md @@ -279,7 +279,7 @@ lines through them. This module can be purchased [here](http://www.banggood.com/2_4G-CC2500-A7105-Flysky-Frsky-Devo-DSM2-Multiprotocol-TX-Module-With-Antenna-p-1048377.html). All the 4 RF modules are already implemented A7105, NRF24L01, CC2500 and CYRF6936. The board is also equiped with an antenna switcher which means only one antenna for all. -To update the firmware of this module you have to solder a 6 pin header (top left) and use an USBASP like explained [below](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#upload-the-code-using-isp-in-system-programming). +**It is highly recommended to update the firmware** of this board as it is distributed with a really old and bugged one. For this you have to solder a 6 pin header (top left) and use an USBASP like explained [below](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#upload-the-code-using-isp-in-system-programming). If you want to enable serial mode for er9x/ersky9x/Taranis/... and depending on your board revision, you have to do one of these modifications: - Add 2 resistors as shown here: ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8895038-170-4in1%20module.jpg) From bec8ba6c2f576ff36824fd16b8c6aba6bf546764 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 27 Jul 2016 19:58:50 +0200 Subject: [PATCH 105/293] BG board might need a resistor change to fix bind. --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index b63b803..ad773c5 100644 --- a/README.md +++ b/README.md @@ -285,6 +285,8 @@ If you want to enable serial mode for er9x/ersky9x/Taranis/... and depending on - Add 2 resistors as shown here: ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8895038-170-4in1%20module.jpg) - Solder pads together as shown by the yellow marks: ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a9204252-13-Taranis_serial.png) +Note: if your module is sometime binding at power up even without pressing the bind button or not having an autobind protocol, then you can solve your issue by replacing the BIND led resistor (on the board back) of 1.2K by a 4.7K (probably a 2.2K would work but untested). + ###Schematic ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8443844-119-multiprotocol_diagram_rotary_serial_2.jpg) From d2891a49fc8b7059a0e4448d2394d2a394cf80e7 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 27 Jul 2016 20:03:39 +0200 Subject: [PATCH 106/293] Update README.md --- README.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index ad773c5..bd5e4ae 100644 --- a/README.md +++ b/README.md @@ -282,10 +282,10 @@ This module can be purchased [here](http://www.banggood.com/2_4G-CC2500-A7105-Fl **It is highly recommended to update the firmware** of this board as it is distributed with a really old and bugged one. For this you have to solder a 6 pin header (top left) and use an USBASP like explained [below](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#upload-the-code-using-isp-in-system-programming). If you want to enable serial mode for er9x/ersky9x/Taranis/... and depending on your board revision, you have to do one of these modifications: -- Add 2 resistors as shown here: ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8895038-170-4in1%20module.jpg) -- Solder pads together as shown by the yellow marks: ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a9204252-13-Taranis_serial.png) +- 1st revision, add 2 resistors as shown here: ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8895038-170-4in1%20module.jpg) +- 2nd revision, solder pads together as shown by the yellow marks: ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a9204252-13-Taranis_serial.png) -Note: if your module is sometime binding at power up even without pressing the bind button or not having an autobind protocol, then you can solve your issue by replacing the BIND led resistor (on the board back) of 1.2K by a 4.7K (probably a 2.2K would work but untested). +Note: if you have the 1st board revision (check pictures above), sometime bind occures at power up even without pressing the bind button or not having an autobind protocol. To solve this issue, replacing the BIND led resistor (on the board back) of 1.2K by a 4.7K. ###Schematic ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8443844-119-multiprotocol_diagram_rotary_serial_2.jpg) From 5bf8b0a2b68b10f3f18e7aec077d0db288de4e66 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 27 Jul 2016 20:06:51 +0200 Subject: [PATCH 107/293] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index bd5e4ae..1d86003 100644 --- a/README.md +++ b/README.md @@ -283,7 +283,7 @@ This module can be purchased [here](http://www.banggood.com/2_4G-CC2500-A7105-Fl If you want to enable serial mode for er9x/ersky9x/Taranis/... and depending on your board revision, you have to do one of these modifications: - 1st revision, add 2 resistors as shown here: ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8895038-170-4in1%20module.jpg) -- 2nd revision, solder pads together as shown by the yellow marks: ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a9204252-13-Taranis_serial.png) +- 2nd revision, solder pads together as shown: ![Screenshot](http://static.rcgroups.net/forums/attachments/4/8/3/5/8/4/a9206217-177-IMG_5790.jpg) Note: if you have the 1st board revision (check pictures above), sometime bind occures at power up even without pressing the bind button or not having an autobind protocol. To solve this issue, replacing the BIND led resistor (on the board back) of 1.2K by a 4.7K. From b28cf30f47d145e032ac167d543db9243c4f6c76 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 27 Jul 2016 20:21:17 +0200 Subject: [PATCH 108/293] Update README.md --- README.md | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 1d86003..507d257 100644 --- a/README.md +++ b/README.md @@ -283,7 +283,9 @@ This module can be purchased [here](http://www.banggood.com/2_4G-CC2500-A7105-Fl If you want to enable serial mode for er9x/ersky9x/Taranis/... and depending on your board revision, you have to do one of these modifications: - 1st revision, add 2 resistors as shown here: ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8895038-170-4in1%20module.jpg) -- 2nd revision, solder pads together as shown: ![Screenshot](http://static.rcgroups.net/forums/attachments/4/8/3/5/8/4/a9206217-177-IMG_5790.jpg) +- 2nd revision, solder pads together as shown: + + Note: if you have the 1st board revision (check pictures above), sometime bind occures at power up even without pressing the bind button or not having an autobind protocol. To solve this issue, replacing the BIND led resistor (on the board back) of 1.2K by a 4.7K. @@ -295,11 +297,17 @@ Notes: - For serial, the dial switch is not needed and the bind button optionnal ###Radio integration -You can 3D print your box (details [here](http://www.rcgroups.com/forums/showpost.php?p=33294140&postcount=2034)): +If you build your own version of the board you can 3D print this case (details [here](http://www.rcgroups.com/forums/showpost.php?p=33294140&postcount=2034)): ![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8462144-54-thumb-Multi_case_9XR.jpg?d=1448575289) ![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8462145-106-thumb-Multi_case_v1.jpg?d=1448575293) +If you have the ready to use board you can 3D print this case (details [here](http://www.rcgroups.com/forums/showpost.php?p=35349049&postcount=3)): + + + + + ##Compilation and programmation ###Toolchain From 05cc4b4bd1e0642b9deb0279ec53e29316f8e52f Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 27 Jul 2016 20:22:24 +0200 Subject: [PATCH 109/293] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 507d257..094eb5e 100644 --- a/README.md +++ b/README.md @@ -302,7 +302,7 @@ If you build your own version of the board you can 3D print this case (details [ ![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8462144-54-thumb-Multi_case_9XR.jpg?d=1448575289) ![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8462145-106-thumb-Multi_case_v1.jpg?d=1448575293) -If you have the ready to use board you can 3D print this case (details [here](http://www.rcgroups.com/forums/showpost.php?p=35349049&postcount=3)): +If you have the Banggood ready to use board you can 3D print this case (details [here](http://www.rcgroups.com/forums/showpost.php?p=35349049&postcount=3)): From 9ab8b84d81fc84c9b46485e33b02eb8697baba1c Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 27 Jul 2016 20:55:53 +0200 Subject: [PATCH 110/293] Fixed Frsky telemetry --- Multiprotocol/FrSky_cc2500.ino | 2 +- Multiprotocol/Telemetry.ino | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/Multiprotocol/FrSky_cc2500.ino b/Multiprotocol/FrSky_cc2500.ino index 85f468e..6051524 100644 --- a/Multiprotocol/FrSky_cc2500.ino +++ b/Multiprotocol/FrSky_cc2500.ino @@ -195,7 +195,7 @@ uint16_t ReadFrSky_2way() if (state == FRSKY_DATA1) { len = CC2500_ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F; - if (len<=MAX_PKT)//27 bytes + if (len && len<=MAX_PKT)//27 bytes { CC2500_ReadData(pkt, len); //received telemetry packets #if defined(TELEMETRY) diff --git a/Multiprotocol/Telemetry.ino b/Multiprotocol/Telemetry.ino index a7d692a..cf8d8d6 100644 --- a/Multiprotocol/Telemetry.ino +++ b/Multiprotocol/Telemetry.ino @@ -64,7 +64,7 @@ void compute_RSSIdbm() void frsky_check_telemetry(uint8_t *pkt,uint8_t len) { - if(pkt[1] == rx_tx_addr[3] || pkt[2] == rx_tx_addr[2] || len ==(pkt[0] + 3)) + if(pkt[1] == rx_tx_addr[3] && pkt[2] == rx_tx_addr[2] && len ==(pkt[0] + 3)) { for (uint8_t i=3;i Date: Wed, 27 Jul 2016 22:06:13 +0200 Subject: [PATCH 111/293] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 094eb5e..78b2a67 100644 --- a/README.md +++ b/README.md @@ -313,7 +313,7 @@ If you have the Banggood ready to use board you can 3D print this case (details ###Toolchain Multiprotocol source can be compiled using the Arduino IDE. -The currently supported Arduino version is [1.6.7](https://www.arduino.cc/download_handler.php?f=/arduino-1.6.7-windows.exe). +The currently supported Arduino version is [1.6.9](http://arduino.cc/download_handler.php?f=/arduino-1.6.9-windows.exe). Download the [zip file](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/archive/master.zip) of this repository, unzip it in a folder, navigate to the Multiprotocol directory and then click on Multiprotocol.ino. The Arduino environment will appear and the Multiprotocol project will be loaded. From 32b962b036b14edc048375283f03cbafa510e4a7 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 27 Jul 2016 22:24:48 +0200 Subject: [PATCH 112/293] J6Pro protocol addition --- Multiprotocol/J6Pro_cyrf6936.ino | 282 +++++++++++++++++++++++++++++++ Multiprotocol/Multiprotocol.h | 6 +- Multiprotocol/Multiprotocol.ino | 8 + Multiprotocol/_Config.h | 3 + 4 files changed, 297 insertions(+), 2 deletions(-) create mode 100644 Multiprotocol/J6Pro_cyrf6936.ino diff --git a/Multiprotocol/J6Pro_cyrf6936.ino b/Multiprotocol/J6Pro_cyrf6936.ino new file mode 100644 index 0000000..ace2302 --- /dev/null +++ b/Multiprotocol/J6Pro_cyrf6936.ino @@ -0,0 +1,282 @@ +/* + 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(J6PRO_CYRF6936_INO) + +#include "iface_cyrf6936.h" + +enum PktState { + J6PRO_BIND, + J6PRO_BIND_01, + J6PRO_BIND_03_START, + J6PRO_BIND_03_CHECK, + J6PRO_BIND_05_1, + J6PRO_BIND_05_2, + J6PRO_BIND_05_3, + J6PRO_BIND_05_4, + J6PRO_BIND_05_5, + J6PRO_BIND_05_6, + J6PRO_CHANSEL, + J6PRO_CHAN_1, + J6PRO_CHAN_2, + J6PRO_CHAN_3, + J6PRO_CHAN_4, +}; + +const uint8_t j6pro_sopcodes[][8] = { + /* Note these are in order transmitted (LSB 1st) */ + {0x3C, 0x37, 0xCC, 0x91, 0xE2, 0xF8, 0xCC, 0x91}, + {0x9B, 0xC5, 0xA1, 0x0F, 0xAD, 0x39, 0xA2, 0x0F}, + {0xEF, 0x64, 0xB0, 0x2A, 0xD2, 0x8F, 0xB1, 0x2A}, + {0x66, 0xCD, 0x7C, 0x50, 0xDD, 0x26, 0x7C, 0x50}, + {0x5C, 0xE1, 0xF6, 0x44, 0xAD, 0x16, 0xF6, 0x44}, + {0x5A, 0xCC, 0xAE, 0x46, 0xB6, 0x31, 0xAE, 0x46}, + {0xA1, 0x78, 0xDC, 0x3C, 0x9E, 0x82, 0xDC, 0x3C}, + {0xB9, 0x8E, 0x19, 0x74, 0x6F, 0x65, 0x18, 0x74}, + {0xDF, 0xB1, 0xC0, 0x49, 0x62, 0xDF, 0xC1, 0x49}, + {0x97, 0xE5, 0x14, 0x72, 0x7F, 0x1A, 0x14, 0x72}, + {0x82, 0xC7, 0x90, 0x36, 0x21, 0x03, 0xFF, 0x17}, + {0xE2, 0xF8, 0xCC, 0x91, 0x3C, 0x37, 0xCC, 0x91}, //Note: the '03' was '9E' in the Cypress recommended table + {0xAD, 0x39, 0xA2, 0x0F, 0x9B, 0xC5, 0xA1, 0x0F}, //The following are the same as the 1st 8 above, + {0xD2, 0x8F, 0xB1, 0x2A, 0xEF, 0x64, 0xB0, 0x2A}, //but with the upper and lower word swapped + {0xDD, 0x26, 0x7C, 0x50, 0x66, 0xCD, 0x7C, 0x50}, + {0xAD, 0x16, 0xF6, 0x44, 0x5C, 0xE1, 0xF6, 0x44}, + {0xB6, 0x31, 0xAE, 0x46, 0x5A, 0xCC, 0xAE, 0x46}, + {0x9E, 0x82, 0xDC, 0x3C, 0xA1, 0x78, 0xDC, 0x3C}, + {0x6F, 0x65, 0x18, 0x74, 0xB9, 0x8E, 0x19, 0x74}, +}; +const uint8_t bind_sop_code[] = {0x62, 0xdf, 0xc1, 0x49, 0xdf, 0xb1, 0xc0, 0x49}; +const uint8_t data_code[] = {0x02, 0xf9, 0x93, 0x97, 0x02, 0xfa, 0x5c, 0xe3, 0x01, 0x2b, 0xf1, 0xdb, 0x01, 0x32, 0xbe, 0x6f}; + +static uint8_t radio_ch[4]; + +static void __attribute__((unused)) j6pro_build_bind_packet() +{ + packet[0] = 0x01; //Packet type + packet[1] = 0x01; //FIXME: What is this? Model number maybe? + packet[2] = 0x56; //FIXME: What is this? + packet[3] = cyrfmfg_id[0]; + packet[4] = cyrfmfg_id[1]; + packet[5] = cyrfmfg_id[2]; + packet[6] = cyrfmfg_id[3]; + packet[7] = cyrfmfg_id[4]; + packet[8] = cyrfmfg_id[5]; +} + +static void __attribute__((unused)) j6pro_build_data_packet() +{ + uint8_t num_channels = 8; + uint8_t i; + uint32_t upperbits = 0; + packet[0] = 0xaa; //FIXME what is this? + for (i = 0; i < 12; i++) { + if (i >= num_channels) { + packet[i+1] = 0xff; + continue; + } + int16_t value = map(Servo_data[i],PPM_MIN_100,PPM_MAX_100,0,1024); + if (value < 0) + value = 0; + if (value > 0x3ff) + value = 0x3ff; + packet[i+1] = value & 0xff; + upperbits |= (value >> 8) << (i * 2); + } + packet[13] = upperbits & 0xff; + packet[14] = (upperbits >> 8) & 0xff; + packet[15] = (upperbits >> 16) & 0xff; +} + +static void __attribute__((unused)) j6pro_cyrf_init() +{ + /* Initialise CYRF chip */ + CYRF_WriteRegister(CYRF_28_CLK_EN, 0x02); + CYRF_WriteRegister(CYRF_32_AUTO_CAL_TIME, 0x3c); + CYRF_WriteRegister(CYRF_35_AUTOCAL_OFFSET, 0x14); + CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, 0x05); + CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, 0x55); + CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25); + CYRF_SetPower(0x05); + CYRF_WriteRegister(CYRF_06_RX_CFG, 0x8a); + CYRF_SetPower(0x28); + CYRF_WriteRegister(CYRF_12_DATA64_THOLD, 0x0e); + CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0xee); + CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x00); + CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x00); + CYRF_ConfigDataCode(data_code, 16); + CYRF_WritePreamble(0x023333); + + CYRF_GetMfgData(cyrfmfg_id); + //Model match + cyrfmfg_id[3]+=RX_num; +} + +static void __attribute__((unused)) cyrf_bindinit() +{ +/* Use when binding */ + //0.060470# 03 2f + CYRF_WriteRegister(CYRF_03_TX_CFG, 0x28 | 0x07); //Use max power for binding in case there is no telem module + + CYRF_ConfigRFChannel(0x52); + CYRF_ConfigSOPCode(bind_sop_code); + CYRF_ConfigCRCSeed(0x0000); + CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4a); + CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); + //0.061511# 13 20 + + CYRF_ConfigRFChannel(0x52); + //0.062684# 0f 05 + CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25); + //0.062792# 0f 05 + CYRF_WriteRegister(CYRF_02_TX_CTRL, 0x40); + j6pro_build_bind_packet(); //01 01 e9 49 ec a9 c4 c1 ff + //CYRF_WriteDataPacketLen(packet, 0x09); +} + +static void __attribute__((unused)) cyrf_datainit() +{ +/* Use when already bound */ + //0.094007# 0f 05 + uint8_t sop_idx = (0xff & (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + cyrfmfg_id[3] - cyrfmfg_id[5])) % 19; + uint16_t crc = (0xff & (cyrfmfg_id[1] - cyrfmfg_id[4] + cyrfmfg_id[5])) | + ((0xff & (cyrfmfg_id[2] + cyrfmfg_id[3] - cyrfmfg_id[4] + cyrfmfg_id[5])) << 8); + CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25); + CYRF_ConfigSOPCode(j6pro_sopcodes[sop_idx]); + CYRF_ConfigCRCSeed(crc); +} + +static void __attribute__((unused)) j6pro_set_radio_channels() +{ + //FIXME: Query free channels + //lowest channel is 0x08, upper channel is 0x4d? + CYRF_FindBestChannels(radio_ch, 3, 5, 8, 77); + radio_ch[3] = radio_ch[0]; +} + +uint16_t ReadJ6Pro() +{ + uint32_t start; + + switch(phase) { + case J6PRO_BIND: + cyrf_bindinit(); + phase = J6PRO_BIND_01; + //no break because we want to send the 1st bind packet now + case J6PRO_BIND_01: + CYRF_ConfigRFChannel(0x52); + CYRF_SetTxRxMode(TX_EN); + //0.062684# 0f 05 + CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25); + //0.062684# 0f 05 + CYRF_WriteDataPacketLen(packet, 0x09); + phase = J6PRO_BIND_03_START; + return 3000; //3msec + case J6PRO_BIND_03_START: + { + start=micros(); + while (micros()-start < 500) // Wait max 500µs + if(CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x06) + break; + } + CYRF_ConfigRFChannel(0x53); + CYRF_SetTxRxMode(RX_EN); + CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4a); + CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); + phase = J6PRO_BIND_03_CHECK; + return 30000; //30msec + case J6PRO_BIND_03_CHECK: + { + uint8_t rx = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS); + if((rx & 0x1a) == 0x1a) { + rx = CYRF_ReadRegister(CYRF_0A_RX_LENGTH); + if(rx == 0x0f) { + rx = CYRF_ReadRegister(CYRF_09_RX_COUNT); + if(rx == 0x0f) { + //Expected and actual length are both 15 + CYRF_ReadDataPacketLen(packet, rx); + if (packet[0] == 0x03 && + packet[3] == cyrfmfg_id[0] && + packet[4] == cyrfmfg_id[1] && + packet[5] == cyrfmfg_id[2] && + packet[6] == cyrfmfg_id[3] && + packet[7] == cyrfmfg_id[4] && + packet[8] == cyrfmfg_id[5]) + { + //Send back Ack + packet[0] = 0x05; + CYRF_ConfigRFChannel(0x54); + CYRF_SetTxRxMode(TX_EN); + phase = J6PRO_BIND_05_1; + return 2000; //2msec + } + } + } + } + phase = J6PRO_BIND_01; + return 500; + } + case J6PRO_BIND_05_1: + case J6PRO_BIND_05_2: + case J6PRO_BIND_05_3: + case J6PRO_BIND_05_4: + case J6PRO_BIND_05_5: + case J6PRO_BIND_05_6: + CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25); + CYRF_WriteDataPacketLen(packet, 0x0f); + phase = phase + 1; + return 4600; //4.6msec + case J6PRO_CHANSEL: + BIND_DONE; + j6pro_set_radio_channels(); + cyrf_datainit(); + phase = J6PRO_CHAN_1; + case J6PRO_CHAN_1: + //Keep transmit power updated + CYRF_SetPower(0); + j6pro_build_data_packet(); + //return 3400; + case J6PRO_CHAN_2: + //return 3500; + case J6PRO_CHAN_3: + //return 3750 + case J6PRO_CHAN_4: + CYRF_ConfigRFChannel(radio_ch[phase - J6PRO_CHAN_1]); + CYRF_SetTxRxMode(TX_EN); + CYRF_WriteDataPacket(packet); + if (phase == J6PRO_CHAN_4) { + phase = J6PRO_CHAN_1; + return 13900; + } + phase = phase + 1; + return 3550; + } + return 0; +} + +uint16_t initJ6Pro() +{ + CYRF_Reset(); + j6pro_cyrf_init(); + + if(IS_AUTOBIND_FLAG_on) { + phase = J6PRO_BIND; + } + else { + phase = J6PRO_CHANSEL; + } + return 2400; +} + +#endif diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 4b5f8fa..69f84c4 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -49,7 +49,8 @@ enum PROTOCOLS MODE_MJXQ=18, // =>NRF24L01 MODE_SHENQI=19, // =>NRF24L01 MODE_FY326=20, // =>NRF24L01 - MODE_SFHSS=21 // =>CC2500 + MODE_SFHSS=21, // =>CC2500 + MODE_J6PRO=22 // =>CYRF6936 }; enum Flysky @@ -510,6 +511,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- SHENQI 19 FY326 20 SFHSS 21 + J6PRO 22 BindBit=> 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No @@ -576,4 +578,4 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- 2047 +125% Channels bits are concatenated to fit in 22 bytes like in SBUS protocol */ - \ No newline at end of file + diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index a1b3f3c..2e1cd67 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -463,6 +463,13 @@ static void protocol_init() remote_callback = devo_callback; break; #endif +#if defined(J6PRO_CYRF6936_INO) + case MODE_J6PRO: + CTRL2_on; //antenna RF4 + next_callback = initJ6Pro(); + remote_callback = ReadJ6Pro; + break; +#endif #if defined(HISKY_NRF24L01_INO) case MODE_HISKY: next_callback=initHiSky(); @@ -633,6 +640,7 @@ static void module_reset() break; case MODE_DSM2: case MODE_DEVO: + case MODE_J6PRO: CYRF_Reset(); break; default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY, MODE_MT99XX, MODE_MJXQ, MODE_SHENQI, MODE_FY326 diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index e6d3394..1f67300 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -36,6 +36,7 @@ #ifdef CYRF6936_INSTALLED #define DEVO_CYRF6936_INO #define DSM2_CYRF6936_INO + #define J6PRO_CYRF6936_INO #endif #ifdef CC2500_INSTALLED #define FRSKY_CC2500_INO @@ -163,6 +164,8 @@ const PPM_Parameters PPM_prot[15]= { NONE MODE_SFHSS NONE + MODE_J6PRO + NONE RX_Num value between 0 and 15 From ed807e0fe5493624157c51517ed43dd0ea27ab98 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 28 Jul 2016 13:02:48 +0200 Subject: [PATCH 113/293] Add J6Pro in protocol list --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 78b2a67..a5a39cb 100644 --- a/README.md +++ b/README.md @@ -173,6 +173,7 @@ DSM2| |DSM2 |DSMX Devo| +J6Pro| #####NRF24L01 RF module Protocol|Sub_protocol From 9d981b09ca444b6573d4a5404434cf9f5068dfb5 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 28 Jul 2016 14:56:48 +0200 Subject: [PATCH 114/293] Add J6Pro channels --- Protocols_Details.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index e6fa761..0c5ceb7 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -117,7 +117,7 @@ option=number of channels and frame rate: - 11 : 11 channels @22ms - 12 : 12 channels @22ms -6 is usually giving the best results with most of the RX. +Value 6 is usually giving the best results with most of the RX. CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 ---|---|---|---|---|---|---|---|---|----|----|---- @@ -126,6 +126,12 @@ A|E|T|R|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 ###Sub_protocol DSMX Same as above +##J6Pro + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 +---|---|---|---|---|---|---|---|---|----|----|---- +A|E|T|R|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 + *** #NRF24L01 RF Module From fd4ff00ee22124a5d705d1eddbd0b70f9dc4bc5a Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 28 Jul 2016 15:01:24 +0200 Subject: [PATCH 115/293] J6Pro channel remapping --- Multiprotocol/J6Pro_cyrf6936.ino | 39 ++++++++++++-------------------- 1 file changed, 15 insertions(+), 24 deletions(-) diff --git a/Multiprotocol/J6Pro_cyrf6936.ino b/Multiprotocol/J6Pro_cyrf6936.ino index ace2302..e434460 100644 --- a/Multiprotocol/J6Pro_cyrf6936.ino +++ b/Multiprotocol/J6Pro_cyrf6936.ino @@ -60,8 +60,6 @@ const uint8_t j6pro_sopcodes[][8] = { const uint8_t bind_sop_code[] = {0x62, 0xdf, 0xc1, 0x49, 0xdf, 0xb1, 0xc0, 0x49}; const uint8_t data_code[] = {0x02, 0xf9, 0x93, 0x97, 0x02, 0xfa, 0x5c, 0xe3, 0x01, 0x2b, 0xf1, 0xdb, 0x01, 0x32, 0xbe, 0x6f}; -static uint8_t radio_ch[4]; - static void __attribute__((unused)) j6pro_build_bind_packet() { packet[0] = 0x01; //Packet type @@ -77,20 +75,14 @@ static void __attribute__((unused)) j6pro_build_bind_packet() static void __attribute__((unused)) j6pro_build_data_packet() { - uint8_t num_channels = 8; uint8_t i; uint32_t upperbits = 0; + uint16_t value; + const uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8}; packet[0] = 0xaa; //FIXME what is this? - for (i = 0; i < 12; i++) { - if (i >= num_channels) { - packet[i+1] = 0xff; - continue; - } - int16_t value = map(Servo_data[i],PPM_MIN_100,PPM_MAX_100,0,1024); - if (value < 0) - value = 0; - if (value > 0x3ff) - value = 0x3ff; + for (i = 0; i < 12; i++) + { + value = convert_channel_10b(ch[i]); packet[i+1] = value & 0xff; upperbits |= (value >> 8) << (i * 2); } @@ -127,7 +119,7 @@ static void __attribute__((unused)) cyrf_bindinit() { /* Use when binding */ //0.060470# 03 2f - CYRF_WriteRegister(CYRF_03_TX_CFG, 0x28 | 0x07); //Use max power for binding in case there is no telem module + CYRF_SetPower(0x28); //Deviation using max power, replaced by bind power... CYRF_ConfigRFChannel(0x52); CYRF_ConfigSOPCode(bind_sop_code); @@ -161,15 +153,16 @@ static void __attribute__((unused)) j6pro_set_radio_channels() { //FIXME: Query free channels //lowest channel is 0x08, upper channel is 0x4d? - CYRF_FindBestChannels(radio_ch, 3, 5, 8, 77); - radio_ch[3] = radio_ch[0]; + CYRF_FindBestChannels(hopping_frequency, 3, 5, 8, 77); + hopping_frequency[3] = hopping_frequency[0]; } uint16_t ReadJ6Pro() { uint32_t start; - switch(phase) { + switch(phase) + { case J6PRO_BIND: cyrf_bindinit(); phase = J6PRO_BIND_01; @@ -184,12 +177,10 @@ uint16_t ReadJ6Pro() phase = J6PRO_BIND_03_START; return 3000; //3msec case J6PRO_BIND_03_START: - { - start=micros(); - while (micros()-start < 500) // Wait max 500µs - if(CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x06) - break; - } + start=micros(); + while (micros()-start < 500) // Wait max 500µs + if(CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x06) + break; CYRF_ConfigRFChannel(0x53); CYRF_SetTxRxMode(RX_EN); CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4a); @@ -252,7 +243,7 @@ uint16_t ReadJ6Pro() case J6PRO_CHAN_3: //return 3750 case J6PRO_CHAN_4: - CYRF_ConfigRFChannel(radio_ch[phase - J6PRO_CHAN_1]); + CYRF_ConfigRFChannel(hopping_frequency[phase - J6PRO_CHAN_1]); CYRF_SetTxRxMode(TX_EN); CYRF_WriteDataPacket(packet); if (phase == J6PRO_CHAN_4) { From 8ea42ea432f42aa60274e74f62f1d39e14c2c73e Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 28 Jul 2016 20:58:12 +0200 Subject: [PATCH 116/293] Couple of optimizations --- Multiprotocol/ESky_nrf24l01.ino | 5 ++--- Multiprotocol/FlySky_a7105.ino | 5 ++--- Multiprotocol/Hisky_nrf24l01.ino | 3 +-- Multiprotocol/J6Pro_cyrf6936.ino | 3 +-- Multiprotocol/Multiprotocol.ino | 16 ++++++++++++++++ Multiprotocol/SFHSS_cc2500.ino | 10 ++++------ Multiprotocol/SLT_nrf24l01.ino | 3 +-- 7 files changed, 27 insertions(+), 18 deletions(-) diff --git a/Multiprotocol/ESky_nrf24l01.ino b/Multiprotocol/ESky_nrf24l01.ino index 1ed7d3d..9281697 100644 --- a/Multiprotocol/ESky_nrf24l01.ino +++ b/Multiprotocol/ESky_nrf24l01.ino @@ -117,11 +117,10 @@ static void __attribute__((unused)) ESKY_send_packet(uint8_t bind) // For arithmetic simplicity, channels are repeated in rf_channels array if (hopping_frequency_no == 0) { - const uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2}; for (uint8_t i = 0; i < 6; i++) { - packet[i*2] = Servo_data[ch[i]]>>8; //high byte of servo timing(1000-2000us) - packet[i*2+1] = Servo_data[ch[i]]&0xFF; //low byte of servo timing(1000-2000us) + packet[i*2] = Servo_data[CH_AETR[i]]>>8; //high byte of servo timing(1000-2000us) + packet[i*2+1] = Servo_data[CH_AETR[i]]&0xFF; //low byte of servo timing(1000-2000us) } } rf_ch = hopping_frequency[hopping_frequency_no]; diff --git a/Multiprotocol/FlySky_a7105.ino b/Multiprotocol/FlySky_a7105.ino index 4810b5d..92f723d 100644 --- a/Multiprotocol/FlySky_a7105.ino +++ b/Multiprotocol/FlySky_a7105.ino @@ -142,11 +142,10 @@ static void __attribute__((unused)) flysky_build_packet(uint8_t init) packet[2] = rx_tx_addr[2]; packet[3] = rx_tx_addr[1]; packet[4] = rx_tx_addr[0]; - const uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4}; for(i = 0; i < 8; i++) { - packet[5 + i*2]=Servo_data[ch[i]]&0xFF; //low byte of servo timing(1000-2000us) - packet[6 + i*2]=(Servo_data[ch[i]]>>8)&0xFF; //high byte of servo timing(1000-2000us) + packet[5 + i*2]=Servo_data[CH_AETR[i]]&0xFF; //low byte of servo timing(1000-2000us) + packet[6 + i*2]=(Servo_data[CH_AETR[i]]>>8)&0xFF; //high byte of servo timing(1000-2000us) } flysky_apply_extension_flags(); } diff --git a/Multiprotocol/Hisky_nrf24l01.ino b/Multiprotocol/Hisky_nrf24l01.ino index c6edabe..36c35b8 100644 --- a/Multiprotocol/Hisky_nrf24l01.ino +++ b/Multiprotocol/Hisky_nrf24l01.ino @@ -120,9 +120,8 @@ static void __attribute__((unused)) build_ch_data() { uint16_t temp; uint8_t i,j; - const uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4}; for (i = 0; i< 8; i++) { - j=ch[i]; + j=CH_AETR[i]; temp=map(limit_channel_100(j),PPM_MIN_100,PPM_MAX_100,0,1000); if (j == THROTTLE) // It is clear that hisky's throttle stick is made reversely, so I adjust it here on purpose temp = 1000 -temp; diff --git a/Multiprotocol/J6Pro_cyrf6936.ino b/Multiprotocol/J6Pro_cyrf6936.ino index e434460..f82bb70 100644 --- a/Multiprotocol/J6Pro_cyrf6936.ino +++ b/Multiprotocol/J6Pro_cyrf6936.ino @@ -78,11 +78,10 @@ static void __attribute__((unused)) j6pro_build_data_packet() uint8_t i; uint32_t upperbits = 0; uint16_t value; - const uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8}; packet[0] = 0xaa; //FIXME what is this? for (i = 0; i < 12; i++) { - value = convert_channel_10b(ch[i]); + value = convert_channel_10b(CH_AETR[i]); packet[i+1] = value & 0xff; upperbits |= (value >> 8) << (i * 2); } diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 2e1cd67..820e11c 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -74,6 +74,11 @@ uint8_t RX_num; uint8_t calData[48][3]; #endif +//Channel mapping for protocols +const uint8_t CH_AETR[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8}; +//const uint8_t CH_TAER[]={THROTTLE, AILERON, ELEVATOR, RUDDER, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8}; +//const uint8_t CH_RETA[]={RUDDER, ELEVATOR, THROTTLE, AILERON, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8}; + // Mode_select variables uint8_t mode_select; uint8_t protocol_flags=0,protocol_flags2=0; @@ -650,6 +655,17 @@ static void module_reset() } } +int16_t map( int16_t x, int16_t in_min, int16_t in_max, int16_t out_min, int16_t out_max) +{ +// return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; + long y ; + x -= in_min ; + y = out_max - out_min ; + y *= x ; + x = y / (in_max - in_min) ; + return x + out_min ; +} + // Channel value is converted to 8bit values full scale uint8_t convert_channel_8b(uint8_t num) { diff --git a/Multiprotocol/SFHSS_cc2500.ino b/Multiprotocol/SFHSS_cc2500.ino index 4a8b545..29f1880 100644 --- a/Multiprotocol/SFHSS_cc2500.ino +++ b/Multiprotocol/SFHSS_cc2500.ino @@ -135,12 +135,10 @@ static void __attribute__((unused)) SFHSS_build_data_packet() #define spacer1 0x02 //0b10 #define spacer2 (spacer1 << 4) uint8_t ch_offset = state == SFHSS_DATA1 ? 0 : 4; - const uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4}; - - uint16_t ch1 = SFHSS_convert_channel(ch[ch_offset+0]); - uint16_t ch2 = SFHSS_convert_channel(ch[ch_offset+1]); - uint16_t ch3 = SFHSS_convert_channel(ch[ch_offset+2]); - uint16_t ch4 = SFHSS_convert_channel(ch[ch_offset+3]); + uint16_t ch1 = SFHSS_convert_channel(CH_AETR[ch_offset+0]); + uint16_t ch2 = SFHSS_convert_channel(CH_AETR[ch_offset+1]); + uint16_t ch3 = SFHSS_convert_channel(CH_AETR[ch_offset+2]); + uint16_t ch4 = SFHSS_convert_channel(CH_AETR[ch_offset+3]); packet[0] = 0x81; // can be 80, 81, 81 for Orange, only 81 for XK packet[1] = rx_tx_addr[0]; diff --git a/Multiprotocol/SLT_nrf24l01.ino b/Multiprotocol/SLT_nrf24l01.ino index e97ae54..0622b55 100644 --- a/Multiprotocol/SLT_nrf24l01.ino +++ b/Multiprotocol/SLT_nrf24l01.ino @@ -111,9 +111,8 @@ static void __attribute__((unused)) SLT_build_packet() { // aileron, elevator, throttle, rudder, gear, pitch uint8_t e = 0; // byte where extension 2 bits for every 10-bit channel are packed - const uint8_t ch[]={AILERON, ELEVATOR, THROTTLE, RUDDER}; for (uint8_t i = 0; i < 4; ++i) { - uint16_t v = convert_channel_10b(ch[i]); + uint16_t v = convert_channel_10b(CH_AETR[i]); packet[i] = v; e = (e >> 2) | (uint8_t) ((v >> 2) & 0xC0); } From 6134ce39d4ef53bf50eb0f0c52c506eb1d29e8e3 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 29 Jul 2016 11:31:12 +0200 Subject: [PATCH 117/293] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a5a39cb..da5a2e3 100644 --- a/README.md +++ b/README.md @@ -215,6 +215,7 @@ MT99XX| |MT |H7 |YZ + |LS MJXQ| |WLH08 |X600 From 3abd8596641561445951788a24d67a374c50dbd6 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 29 Jul 2016 11:33:48 +0200 Subject: [PATCH 118/293] Update Protocols_Details.md --- Protocols_Details.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index 0c5ceb7..fa84b08 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -295,6 +295,8 @@ Models: Eachine H7, Cheerson CX023 ###Sub_protocol YZ Model: Yi Zhan i6S Only one model can be flown at the same time since the ID is hardcoded. +###Sub_protocol LS +Models: LS114, 124 ##Shenqi Autobind protocol From fd7b81af102e9e1f97c4d9a898d57153b1bd0b5a Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 29 Jul 2016 22:54:30 +0200 Subject: [PATCH 119/293] Add FQ777 --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index da5a2e3..151dd1d 100644 --- a/README.md +++ b/README.md @@ -223,6 +223,7 @@ MJXQ| |H26D Shenqi| FY326| +FQ777| Note: - The dial should be set to 0 for serial. Which means all protocol selection pins should be left unconnected. From 8dc5ae4f867b53e95e71b51876cc3c87f3ea2ce3 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 29 Jul 2016 23:03:49 +0200 Subject: [PATCH 120/293] Add FQ777 --- Protocols_Details.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index fa84b08..92ebbd4 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -244,6 +244,12 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 ---|---|---|---|---|---|---|---|--- A|E|T|R|FLIP|RTH|HEADLESS|EXPERT|CALIBRATE +##FQ777 + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +---|---|---|---|---|---|---|--- +A|E|T|R|FLIP|RTH|HEADLESS|EXPERT + ##HISKY CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- From 6d546094efed966f32501d53404eb5452fd451d0 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 1 Aug 2016 21:57:18 +0200 Subject: [PATCH 121/293] New protocols and optimizations New protocols: - FQ777 for FQ777-124 - MT99xx -> "LS" for 114/124 --- Multiprotocol/A7105_SPI.ino | 61 +++------ Multiprotocol/CC2500_SPI.ino | 65 ++-------- Multiprotocol/CX10_nrf24l01.ino | 2 +- Multiprotocol/CYRF6936_SPI.ino | 85 +++---------- Multiprotocol/FQ777_nrf24l01.ino | 205 ++++++++++++++++++++++++++++++ Multiprotocol/Hubsan_a7105.ino | 4 +- Multiprotocol/MT99xx_nrf24l01.ino | 118 +++++++++++------ Multiprotocol/Multiprotocol.h | 8 +- Multiprotocol/Multiprotocol.ino | 172 ++++++++++++++++++++++++- Multiprotocol/NRF24l01_SPI.ino | 102 +++++---------- Multiprotocol/SFHSS_cc2500.ino | 35 ++--- Multiprotocol/Symax_nrf24l01.ino | 8 +- Multiprotocol/_Config.h | 4 + Multiprotocol/iface_nrf24l01.h | 6 +- 14 files changed, 576 insertions(+), 299 deletions(-) create mode 100644 Multiprotocol/FQ777_nrf24l01.ino diff --git a/Multiprotocol/A7105_SPI.ino b/Multiprotocol/A7105_SPI.ino index 16f5869..15c0b56 100644 --- a/Multiprotocol/A7105_SPI.ino +++ b/Multiprotocol/A7105_SPI.ino @@ -24,10 +24,10 @@ void A7105_WriteData(uint8_t len, uint8_t channel) { uint8_t i; CS_off; - A7105_Write(A7105_RST_WRPTR); - A7105_Write(0x05); + SPI_Write(A7105_RST_WRPTR); + SPI_Write(0x05); for (i = 0; i < len; i++) - A7105_Write(packet[i]); + SPI_Write(packet[i]); CS_on; A7105_WriteReg(0x0F, channel); A7105_Strobe(A7105_TX); @@ -37,7 +37,7 @@ void A7105_ReadData() { uint8_t i; A7105_Strobe(0xF0); //A7105_RST_RDPTR CS_off; - A7105_Write(0x45); + SPI_Write(0x45); for (i=0;i<16;i++) packet[i]=A7105_Read(); CS_on; @@ -45,53 +45,34 @@ void A7105_ReadData() { void A7105_WriteReg(uint8_t address, uint8_t data) { CS_off; - A7105_Write(address); + SPI_Write(address); NOP(); - A7105_Write(data); + SPI_Write(data); CS_on; } uint8_t A7105_ReadReg(uint8_t address) { uint8_t result; CS_off; - A7105_Write(address |=0x40); //bit 6 =1 for reading + SPI_Write(address |=0x40); //bit 6 =1 for reading result = A7105_Read(); CS_on; return(result); } -void A7105_Write(uint8_t command) { - uint8_t n=8; - - SCK_off;//SCK start low - SDI_off; - while(n--) { - if(command&0x80) - SDI_on; - else - SDI_off; - SCK_on; - NOP(); - SCK_off; - command = command << 1; - } - SDI_on; -} - -uint8_t A7105_Read(void) { - uint8_t result=0; +uint8_t A7105_Read(void) +{ + uint8_t result; uint8_t i; - SDI_SET_INPUT; - for(i=0;i<8;i++) { + for(i=0;i<8;i++) + { + result=result<<1; if(SDI_1) ///if SDIO =1 - result=(result<<1)|0x01; - else - result=result<<1; + result |= 0x01; SCK_on; NOP(); SCK_off; - NOP(); } SDI_SET_OUTPUT; return result; @@ -122,7 +103,7 @@ uint8_t A7105_Reset() uint8_t result; A7105_WriteReg(0x00, 0x00); - _delay_us(1000); + delayMicroseconds(1000); A7105_SetTxRxMode(TXRX_OFF); //Set both GPIO as output and low result=A7105_ReadReg(0x10) == 0x9E; //check if is reset. A7105_Strobe(A7105_STANDBY); @@ -131,11 +112,11 @@ uint8_t A7105_Reset() void A7105_WriteID(uint32_t ida) { CS_off; - A7105_Write(0x06);//ex id=0x5475c52a ;txid3txid2txid1txid0 - A7105_Write((ida>>24)&0xff);//53 - A7105_Write((ida>>16)&0xff);//75 - A7105_Write((ida>>8)&0xff);//c5 - A7105_Write((ida>>0)&0xff);//2a + SPI_Write(0x06);//ex id=0x5475c52a ;txid3txid2txid1txid0 + SPI_Write((ida>>24)&0xff);//53 + SPI_Write((ida>>16)&0xff);//75 + SPI_Write((ida>>8)&0xff);//c5 + SPI_Write((ida>>0)&0xff);//2a CS_on; } @@ -179,7 +160,7 @@ void A7105_SetPower() void A7105_Strobe(uint8_t address) { CS_off; - A7105_Write(address); + SPI_Write(address); CS_on; } diff --git a/Multiprotocol/CC2500_SPI.ino b/Multiprotocol/CC2500_SPI.ino index 34f1b73..67ea66c 100644 --- a/Multiprotocol/CC2500_SPI.ino +++ b/Multiprotocol/CC2500_SPI.ino @@ -28,9 +28,9 @@ void CC2500_ReadData(uint8_t *dpbuffer, uint8_t len) static void CC2500_ReadRegisterMulti(uint8_t address, uint8_t data[], uint8_t length) { CC25_CSN_off; - CC2500_SPI_Write(address); + SPI_Write(address); for(uint8_t i = 0; i < length; i++) - data[i] = CC2500_SPI_Read(); + data[i] = SPI_Read(); CC25_CSN_on; } @@ -39,9 +39,9 @@ static void CC2500_ReadRegisterMulti(uint8_t address, uint8_t data[], uint8_t le static void CC2500_WriteRegisterMulti(uint8_t address, const uint8_t data[], uint8_t length) { CC25_CSN_off; - CC2500_SPI_Write(CC2500_WRITE_BURST | address); + SPI_Write(CC2500_WRITE_BURST | address); for(uint8_t i = 0; i < length; i++) - CC2500_SPI_Write(data[i]); + SPI_Write(data[i]); CC25_CSN_on; } @@ -52,62 +52,23 @@ void CC2500_WriteData(uint8_t *dpbuffer, uint8_t len) CC2500_Strobe(CC2500_STX);//0x35 } -//-------------------------------------- -static void CC2500_SPI_Write(uint8_t command) { - uint8_t n=8; - - SCK_off;//SCK start low - SDI_off; - while(n--) - { - if(command&0x80) - SDI_on; - else - SDI_off; - SCK_on; - NOP(); - SCK_off; - command = command << 1; - } - SDI_on; -} - //---------------------------- void CC2500_WriteReg(uint8_t address, uint8_t data) {//same as 7105 CC25_CSN_off; - CC2500_SPI_Write(address); + SPI_Write(address); NOP(); - CC2500_SPI_Write(data); + SPI_Write(data); CC25_CSN_on; } -static uint8_t CC2500_SPI_Read(void) -{ - uint8_t result; - uint8_t i; - result=0; - for(i=0;i<8;i++) - { - if(SDO_1) /// - result=(result<<1)|0x01; - else - result=result<<1; - SCK_on; - NOP(); - SCK_off; - NOP(); - } - return result; -} - //-------------------------------------------- static uint8_t CC2500_ReadReg(uint8_t address) { uint8_t result; CC25_CSN_off; address |=0x80; //bit 7 =1 for reading - CC2500_SPI_Write(address); - result = CC2500_SPI_Read(); + SPI_Write(address); + result = SPI_Read(); CC25_CSN_on; return(result); } @@ -115,7 +76,7 @@ static uint8_t CC2500_ReadReg(uint8_t address) void CC2500_Strobe(uint8_t address) { CC25_CSN_off; - CC2500_SPI_Write(address); + SPI_Write(address); CC25_CSN_on; } //------------------------ @@ -123,11 +84,11 @@ void CC2500_Strobe(uint8_t address) { // Toggle chip select signal CC25_CSN_on; - _delay_us(30); + delayMicroseconds(30); CC25_CSN_off; - _delay_us(30); + delayMicroseconds(30); CC25_CSN_on; - _delay_us(45); + delayMicroseconds(45); CC2500_Strobe(CC2500_SRES); _delay_ms(100); } @@ -135,7 +96,7 @@ void CC2500_Strobe(uint8_t address) uint8_t CC2500_Reset() { CC2500_Strobe(CC2500_SRES); - _delay_us(1000); + delayMicroseconds(1000); CC2500_SetTxRxMode(TXRX_OFF); return CC2500_ReadReg(CC2500_0E_FREQ1) == 0xC4;//check if reset } diff --git a/Multiprotocol/CX10_nrf24l01.ino b/Multiprotocol/CX10_nrf24l01.ino index 434f22a..ae39f23 100644 --- a/Multiprotocol/CX10_nrf24l01.ino +++ b/Multiprotocol/CX10_nrf24l01.ino @@ -215,7 +215,7 @@ uint16_t CX10_callback() NRF24L01_FlushTx(); NRF24L01_SetTxRxMode(TX_EN); CX10_Write_Packet(1); - _delay_us(400); + delayMicroseconds(400); // switch to RX mode NRF24L01_SetTxRxMode(TXRX_OFF); NRF24L01_FlushRx(); diff --git a/Multiprotocol/CYRF6936_SPI.ino b/Multiprotocol/CYRF6936_SPI.ino index bb4cc23..51a9b08 100644 --- a/Multiprotocol/CYRF6936_SPI.ino +++ b/Multiprotocol/CYRF6936_SPI.ino @@ -14,63 +14,12 @@ */ #include "iface_cyrf6936.h" -#ifdef XMEGA -#define XNOP() NOP() -#else -#define XNOP() -#endif - -static void cyrf_spi_write(uint8_t command) -{ - uint8_t n=8; - SCK_off;//SCK start low - XNOP() ; - SDI_off; - XNOP() ; - while(n--) { - if(command&0x80) - SDI_on; - else - SDI_off; - XNOP() ; - SCK_on; - NOP(); - XNOP() ; - XNOP() ; - SCK_off; - command = command << 1; - XNOP() ; - } - SDI_on; -} - -static uint8_t cyrf_spi_read() -{ - uint8_t result; - uint8_t i; - result=0; - for(i=0;i<8;i++) - { - result<<=1; - if(SDO_1) /// - result|=0x01; - SCK_on; - XNOP() ; - XNOP() ; - NOP(); - SCK_off; - XNOP() ; - XNOP() ; - NOP(); - } - return result; -} void CYRF_WriteRegister(uint8_t address, uint8_t data) { CYRF_CSN_off; - cyrf_spi_write(0x80 | address); - cyrf_spi_write(data); + SPI_Write(0x80 | address); + SPI_Write(data); CYRF_CSN_on; } @@ -79,9 +28,9 @@ static void CYRF_WriteRegisterMulti(uint8_t address, const uint8_t data[], uint8 uint8_t i; CYRF_CSN_off; - cyrf_spi_write(0x80 | address); + SPI_Write(0x80 | address); for(i = 0; i < length; i++) - cyrf_spi_write(data[i]); + SPI_Write(data[i]); CYRF_CSN_on; } @@ -90,9 +39,9 @@ static void CYRF_ReadRegisterMulti(uint8_t address, uint8_t data[], uint8_t leng uint8_t i; CYRF_CSN_off; - cyrf_spi_write(address); + SPI_Write(address); for(i = 0; i < length; i++) - data[i] = cyrf_spi_read(); + data[i] = SPI_Read(); CYRF_CSN_on; } @@ -100,8 +49,8 @@ uint8_t CYRF_ReadRegister(uint8_t address) { uint8_t data; CYRF_CSN_off; - cyrf_spi_write(address); - data = cyrf_spi_read(); + SPI_Write(address); + data = SPI_Read(); CYRF_CSN_on; return data; } @@ -110,11 +59,11 @@ uint8_t CYRF_ReadRegister(uint8_t address) uint8_t CYRF_Reset() { CYRF_WriteRegister(CYRF_1D_MODE_OVERRIDE, 0x01);//software reset - _delay_us(200);// + delayMicroseconds(200);// // RS_HI; - // _delay_us(100); + // delayMicroseconds(100); // RS_LO; - // _delay_us(100); + // delayMicroseconds(100); CYRF_WriteRegister(CYRF_0C_XTAL_CTRL, 0xC0); //Enable XOUT as GPIO CYRF_WriteRegister(CYRF_0D_IO_CFG, 0x04); //Enable PACTL as GPIO CYRF_SetTxRxMode(TXRX_OFF); @@ -211,10 +160,10 @@ void CYRF_ConfigDataCode(const uint8_t *datacodes, uint8_t len) void CYRF_WritePreamble(uint32_t preamble) { CYRF_CSN_off; - cyrf_spi_write(0x80 | 0x24); - cyrf_spi_write(preamble & 0xff); - cyrf_spi_write((preamble >> 8) & 0xff); - cyrf_spi_write((preamble >> 16) & 0xff); + SPI_Write(0x80 | 0x24); + SPI_Write(preamble & 0xff); + SPI_Write((preamble >> 8) & 0xff); + SPI_Write((preamble >> 16) & 0xff); CYRF_CSN_on; } /* @@ -277,13 +226,13 @@ void CYRF_FindBestChannels(uint8_t *channels, uint8_t len, uint8_t minspace, uin CYRF_ConfigCRCSeed(0x0000); CYRF_SetTxRxMode(RX_EN); //Wait for pre-amp to switch from send to receive - _delay_us(1000); + delayMicroseconds(1000); for(i = 0; i < NUM_FREQ; i++) { CYRF_ConfigRFChannel(i); CYRF_ReadRegister(CYRF_13_RSSI); CYRF_StartReceive(); - _delay_us(10); + delayMicroseconds(10); rssi[i] = CYRF_ReadRegister(CYRF_13_RSSI); } diff --git a/Multiprotocol/FQ777_nrf24l01.ino b/Multiprotocol/FQ777_nrf24l01.ino new file mode 100644 index 0000000..c73f89c --- /dev/null +++ b/Multiprotocol/FQ777_nrf24l01.ino @@ -0,0 +1,205 @@ +/* + 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 . + */ +// Last sync with bikemike FQ777-124.ino + +#if defined(FQ777_NRF24L01_INO) + +#include "iface_nrf24l01.h" + +#define FQ777_INITIAL_WAIT 500 +#define FQ777_PACKET_PERIOD 1500 +#define FQ777_PACKET_SIZE 8 +#define FQ777_BIND_COUNT 1000 +#define FQ777_NUM_RF_CHANNELS 4 + +enum { + FQ777_FLAG_RETURN = 0x40, // 0x40 when not off, !0x40 when one key return + FQ777_FLAG_HEADLESS = 0x04, + FQ777_FLAG_EXPERT = 0x01, + FQ777_FLAG_FLIP = 0x80, +}; + +const uint8_t ssv_xor[] = {0x80,0x44,0x64,0x75,0x6C,0x71,0x2A,0x36,0x7C,0xF1,0x6E,0x52,0x9,0x9D,0x1F,0x78,0x3F,0xE1,0xEE,0x16,0x6D,0xE8,0x73,0x9,0x15,0xD7,0x92,0xE7,0x3,0xBA}; +uint8_t FQ777_bind_addr [] = {0xe7,0xe7,0xe7,0xe7,0x67}; + +static void __attribute__((unused)) ssv_pack_dpl(uint8_t addr[], uint8_t pid, uint8_t* len, uint8_t* payload, uint8_t* packed_payload) +{ + uint8_t i = 0; + + uint16_t pcf = (*len & 0x3f) << 3; + pcf |= (pid & 0x3) << 1; + pcf |= 0x00; // noack field + + uint8_t header[7] = {0}; + header[6] = pcf; + header[5] = (pcf >> 7) | (addr[0] << 1); + header[4] = (addr[0] >> 7) | (addr[1] << 1); + header[3] = (addr[1] >> 7) | (addr[2] << 1); + header[2] = (addr[2] >> 7) | (addr[3] << 1); + header[1] = (addr[3] >> 7) | (addr[4] << 1); + header[0] = (addr[4] >> 7); + + // calculate the crc + union + { + uint8_t bytes[2]; + uint16_t val; + } crc; + + for (i = 0; i < 7; ++i) + crc.val=crc16_update(0x3c18,header[i]); + for (i = 0; i < *len; ++i) + crc.val=crc16_update(crc.val,payload[i]); + + // encode payload and crc + // xor with this: + for (i = 0; i < *len; ++i) + payload[i] ^= ssv_xor[i]; + crc.bytes[1] ^= ssv_xor[i++]; + crc.bytes[0] ^= ssv_xor[i++]; + + // pack the pcf, payload, and crc into packed_payload + packed_payload[0] = pcf >> 1; + packed_payload[1] = (pcf << 7) | (payload[0] >> 1); + + for (i = 0; i < *len - 1; ++i) + packed_payload[i+2] = (payload[i] << 7) | (payload[i+1] >> 1); + + packed_payload[i+2] = (payload[i] << 7) | (crc.val >> 9); + ++i; + packed_payload[i+2] = (crc.val >> 1 & 0x80 ) | (crc.val >> 1 & 0x7F); + ++i; + packed_payload[i+2] = (crc.val << 7); + + *len += 4; +} + +static void __attribute__((unused)) FQ777_send_packet(uint8_t bind) +{ + uint8_t packet_len = FQ777_PACKET_SIZE; + uint8_t packet_ori[8]; + if (bind) + { + // 4,5,6 = address fields + // last field is checksum of address fields + packet_ori[0] = 0x20; + packet_ori[1] = 0x15; + packet_ori[2] = 0x05; + packet_ori[3] = 0x06; + packet_ori[4] = rx_tx_addr[0]; + packet_ori[5] = rx_tx_addr[1]; + packet_ori[6] = rx_tx_addr[2]; + packet_ori[7] = packet[4] + packet[5] + packet[6]; + } + else + { + // throt, yaw, pitch, roll, trims, flags/left button,00,right button + //0-3 0x00-0x64 + //4 roll/pitch/yaw trims. cycles through one trim at a time - 0-40 trim1, 40-80 trim2, 80-C0 trim3 (center: A0 20 60) + //5 flags for throttle button, two buttons above throttle - def: 0x40 + //6 00 ?? + //7 checksum - add values in other fields + + /* + // Trims are usually done through the radio configuration but leaving the code here just in case... + uint8_t trim_mod = packet_count % 144; + uint8_t trim_val = 0; + if (36 <= trim_mod && trim_mod < 72) // yaw + trim_val = 0x20; // don't modify yaw trim + else + if (108 < trim_mod && trim_mod) // pitch + trim_val = map(ppm[FQ777124_TRIM_CHAN_PITCH], PPM_MIN, PPM_MAX, 0x01, 0x3E) + 0xA0 - 0x1F; + else // roll + trim_val = map(ppm[FQ777124_TRIM_CHAN_ROLL], PPM_MIN, PPM_MAX, 0x01, 0x3E) + 0x60 - 0x1F;*/ + + packet_ori[0] = convert_channel_8b_scale(THROTTLE,0,0x64); + packet_ori[1] = convert_channel_8b_scale(RUDDER,0,0x64); + packet_ori[2] = convert_channel_8b_scale(ELEVATOR,0,0x64); + packet_ori[3] = convert_channel_8b_scale(AILERON,0,0x64); + packet_ori[4] = 0x20; //trim_val; // calculated above + packet_ori[5] = GET_FLAG(Servo_AUX1, FQ777_FLAG_FLIP) + | GET_FLAG(Servo_AUX3, FQ777_FLAG_HEADLESS) + | GET_FLAG(!Servo_AUX2, FQ777_FLAG_RETURN) + | GET_FLAG(Servo_AUX4,FQ777_FLAG_EXPERT); + + packet_ori[6] = 0x00; + // calculate checksum + uint8_t checksum = 0; + for (int i = 0; i < 7; ++i) + checksum += packet_ori[i]; + packet_ori[7] = checksum; + + //packet_count++; + } + + ssv_pack_dpl( (0 == bind) ? rx_tx_addr : FQ777_bind_addr, hopping_frequency_no, &packet_len, packet_ori, packet); + + NRF24L01_WriteReg(NRF24L01_00_CONFIG,_BV(NRF24L01_00_PWR_UP)); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no++]); + hopping_frequency_no %= FQ777_NUM_RF_CHANNELS; + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); + NRF24L01_FlushTx(); + NRF24L01_WritePayload(packet, packet_len); + NRF24L01_WritePayload(packet, packet_len); + NRF24L01_WritePayload(packet, packet_len); +} + +static void __attribute__((unused)) FQ777_init() +{ + NRF24L01_Initialize(); + NRF24L01_SetTxRxMode(TX_EN); + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, FQ777_bind_addr, 5); + NRF24L01_FlushTx(); + NRF24L01_FlushRx(); + NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgement on all data pipes + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x00); + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); + NRF24L01_SetBitrate(NRF24L01_BR_250K); + NRF24L01_SetPower(); +} + +uint16_t FQ777_callback() +{ + if(bind_counter!=0) + { + FQ777_send_packet(1); + if (bind_counter-- == 0) + { + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5); + BIND_DONE; + } + } + else + FQ777_send_packet(0); + return FQ777_PACKET_PERIOD; +} + +uint16_t initFQ777(void) +{ + BIND_IN_PROGRESS; // autobind protocol + bind_counter = FQ777_BIND_COUNT; + hopping_frequency[0] = 0x4D; + hopping_frequency[1] = 0x43; + hopping_frequency[2] = 0x27; + hopping_frequency[3] = 0x07; + hopping_frequency_no=0; + rx_tx_addr[2] = 0x00; + rx_tx_addr[3] = 0xe7; + rx_tx_addr[4] = 0x67; + FQ777_init(); + return FQ777_INITIAL_WAIT; +} + +#endif diff --git a/Multiprotocol/Hubsan_a7105.ino b/Multiprotocol/Hubsan_a7105.ino index 760cb4e..ff54c5a 100644 --- a/Multiprotocol/Hubsan_a7105.ino +++ b/Multiprotocol/Hubsan_a7105.ino @@ -235,9 +235,9 @@ uint16_t ReadHubsan() phase &= ~WAIT_WRITE; if(id_data == ID_PLUS) { - if(state == BIND_7 && packet[2] == 9) + if(phase == BIND_7 && packet[2] == 9) { - state = DATA_1; + phase = DATA_1; A7105_WriteReg(A7105_1F_CODE_I, 0x0F); BIND_DONE; return 4500; diff --git a/Multiprotocol/MT99xx_nrf24l01.ino b/Multiprotocol/MT99xx_nrf24l01.ino index 5e719ed..0e0d656 100644 --- a/Multiprotocol/MT99xx_nrf24l01.ino +++ b/Multiprotocol/MT99xx_nrf24l01.ino @@ -12,7 +12,7 @@ You should have received a copy of the GNU General Public License along with Multiprotocol. If not, see . */ -// compatible with MT99xx, Eachine H7, Yi Zhan i6S +// compatible with MT99xx, Eachine H7, Yi Zhan i6S and LS114/124 // Last sync with Goebish mt99xx_nrf24l01.c dated 2016-01-29 #if defined(MT99XX_NRF24L01_INO) @@ -43,34 +43,54 @@ enum { MT99XX_DATA }; +const uint8_t h7_mys_byte[] = { + 0x01, 0x11, 0x02, 0x12, 0x03, 0x13, 0x04, 0x14, + 0x05, 0x15, 0x06, 0x16, 0x07, 0x17, 0x00, 0x10 +}; + +static const u8 ls_mys_byte[] = { + 0x05, 0x15, 0x25, 0x06, 0x16, 0x26, + 0x07, 0x17, 0x27, 0x00, 0x10, 0x20, + 0x01, 0x11, 0x21, 0x02, 0x12, 0x22, + 0x03, 0x13, 0x23, 0x04, 0x14, 0x24 +}; + static void __attribute__((unused)) MT99XX_send_packet() { const uint8_t yz_p4_seq[] = {0xa0, 0x20, 0x60}; - const uint8_t mys_byte[] = { - 0x01, 0x11, 0x02, 0x12, 0x03, 0x13, 0x04, 0x14, - 0x05, 0x15, 0x06, 0x16, 0x07, 0x17, 0x00, 0x10 - }; static uint8_t yz_seq_num=0; + static uint8_t ls_counter=0; if(sub_protocol != YZ) - { // MT99XX & H7 + { // MT99XX & H7 & LS packet[0] = convert_channel_8b_scale(THROTTLE,0x00,0xE1); // throttle packet[1] = convert_channel_8b_scale(RUDDER ,0x00,0xE1); // rudder packet[2] = convert_channel_8b_scale(AILERON ,0x00,0xE1); // aileron packet[3] = convert_channel_8b_scale(ELEVATOR,0x00,0xE1); // elevator packet[4] = 0x20; // pitch trim (0x3f-0x20-0x00) packet[5] = 0x20; // roll trim (0x00-0x20-0x3f) - packet[6] = GET_FLAG( Servo_AUX1, FLAG_MT_FLIP ) - | GET_FLAG( Servo_AUX3, FLAG_MT_SNAPSHOT ) - | GET_FLAG( Servo_AUX4, FLAG_MT_VIDEO ); - if(sub_protocol==MT99) - packet[6] |= 0x40 | FLAG_MT_RATE2; + packet[6] = GET_FLAG( Servo_AUX1, FLAG_MT_FLIP ); + packet[7] = h7_mys_byte[hopping_frequency_no]; // next rf channel index ? + + if(sub_protocol==H7) + packet[6]|=FLAG_MT_RATE1; // max rate on H7 else - packet[6] |= FLAG_MT_RATE1; // max rate on H7 - // todo: mys_byte = next channel index ? - // low nibble: index in chan list ? - // high nibble: 0->start from start of list, 1->start from end of list ? - packet[7] = mys_byte[hopping_frequency_no]; + if(sub_protocol==MT99) + packet[6] |= 0x40 | FLAG_MT_RATE2 + | GET_FLAG( Servo_AUX3, FLAG_MT_SNAPSHOT ) + | GET_FLAG( Servo_AUX4, FLAG_MT_VIDEO ); // max rate on MT99xx + else + if(sub_protocol==LS) + packet[6] |= 0x40 | FLAG_MT_RATE2; + else //LS + { + packet[6] |= FLAG_MT_RATE2 // max rate + | GET_FLAG( Servo_AUX5, 0x10 ); //HEADLESS + packet[7] = ls_mys_byte[ls_counter++]; + if(ls_counter >= sizeof(ls_mys_byte)) + ls_counter=0; + } + uint8_t result=checksum_offset; for(uint8_t i=0; i<8; i++) result += packet[i]; @@ -102,7 +122,10 @@ static void __attribute__((unused)) MT99XX_send_packet() packet[8] = 0xff; } - NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no] + channel_offset); + if(sub_protocol == LS) + NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x2D); // LS always transmits on the same channel + else + NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no] + channel_offset); NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); NRF24L01_FlushTx(); XN297_WritePayload(packet, MT99XX_PACKET_SIZE); @@ -120,8 +143,11 @@ static void __attribute__((unused)) MT99XX_send_packet() static void __attribute__((unused)) MT99XX_init() { NRF24L01_Initialize(); + if(sub_protocol == YZ) + XN297_SetScrambledMode(XN297_UNSCRAMBLED); NRF24L01_SetTxRxMode(TX_EN); NRF24L01_FlushTx(); + XN297_SetTXAddr((uint8_t *)"\xCC\xCC\xCC\xCC\xCC", 5); 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_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only @@ -133,19 +159,26 @@ static void __attribute__((unused)) MT99XX_init() NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps NRF24L01_SetPower(); - XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP) | (sub_protocol == YZ ? BV(XN297_UNSCRAMBLED):0) ); + XN297_Configure(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO) | BV(NRF24L01_00_PWR_UP) ); - XN297_SetTXAddr((uint8_t *)"\xCC\xCC\xCC\xCC\xCC", 5); } static void __attribute__((unused)) MT99XX_initialize_txid() { + rx_tx_addr[3] = 0xCC; + rx_tx_addr[4] = 0xCC; if(sub_protocol == YZ) { rx_tx_addr[0] = 0x53; // test (SB id) rx_tx_addr[1] = 0x00; + rx_tx_addr[2] = 0x00; } - checksum_offset = (rx_tx_addr[0] + rx_tx_addr[1]) & 0xff; + else + if(sub_protocol == LS) + rx_tx_addr[0] = 0xCC; + else //MT99 & H7 + rx_tx_addr[2] = 0x00; + checksum_offset = rx_tx_addr[0] + rx_tx_addr[1] + rx_tx_addr[2]; channel_offset = (((checksum_offset & 0xf0)>>4) + (checksum_offset & 0x0f)) % 8; } @@ -157,16 +190,16 @@ uint16_t MT99XX_callback() { if (bind_counter == 0) { - rx_tx_addr[2] = 0x00; - rx_tx_addr[3] = 0xCC; - rx_tx_addr[4] = 0xCC; // set tx address for data packets XN297_SetTXAddr(rx_tx_addr, 5); BIND_DONE; } else { - NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]); + if(sub_protocol == LS) + NRF24L01_WriteReg(NRF24L01_05_RF_CH, 0x2D); // LS always transmits on the same channel + else + NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]); NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); NRF24L01_FlushTx(); XN297_WritePayload(packet, MT99XX_PACKET_SIZE); // bind packet @@ -193,23 +226,30 @@ uint16_t initMT99XX(void) MT99XX_init(); packet[0] = 0x20; - if(sub_protocol!=YZ) + packet_period = MT99XX_PACKET_PERIOD_MT; + switch(sub_protocol) { // MT99 & H7 - packet_period = MT99XX_PACKET_PERIOD_MT; - packet[1] = 0x14; - packet[2] = 0x03; - packet[3] = 0x25; + case MT99: + case H7: + packet[1] = 0x14; + packet[2] = 0x03; + packet[3] = 0x25; + break; + case YZ: + packet_period = MT99XX_PACKET_PERIOD_YZ; + packet[1] = 0x15; + packet[2] = 0x05; + packet[3] = 0x06; + break; + case LS: + packet[1] = 0x14; + packet[2] = 0x05; + packet[3] = 0x11; + break; } - else - { // YZ - packet_period = MT99XX_PACKET_PERIOD_YZ; - packet[1] = 0x15; - packet[2] = 0x05; - packet[3] = 0x06; - } - packet[4] = rx_tx_addr[0]; // 1st byte for data state tx address - packet[5] = rx_tx_addr[1]; // 2nd byte for data state tx address (always 0x00 on Yi Zhan ?) - packet[6] = 0x00; // 3rd byte for data state tx address (always 0x00 ?) + packet[4] = rx_tx_addr[0]; + packet[5] = rx_tx_addr[1]; + packet[6] = rx_tx_addr[2]; packet[7] = checksum_offset; // checksum offset packet[8] = 0xAA; // fixed packet_count=0; diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 69f84c4..d8d94a7 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -50,7 +50,8 @@ enum PROTOCOLS MODE_SHENQI=19, // =>NRF24L01 MODE_FY326=20, // =>NRF24L01 MODE_SFHSS=21, // =>CC2500 - MODE_J6PRO=22 // =>CYRF6936 + MODE_J6PRO=22, // =>CYRF6936 + MODE_FQ777=23 // =>NRF24L01 }; enum Flysky @@ -108,7 +109,8 @@ enum MT99XX { MT99 = 0, H7 = 1, - YZ = 2 + YZ = 2, + LS = 3 }; enum MJXQ { @@ -512,6 +514,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- FY326 20 SFHSS 21 J6PRO 22 + FQ777 23 BindBit=> 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No @@ -558,6 +561,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- MT99 0 H7 1 YZ 2 + LS 3 sub_protocol==MJXQ WLH08 0 X600 1 diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 820e11c..8e0416a 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -22,7 +22,6 @@ */ #include #include -#include #include "Multiprotocol.h" //#define DEBUG_TX @@ -53,7 +52,6 @@ uint8_t phase; uint16_t bind_counter; uint8_t bind_phase; uint8_t binding_idx; -uint32_t packet_counter; uint16_t packet_period; uint8_t packet_count; uint8_t packet_sent; @@ -66,7 +64,7 @@ uint8_t throttle, rudder, elevator, aileron; uint8_t flags; uint16_t crc; // -uint32_t state; +uint16_t state; uint8_t len; uint8_t RX_num; @@ -558,6 +556,12 @@ static void protocol_init() next_callback=initFY326(); remote_callback = FY326_callback; break; +#endif +#if defined(FQ777_NRF24L01_INO) + case MODE_FQ777: + next_callback=initFQ777(); + remote_callback = FQ777_callback; + break; #endif } @@ -648,7 +652,7 @@ static void module_reset() case MODE_J6PRO: CYRF_Reset(); break; - default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY, MODE_MT99XX, MODE_MJXQ, MODE_SHENQI, MODE_FY326 + default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY, MODE_MT99XX, MODE_MJXQ, MODE_SHENQI, MODE_FY326, MODE_FQ777 NRF24L01_Reset(); break; } @@ -824,6 +828,166 @@ static uint32_t random_id(uint16_t adress, uint8_t create_new) return id; } +/********************/ +/** SPI routines **/ +/********************/ +void SPI_Write(uint8_t command) +{ + uint8_t n=8; + + SCK_off;//SCK start low + SDI_off; + do + { + if(command&0x80) + SDI_on; + else + SDI_off; + SCK_on; + command = command << 1; + SCK_off; + } + while(--n) ; + SDI_on; +} + +uint8_t SPI_Read(void) +{ + uint8_t result; + uint8_t i; + for(i=0;i<8;i++) + { + result=result<<1; + if(SDO_1) + result |= 0x01; + SCK_on; + NOP(); + SCK_off; + } + return result; +} + +/************************************/ +/** Arduino replacement routines **/ +/************************************/ +// replacement millis() and micros() +// These work polled, no interrupts +// micros() MUST be called at least once every 32 milliseconds +uint16_t MillisPrecount ; +uint16_t lastTimerValue ; +uint32_t TotalMicros ; +uint32_t TotalMillis ; +uint8_t Correction ; + +uint32_t micros() +{ + uint16_t elapsed ; + uint8_t millisToAdd ; + uint8_t oldSREG = SREG ; + cli() ; + uint16_t time = TCNT1 ; // Read timer 1 + SREG = oldSREG ; + + elapsed = time - lastTimerValue ; + elapsed += Correction ; + Correction = elapsed & 0x01 ; + elapsed >>= 1 ; + + uint32_t ltime = TotalMicros ; + ltime += elapsed ; + cli() ; + TotalMicros = ltime ; // Done this way for RPM to work correctly + lastTimerValue = time ; + SREG = oldSREG ; // Still valid from above + + elapsed += MillisPrecount; + millisToAdd = 0 ; + + if ( elapsed > 15999 ) + { + millisToAdd = 16 ; + elapsed -= 16000 ; + } + if ( elapsed > 7999 ) + { + millisToAdd += 8 ; + elapsed -= 8000 ; + } + if ( elapsed > 3999 ) + { + millisToAdd += 4 ; + elapsed -= 4000 ; + } + if ( elapsed > 1999 ) + { + millisToAdd += 2 ; + elapsed -= 2000 ; + } + if ( elapsed > 999 ) + { + millisToAdd += 1 ; + elapsed -= 1000 ; + } + TotalMillis += millisToAdd ; + MillisPrecount = elapsed ; + return TotalMicros ; +} + +uint32_t millis() +{ + micros() ; + return TotalMillis ; +} + +void delay(unsigned long ms) +{ + uint16_t start = (uint16_t)micros(); + uint16_t lms = ms ; + + while (lms > 0) { + if (((uint16_t)micros() - start) >= 1000) { + lms--; + start += 1000; + } + } +} + +/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */ +void delayMicroseconds(unsigned int us) +{ + // calling avrlib's delay_us() function with low values (e.g. 1 or + // 2 microseconds) gives delays longer than desired. + //delay_us(us); + + // for the 16 MHz clock on most Arduino boards + + // for a one-microsecond delay, simply return. the overhead + // of the function call yields a delay of approximately 1 1/8 us. + if (--us == 0) + return; + + // the following loop takes a quarter of a microsecond (4 cycles) + // per iteration, so execute it four times for each microsecond of + // delay requested. + us <<= 2; + + // account for the time taken in the preceeding commands. + us -= 2; + + // busy wait + __asm__ __volatile__ ( + "1: sbiw %0,1" "\n\t" // 2 cycles + "brne 1b" : "=w" (us) : "0" (us) // 2 cycles + ); +} + +void init() +{ + // this needs to be called before setup() or some functions won't + // work there + sei(); +} + /**************************/ /**************************/ /** Interrupt routines **/ diff --git a/Multiprotocol/NRF24l01_SPI.ino b/Multiprotocol/NRF24l01_SPI.ino index ac67c06..bceefeb 100644 --- a/Multiprotocol/NRF24l01_SPI.ino +++ b/Multiprotocol/NRF24l01_SPI.ino @@ -19,45 +19,6 @@ //--------------------------- #include "iface_nrf24l01.h" -static void nrf_spi_write(uint8_t command) -{ - uint8_t n=8; - - SCK_off;//SCK start low - SDI_off; - while(n--) { - if(command&0x80) - SDI_on; - else - SDI_off; - SCK_on; - NOP(); - SCK_off; - command = command << 1; - } - SDI_on; -} - -//VARIANT 2 -static uint8_t nrf_spi_read(void) -{ - uint8_t result; - uint8_t i; - result=0; - for(i=0;i<8;i++) { - result<<=1; - if(SDO_1) /// - result|=0x01; - SCK_on; - NOP(); - SCK_off; - NOP(); - } - return result; -} -//-------------------------------------------- - - //--------------------------- // NRF24L01+ SPI Specific Functions @@ -73,8 +34,8 @@ void NRF24L01_Initialize() void NRF24L01_WriteReg(uint8_t reg, uint8_t data) { NRF_CSN_off; - nrf_spi_write(W_REGISTER | (REGISTER_MASK & reg)); - nrf_spi_write(data); + SPI_Write(W_REGISTER | (REGISTER_MASK & reg)); + SPI_Write(data); NRF_CSN_on; } @@ -82,26 +43,26 @@ void NRF24L01_WriteRegisterMulti(uint8_t reg, uint8_t * data, uint8_t length) { NRF_CSN_off; - nrf_spi_write(W_REGISTER | ( REGISTER_MASK & reg)); + SPI_Write(W_REGISTER | ( REGISTER_MASK & reg)); for (uint8_t i = 0; i < length; i++) - nrf_spi_write(data[i]); + SPI_Write(data[i]); NRF_CSN_on; } void NRF24L01_WritePayload(uint8_t * data, uint8_t length) { NRF_CSN_off; - nrf_spi_write(W_TX_PAYLOAD); + SPI_Write(W_TX_PAYLOAD); for (uint8_t i = 0; i < length; i++) - nrf_spi_write(data[i]); + SPI_Write(data[i]); NRF_CSN_on; } uint8_t NRF24L01_ReadReg(uint8_t reg) { NRF_CSN_off; - nrf_spi_write(R_REGISTER | (REGISTER_MASK & reg)); - uint8_t data = nrf_spi_read(); + SPI_Write(R_REGISTER | (REGISTER_MASK & reg)); + uint8_t data = SPI_Read(); NRF_CSN_on; return data; } @@ -109,25 +70,25 @@ uint8_t NRF24L01_ReadReg(uint8_t reg) /*static void NRF24L01_ReadRegisterMulti(uint8_t reg, uint8_t * data, uint8_t length) { NRF_CSN_off; - nrf_spi_write(R_REGISTER | (REGISTER_MASK & reg)); + SPI_Write(R_REGISTER | (REGISTER_MASK & reg)); for(uint8_t i = 0; i < length; i++) - data[i] = nrf_spi_read(); + data[i] = SPI_Read(); NRF_CSN_on; } */ static void NRF24L01_ReadPayload(uint8_t * data, uint8_t length) { NRF_CSN_off; - nrf_spi_write(R_RX_PAYLOAD); + SPI_Write(R_RX_PAYLOAD); for(uint8_t i = 0; i < length; i++) - data[i] = nrf_spi_read(); + data[i] = SPI_Read(); NRF_CSN_on; } static void NRF24L01_Strobe(uint8_t state) { NRF_CSN_off; - nrf_spi_write(state); + SPI_Write(state); NRF_CSN_on; } @@ -144,8 +105,8 @@ void NRF24L01_FlushRx() void NRF24L01_Activate(uint8_t code) { NRF_CSN_off; - nrf_spi_write(ACTIVATE); - nrf_spi_write(code); + SPI_Write(ACTIVATE); + SPI_Write(code); NRF_CSN_on; } @@ -202,7 +163,7 @@ void NRF24L01_SetTxRxMode(enum TXRX_State mode) NRF24L01_WriteReg(NRF24L01_00_CONFIG, (1 << NRF24L01_00_EN_CRC) // switch to TX mode | (1 << NRF24L01_00_CRCO) | (1 << NRF24L01_00_PWR_UP)); - _delay_us(130); + delayMicroseconds(130); NRF_CSN_on; } else @@ -217,7 +178,7 @@ void NRF24L01_SetTxRxMode(enum TXRX_State mode) | (1 << NRF24L01_00_CRCO) | (1 << NRF24L01_00_PWR_UP) | (1 << NRF24L01_00_PRIM_RX)); - _delay_us(130); + delayMicroseconds(130); NRF_CSN_on; } else @@ -241,7 +202,7 @@ void NRF24L01_Reset() NRF24L01_Strobe(0xff); // NOP NRF24L01_ReadReg(0x07); NRF24L01_SetTxRxMode(TXRX_OFF); - _delay_us(100); + delayMicroseconds(100); } uint8_t NRF24L01_packet_ack() @@ -258,7 +219,7 @@ uint8_t NRF24L01_packet_ack() /////////////// // XN297 emulation layer -uint8_t xn297_scramble_enabled=1; //enabled by default +uint8_t xn297_scramble_enabled=XN297_SCRAMBLED; //enabled by default uint8_t xn297_addr_len; uint8_t xn297_tx_addr[5]; uint8_t xn297_rx_addr[5]; @@ -271,13 +232,6 @@ static const uint8_t xn297_scramble[] = { 0x1b, 0x5d, 0x19, 0x10, 0x24, 0xd3, 0xdc, 0x3f, 0x8e, 0xc5, 0x2f}; -const uint16_t PROGMEM xn297_crc_xorout[] = { - 0x0000, 0x3d5f, 0xa6f1, 0x3a23, 0xaa16, 0x1caf, - 0x62b2, 0xe0eb, 0x0821, 0xbe07, 0x5f1a, 0xaf15, - 0x4f0a, 0xad24, 0x5e48, 0xed34, 0x068c, 0xf2c9, - 0x1852, 0xdf36, 0x129d, 0xb17c, 0xd5f5, 0x70d7, - 0xb798, 0x5133, 0x67db, 0xd94e}; - const uint16_t PROGMEM xn297_crc_xorout_scrambled[] = { 0x0000, 0x3448, 0x9BA7, 0x8BBB, 0x85E1, 0x3E8C, 0x451E, 0x18E6, 0x6B24, 0xE7AB, 0x3828, 0x814B, @@ -285,6 +239,13 @@ const uint16_t PROGMEM xn297_crc_xorout_scrambled[] = { 0x8B17, 0x2920, 0x8B5F, 0x61B1, 0xD391, 0x7401, 0x2138, 0x129F, 0xB3A0, 0x2988}; +const uint16_t PROGMEM xn297_crc_xorout[] = { + 0x0000, 0x3d5f, 0xa6f1, 0x3a23, 0xaa16, 0x1caf, + 0x62b2, 0xe0eb, 0x0821, 0xbe07, 0x5f1a, 0xaf15, + 0x4f0a, 0xad24, 0x5e48, 0xed34, 0x068c, 0xf2c9, + 0x1852, 0xdf36, 0x129d, 0xb17c, 0xd5f5, 0x70d7, + 0xb798, 0x5133, 0x67db, 0xd94e}; + static uint8_t bit_reverse(uint8_t b_in) { uint8_t b_out = 0; @@ -296,10 +257,9 @@ static uint8_t bit_reverse(uint8_t b_in) return b_out; } +static const uint16_t polynomial = 0x1021; static uint16_t crc16_update(uint16_t crc, uint8_t a) { - static const uint16_t polynomial = 0x1021; - crc ^= a << 8; for (uint8_t i = 0; i < 8; ++i) if (crc & 0x8000) @@ -345,14 +305,18 @@ void XN297_SetRXAddr(const uint8_t* addr, uint8_t len) NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, buf, 5); } -void XN297_Configure(uint16_t flags) +void XN297_Configure(uint8_t flags) { - xn297_scramble_enabled = !(flags & BV(XN297_UNSCRAMBLED)); xn297_crc = !!(flags & BV(NRF24L01_00_EN_CRC)); flags &= ~(BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_CRCO)); NRF24L01_WriteReg(NRF24L01_00_CONFIG, flags & 0xFF); } +void XN297_SetScrambledMode(const u8 mode) +{ + xn297_scramble_enabled = mode; +} + void XN297_WritePayload(uint8_t* msg, uint8_t len) { uint8_t buf[32]; diff --git a/Multiprotocol/SFHSS_cc2500.ino b/Multiprotocol/SFHSS_cc2500.ino index 29f1880..3108983 100644 --- a/Multiprotocol/SFHSS_cc2500.ino +++ b/Multiprotocol/SFHSS_cc2500.ino @@ -18,7 +18,7 @@ #include "iface_cc2500.h" -//#define SFHSS_USE_TUNE_FREQ +#define SFHSS_USE_TUNE_FREQ #define SFHSS_COARSE 0 #define SFHSS_PACKET_LEN 13 @@ -73,20 +73,6 @@ const PROGMEM uint8_t SFHSS_init_values[] = { /* 20 */ 0xF8, 0xB6, 0x10, 0xEA, 0x0A, 0x11, 0x11 }; -static void __attribute__((unused)) SFHSS_rf_init() -{ - CC2500_Reset(); - CC2500_Strobe(CC2500_SIDLE); - - for (uint8_t i = 0; i < 39; ++i) - CC2500_WriteReg(i, pgm_read_byte_near(&SFHSS_init_values[i])); - //CC2500_WriteRegisterMulti(CC2500_00_IOCFG2, init_values, sizeof(init_values)); - CC2500_WriteReg(CC2500_0C_FSCTRL0, option); - - CC2500_SetTxRxMode(TX_EN); - CC2500_SetPower(); -} - static void __attribute__((unused)) SFHSS_tune_chan() { CC2500_Strobe(CC2500_SIDLE); @@ -99,7 +85,7 @@ static void __attribute__((unused)) SFHSS_tune_chan_fast() CC2500_Strobe(CC2500_SIDLE); CC2500_WriteReg(CC2500_0A_CHANNR, rf_ch_num*6+16); CC2500_WriteRegisterMulti(CC2500_23_FSCAL3, calData[rf_ch_num], 3); - _delay_us(6); + delayMicroseconds(6); } #ifdef SFHSS_USE_TUNE_FREQ @@ -112,6 +98,20 @@ static void __attribute__((unused)) SFHSS_tune_freq() { } #endif +static void __attribute__((unused)) SFHSS_rf_init() +{ + CC2500_Reset(); + CC2500_Strobe(CC2500_SIDLE); + + for (uint8_t i = 0; i < 39; ++i) + CC2500_WriteReg(i, pgm_read_byte_near(&SFHSS_init_values[i])); + //CC2500_WriteRegisterMulti(CC2500_00_IOCFG2, init_values, sizeof(init_values)); + //CC2500_WriteReg(CC2500_0C_FSCTRL0, option); + + CC2500_SetTxRxMode(TX_EN); + CC2500_SetPower(); +} + static void __attribute__((unused)) SFHSS_calc_next_chan() { rf_ch_num += fhss_code + 2; @@ -194,6 +194,9 @@ uint16_t ReadSFHSS() state = SFHSS_TUNE; return 2000; case SFHSS_TUNE: +#ifdef SFHSS_USE_TUNE_FREQ + SFHSS_tune_freq(); +#endif CC2500_SetPower(); state = SFHSS_DATA1; return 3150; diff --git a/Multiprotocol/Symax_nrf24l01.ino b/Multiprotocol/Symax_nrf24l01.ino index 266396b..994eccc 100644 --- a/Multiprotocol/Symax_nrf24l01.ino +++ b/Multiprotocol/Symax_nrf24l01.ino @@ -161,7 +161,7 @@ static void __attribute__((unused)) SYMAX_send_packet(uint8_t bind) NRF24L01_WritePayload(packet, packet_length); - if (packet_counter++ % 2) // use each channel twice + if (packet_count++ % 2) // use each channel twice hopping_frequency_no = (hopping_frequency_no + 1) % rf_ch_num; NRF24L01_SetPower(); // Set tx_power @@ -243,7 +243,7 @@ static void __attribute__((unused)) symax_init1() memcpy(hopping_frequency, chans_bind, rf_ch_num); } hopping_frequency_no = 0; - packet_counter = 0; + packet_count = 0; } // channels determined by last byte of tx address @@ -306,7 +306,7 @@ static void __attribute__((unused)) symax_init2() NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5); } hopping_frequency_no = 0; - packet_counter = 0; + packet_count = 0; } uint16_t symax_callback() @@ -345,7 +345,7 @@ uint16_t symax_callback() uint16_t initSymax() { - packet_counter = 0; + packet_count = 0; flags = 0; BIND_IN_PROGRESS; // autobind protocol symax_init(); diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 1f67300..de08740 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -58,6 +58,7 @@ #define MJXQ_NRF24L01_INO #define SHENQI_NRF24L01_INO #define FY326_NRF24L01_INO + #define FQ777_NRF24L01_INO #endif //Uncomment to enable telemetry @@ -153,6 +154,7 @@ const PPM_Parameters PPM_prot[15]= { MT99 H7 YZ + LS MODE_MJXQ WLH08 X600 @@ -166,6 +168,8 @@ const PPM_Parameters PPM_prot[15]= { NONE MODE_J6PRO NONE + MODE_FQ777 + NONE RX_Num value between 0 and 15 diff --git a/Multiprotocol/iface_nrf24l01.h b/Multiprotocol/iface_nrf24l01.h index 92ff9e1..cc8b6fe 100644 --- a/Multiprotocol/iface_nrf24l01.h +++ b/Multiprotocol/iface_nrf24l01.h @@ -103,6 +103,8 @@ enum { //#define NOP 0xFF // XN297 emulation layer -#define XN297_UNSCRAMBLED 8 - +enum { + XN297_UNSCRAMBLED = 0, + XN297_SCRAMBLED +}; #endif \ No newline at end of file From f9fdc36d0da1ce71c7eda3e290f554cea6ab086e Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 1 Aug 2016 22:06:29 +0200 Subject: [PATCH 122/293] Arduino 1.6.10 and extra optimization --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 151dd1d..bff6a37 100644 --- a/README.md +++ b/README.md @@ -316,16 +316,17 @@ If you have the Banggood ready to use board you can 3D print this case (details ###Toolchain Multiprotocol source can be compiled using the Arduino IDE. -The currently supported Arduino version is [1.6.9](http://arduino.cc/download_handler.php?f=/arduino-1.6.9-windows.exe). +The currently supported Arduino version is [1.6.10](https://www.arduino.cc/download_handler.php?f=/arduino-1.6.10-windows.exe). Download the [zip file](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/archive/master.zip) of this repository, unzip it in a folder, navigate to the Multiprotocol directory and then click on Multiprotocol.ino. The Arduino environment will appear and the Multiprotocol project will be loaded. [_Config.h file](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Multiprotocol/_Config.h) must be modified to select which protocols will be available, change protocols/sub_protocols/settings associated with dial for PPM input, different TX channel orders and timing, Telemetry or not, ... +This is mandatory since all protocols will not fit in the ATmega328. You need to pick and choose what you want. Notes: - Make sure to select "Arduino Pro or Pro Mini, ATmega328 (5V,16MHz)" before compiling. - Compilation of the code posted here works. So if it doesn't for you this is a problem with your setup, please double check everything before asking. - +- If you want to reduce the code size even further, you can modify the file platform.txt located in "C:\Program Files (x86)\Arduino\hardware\arduino\avr". Set the line "compiler.c.elf.extra_flags=" to "compiler.c.elf.extra_flags=-Wl,--relax". ###Upload the code using ISP (In System Programming) It is recommended to use an external programmer like [USBASP](http://www.banggood.com/USBASP-USBISP-3_3-5V-AVR-Downloader-Programmer-With-ATMEGA8-ATMEGA128-p-934425.html) to upload the code in the Atmega328. The programmer should be set to 3.3V or nothing to not supply any over voltage to the multimodule and avoid any damages. From c54f1ca9b09423797b27a86419ac9fb5bb146df5 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 1 Aug 2016 22:08:53 +0200 Subject: [PATCH 123/293] Update README.md --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index bff6a37..d6a44f0 100644 --- a/README.md +++ b/README.md @@ -320,13 +320,14 @@ The currently supported Arduino version is [1.6.10](https://www.arduino.cc/downl Download the [zip file](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/archive/master.zip) of this repository, unzip it in a folder, navigate to the Multiprotocol directory and then click on Multiprotocol.ino. The Arduino environment will appear and the Multiprotocol project will be loaded. -[_Config.h file](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Multiprotocol/_Config.h) must be modified to select which protocols will be available, change protocols/sub_protocols/settings associated with dial for PPM input, different TX channel orders and timing, Telemetry or not, ... -This is mandatory since all protocols will not fit in the ATmega328. You need to pick and choose what you want. +**[_Config.h file](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Multiprotocol/_Config.h) must be modified** to select which protocols will be available, change protocols/sub_protocols/settings associated with dial for PPM input, different TX channel orders and timing, Telemetry or not, ... +This is mandatory since all available protocols will not fit in the ATmega328. You need to pick and choose what you want. Notes: - Make sure to select "Arduino Pro or Pro Mini, ATmega328 (5V,16MHz)" before compiling. - Compilation of the code posted here works. So if it doesn't for you this is a problem with your setup, please double check everything before asking. - If you want to reduce the code size even further, you can modify the file platform.txt located in "C:\Program Files (x86)\Arduino\hardware\arduino\avr". Set the line "compiler.c.elf.extra_flags=" to "compiler.c.elf.extra_flags=-Wl,--relax". + ###Upload the code using ISP (In System Programming) It is recommended to use an external programmer like [USBASP](http://www.banggood.com/USBASP-USBISP-3_3-5V-AVR-Downloader-Programmer-With-ATMEGA8-ATMEGA128-p-934425.html) to upload the code in the Atmega328. The programmer should be set to 3.3V or nothing to not supply any over voltage to the multimodule and avoid any damages. From c4e66d0c9c117470576dc57926b8c403972ce79e Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 2 Aug 2016 20:33:58 +0200 Subject: [PATCH 124/293] Revert throttle on MT99xx... --- Multiprotocol/MT99xx_nrf24l01.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Multiprotocol/MT99xx_nrf24l01.ino b/Multiprotocol/MT99xx_nrf24l01.ino index 0e0d656..ec8a084 100644 --- a/Multiprotocol/MT99xx_nrf24l01.ino +++ b/Multiprotocol/MT99xx_nrf24l01.ino @@ -63,9 +63,9 @@ static void __attribute__((unused)) MT99XX_send_packet() if(sub_protocol != YZ) { // MT99XX & H7 & LS - packet[0] = convert_channel_8b_scale(THROTTLE,0x00,0xE1); // throttle + packet[0] = convert_channel_8b_scale(THROTTLE,0xE1,0x00); // throttle packet[1] = convert_channel_8b_scale(RUDDER ,0x00,0xE1); // rudder - packet[2] = convert_channel_8b_scale(AILERON ,0x00,0xE1); // aileron + packet[2] = convert_channel_8b_scale(AILERON ,0xE1,0x00); // aileron packet[3] = convert_channel_8b_scale(ELEVATOR,0x00,0xE1); // elevator packet[4] = 0x20; // pitch trim (0x3f-0x20-0x00) packet[5] = 0x20; // roll trim (0x00-0x20-0x3f) From 407e57d334ce00be88da6917e435871fe42c8051 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 2 Aug 2016 20:55:29 +0200 Subject: [PATCH 125/293] Update Protocols_Details.md --- Protocols_Details.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 92ebbd4..9676586 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -302,7 +302,7 @@ Models: Eachine H7, Cheerson CX023 Model: Yi Zhan i6S Only one model can be flown at the same time since the ID is hardcoded. ###Sub_protocol LS -Models: LS114, 124 +Models: LS114, 124, 215 ##Shenqi Autobind protocol From cea0f1766fb95e5a09489fccf02f8ec437b2d666 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 3 Aug 2016 09:05:10 +0200 Subject: [PATCH 126/293] Update Protocols_Details.md --- Protocols_Details.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index 9676586..064015c 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -304,6 +304,10 @@ Only one model can be flown at the same time since the ID is hardcoded. ###Sub_protocol LS Models: LS114, 124, 215 +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP||||HEADLESS + ##Shenqi Autobind protocol From 47ad2b5cfaa7a709320078ab2b29f705e28ac8df Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 3 Aug 2016 09:05:21 +0200 Subject: [PATCH 127/293] MT99xx fix --- Multiprotocol/MT99xx_nrf24l01.ino | 23 ++++++++++------------- 1 file changed, 10 insertions(+), 13 deletions(-) diff --git a/Multiprotocol/MT99xx_nrf24l01.ino b/Multiprotocol/MT99xx_nrf24l01.ino index ec8a084..f3493e1 100644 --- a/Multiprotocol/MT99xx_nrf24l01.ino +++ b/Multiprotocol/MT99xx_nrf24l01.ino @@ -79,17 +79,14 @@ static void __attribute__((unused)) MT99XX_send_packet() packet[6] |= 0x40 | FLAG_MT_RATE2 | GET_FLAG( Servo_AUX3, FLAG_MT_SNAPSHOT ) | GET_FLAG( Servo_AUX4, FLAG_MT_VIDEO ); // max rate on MT99xx - else - if(sub_protocol==LS) - packet[6] |= 0x40 | FLAG_MT_RATE2; - else //LS - { - packet[6] |= FLAG_MT_RATE2 // max rate - | GET_FLAG( Servo_AUX5, 0x10 ); //HEADLESS - packet[7] = ls_mys_byte[ls_counter++]; - if(ls_counter >= sizeof(ls_mys_byte)) - ls_counter=0; - } + else //LS + { + packet[6] |= FLAG_MT_RATE2 // max rate + | GET_FLAG( Servo_AUX5, 0x10 ); //HEADLESS + packet[7] = ls_mys_byte[ls_counter++]; + if(ls_counter >= sizeof(ls_mys_byte)) + ls_counter=0; + } uint8_t result=checksum_offset; for(uint8_t i=0; i<8; i++) @@ -99,9 +96,9 @@ static void __attribute__((unused)) MT99XX_send_packet() else { // YZ packet[0] = convert_channel_8b_scale(THROTTLE,0x00,0x64); // throttle - packet[1] = convert_channel_8b_scale(RUDDER ,0x00,0x64); // rudder + packet[1] = convert_channel_8b_scale(RUDDER ,0x64,0x00); // rudder packet[2] = convert_channel_8b_scale(ELEVATOR,0x00,0x64); // elevator - packet[3] = convert_channel_8b_scale(AILERON ,0x00,0x64); // aileron + packet[3] = convert_channel_8b_scale(AILERON ,0x64,0x00); // aileron if(packet_count++ >= 23) { yz_seq_num ++; From e04f901590a3a9a453ca630e082619ee87f97315 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 3 Aug 2016 10:12:08 +0200 Subject: [PATCH 128/293] LS protocol features --- Multiprotocol/FQ777_nrf24l01.ino | 2 +- Multiprotocol/MT99xx_nrf24l01.ino | 7 ++++++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/Multiprotocol/FQ777_nrf24l01.ino b/Multiprotocol/FQ777_nrf24l01.ino index c73f89c..1381693 100644 --- a/Multiprotocol/FQ777_nrf24l01.ino +++ b/Multiprotocol/FQ777_nrf24l01.ino @@ -19,7 +19,7 @@ #include "iface_nrf24l01.h" #define FQ777_INITIAL_WAIT 500 -#define FQ777_PACKET_PERIOD 1500 +#define FQ777_PACKET_PERIOD 2000 #define FQ777_PACKET_SIZE 8 #define FQ777_BIND_COUNT 1000 #define FQ777_NUM_RF_CHANNELS 4 diff --git a/Multiprotocol/MT99xx_nrf24l01.ino b/Multiprotocol/MT99xx_nrf24l01.ino index f3493e1..e4d3326 100644 --- a/Multiprotocol/MT99xx_nrf24l01.ino +++ b/Multiprotocol/MT99xx_nrf24l01.ino @@ -82,7 +82,12 @@ static void __attribute__((unused)) MT99XX_send_packet() else //LS { packet[6] |= FLAG_MT_RATE2 // max rate - | GET_FLAG( Servo_AUX5, 0x10 ); //HEADLESS + | GET_FLAG( Servo_AUX2, 0x01 ) //??? + | GET_FLAG( Servo_AUX3, 0x04 ) //??? + | GET_FLAG( Servo_AUX4, 0x08 ) //??? + | GET_FLAG( Servo_AUX5, 0x10 ) //HEADLESS + | GET_FLAG( Servo_AUX6, 0x20 ) //??? + | GET_FLAG( Servo_AUX7, 0x40 ); //??? packet[7] = ls_mys_byte[ls_counter++]; if(ls_counter >= sizeof(ls_mys_byte)) ls_counter=0; From 86728b79e30d9b3bdc579c8505447df28d4e13c2 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 3 Aug 2016 17:32:50 +0200 Subject: [PATCH 129/293] Fixed FQ777 --- Multiprotocol/FQ777_nrf24l01.ino | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Multiprotocol/FQ777_nrf24l01.ino b/Multiprotocol/FQ777_nrf24l01.ino index 1381693..f9affb6 100644 --- a/Multiprotocol/FQ777_nrf24l01.ino +++ b/Multiprotocol/FQ777_nrf24l01.ino @@ -58,8 +58,9 @@ static void __attribute__((unused)) ssv_pack_dpl(uint8_t addr[], uint8_t pid, ui uint16_t val; } crc; + crc.val=0x3c18; for (i = 0; i < 7; ++i) - crc.val=crc16_update(0x3c18,header[i]); + crc.val=crc16_update(crc.val,header[i]); for (i = 0; i < *len; ++i) crc.val=crc16_update(crc.val,payload[i]); @@ -133,7 +134,6 @@ static void __attribute__((unused)) FQ777_send_packet(uint8_t bind) | GET_FLAG(Servo_AUX3, FQ777_FLAG_HEADLESS) | GET_FLAG(!Servo_AUX2, FQ777_FLAG_RETURN) | GET_FLAG(Servo_AUX4,FQ777_FLAG_EXPERT); - packet_ori[6] = 0x00; // calculate checksum uint8_t checksum = 0; @@ -168,6 +168,10 @@ static void __attribute__((unused)) FQ777_init() NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); NRF24L01_SetBitrate(NRF24L01_BR_250K); NRF24L01_SetPower(); + NRF24L01_Activate(0x73); // Activate feature register + NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x00); // Disable dynamic payload length on all pipes + NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x01); + NRF24L01_Activate(0x73); } uint16_t FQ777_callback() From 7107c68a417fe133693c42ffbbed75befff42d95 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 3 Aug 2016 22:50:37 +0200 Subject: [PATCH 130/293] MT99xx->LS: more channels --- Protocols_Details.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 064015c..572fcd6 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -306,7 +306,7 @@ Models: LS114, 124, 215 CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 ---|---|---|---|---|---|---|---|--- -A|E|T|R|FLIP||||HEADLESS +A|E|T|R|FLIP|INVERT|PICTURE|VIDEO|HEADLESS ##Shenqi Autobind protocol From 91e395884fa221e23f67cbe5c670000946e5d3d0 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 3 Aug 2016 23:08:48 +0200 Subject: [PATCH 131/293] MT99xx->LS: more channels --- Multiprotocol/MT99xx_nrf24l01.ino | 22 +++++++++++++++------- 1 file changed, 15 insertions(+), 7 deletions(-) diff --git a/Multiprotocol/MT99xx_nrf24l01.ino b/Multiprotocol/MT99xx_nrf24l01.ino index e4d3326..384745d 100644 --- a/Multiprotocol/MT99xx_nrf24l01.ino +++ b/Multiprotocol/MT99xx_nrf24l01.ino @@ -37,6 +37,16 @@ enum{ FLAG_MT_FLIP = 0x80, }; +enum{ + // flags going to packet[6] (LS) + FLAG_LS_INVERT = 0x01, + FLAG_LS_RATE = 0x02, + FLAG_LS_HEADLESS= 0x10, + FLAG_LS_SNAPSHOT= 0x20, + FLAG_LS_VIDEO = 0x40, + FLAG_LS_FLIP = 0x80, +}; + enum { MT99XX_INIT = 0, MT99XX_BIND, @@ -81,13 +91,11 @@ static void __attribute__((unused)) MT99XX_send_packet() | GET_FLAG( Servo_AUX4, FLAG_MT_VIDEO ); // max rate on MT99xx else //LS { - packet[6] |= FLAG_MT_RATE2 // max rate - | GET_FLAG( Servo_AUX2, 0x01 ) //??? - | GET_FLAG( Servo_AUX3, 0x04 ) //??? - | GET_FLAG( Servo_AUX4, 0x08 ) //??? - | GET_FLAG( Servo_AUX5, 0x10 ) //HEADLESS - | GET_FLAG( Servo_AUX6, 0x20 ) //??? - | GET_FLAG( Servo_AUX7, 0x40 ); //??? + packet[6] |= FLAG_LS_RATE // max rate + | GET_FLAG( Servo_AUX2, FLAG_LS_INVERT ) //INVERT + | GET_FLAG( Servo_AUX3, FLAG_LS_SNAPSHOT ) //SNAPSHOT + | GET_FLAG( Servo_AUX4, FLAG_LS_VIDEO ) //VIDEO + | GET_FLAG( Servo_AUX5, FLAG_LS_HEADLESS ); //HEADLESS packet[7] = ls_mys_byte[ls_counter++]; if(ls_counter >= sizeof(ls_mys_byte)) ls_counter=0; From 9e902a5dd4fdf3538fc418694bed5553d45384e7 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sun, 7 Aug 2016 18:47:26 +0200 Subject: [PATCH 132/293] FQ777 Mod and FrSkyX optimization --- Multiprotocol/FQ777_nrf24l01.ino | 14 ++++++++---- Multiprotocol/FrSkyX_cc2500.ino | 18 ++++++++------- Multiprotocol/Multiprotocol.h | 39 -------------------------------- 3 files changed, 19 insertions(+), 52 deletions(-) diff --git a/Multiprotocol/FQ777_nrf24l01.ino b/Multiprotocol/FQ777_nrf24l01.ino index f9affb6..e2b23f4 100644 --- a/Multiprotocol/FQ777_nrf24l01.ino +++ b/Multiprotocol/FQ777_nrf24l01.ino @@ -113,7 +113,7 @@ static void __attribute__((unused)) FQ777_send_packet(uint8_t bind) //6 00 ?? //7 checksum - add values in other fields - /* + // Trims are usually done through the radio configuration but leaving the code here just in case... uint8_t trim_mod = packet_count % 144; uint8_t trim_val = 0; @@ -121,15 +121,15 @@ static void __attribute__((unused)) FQ777_send_packet(uint8_t bind) trim_val = 0x20; // don't modify yaw trim else if (108 < trim_mod && trim_mod) // pitch - trim_val = map(ppm[FQ777124_TRIM_CHAN_PITCH], PPM_MIN, PPM_MAX, 0x01, 0x3E) + 0xA0 - 0x1F; + trim_val = 0xA0; else // roll - trim_val = map(ppm[FQ777124_TRIM_CHAN_ROLL], PPM_MIN, PPM_MAX, 0x01, 0x3E) + 0x60 - 0x1F;*/ + trim_val = 0x60; packet_ori[0] = convert_channel_8b_scale(THROTTLE,0,0x64); packet_ori[1] = convert_channel_8b_scale(RUDDER,0,0x64); packet_ori[2] = convert_channel_8b_scale(ELEVATOR,0,0x64); packet_ori[3] = convert_channel_8b_scale(AILERON,0,0x64); - packet_ori[4] = 0x20; //trim_val; // calculated above + packet_ori[4] = trim_val; // calculated above packet_ori[5] = GET_FLAG(Servo_AUX1, FQ777_FLAG_FLIP) | GET_FLAG(Servo_AUX3, FQ777_FLAG_HEADLESS) | GET_FLAG(!Servo_AUX2, FQ777_FLAG_RETURN) @@ -166,6 +166,7 @@ static void __attribute__((unused)) FQ777_init() NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // No Auto Acknowledgement on all data pipes NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x00); NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); + NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits NRF24L01_SetBitrate(NRF24L01_BR_250K); NRF24L01_SetPower(); NRF24L01_Activate(0x73); // Activate feature register @@ -179,7 +180,8 @@ uint16_t FQ777_callback() if(bind_counter!=0) { FQ777_send_packet(1); - if (bind_counter-- == 0) + bind_counter--; + if (bind_counter == 0) { NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5); BIND_DONE; @@ -194,6 +196,8 @@ uint16_t initFQ777(void) { BIND_IN_PROGRESS; // autobind protocol bind_counter = FQ777_BIND_COUNT; + packet_count=0; + memset(packet,0,32); hopping_frequency[0] = 0x4D; hopping_frequency[1] = 0x43; hopping_frequency[2] = 0x27; diff --git a/Multiprotocol/FrSkyX_cc2500.ino b/Multiprotocol/FrSkyX_cc2500.ino index 5e29950..ed40f28 100644 --- a/Multiprotocol/FrSkyX_cc2500.ino +++ b/Multiprotocol/FrSkyX_cc2500.ino @@ -119,18 +119,20 @@ static void __attribute__((unused)) initialize_data(uint8_t adr) CC2500_WriteReg(CC2500_09_ADDR, adr ? 0x03 : rx_tx_addr[3]); CC2500_WriteReg(CC2500_07_PKTCTRL1,0x05); } -/* - static uint8_t __attribute__((unused)) crc_Byte( uint8_t byte ) - { - crc = (crc<<8) ^ pgm_read_word(&CRCTable[((uint8_t)(crc>>8) ^ byte) & 0xFF]); - return byte; - } -*/ + +//**CRC** +const uint16_t PROGMEM CRC_Short[]={ + 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, + 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7 }; +static uint16_t __attribute__((unused)) CRCTable(uint8_t val) +{ + return pgm_read_word(&CRC_Short[val&0x0F]) ^ (0x1081 * (val>>4)); +} static uint16_t __attribute__((unused)) crc_x(uint8_t *data, uint8_t len) { uint16_t crc = 0; for(uint8_t i=0; i < len; i++) - crc = (crc<<8) ^ pgm_read_word(&CRCTable[((uint8_t)(crc>>8) ^ *data++) & 0xFF]); + crc = (crc<<8) ^ CRCTable((uint8_t)(crc>>8) ^ *data++); return crc; } diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index d8d94a7..f89b7ef 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -439,45 +439,6 @@ enum { PKT_TIMEOUT }; -//******************* -//*** CRC Table *** -//******************* -const uint16_t PROGMEM CRCTable[]= -{ - 0x0000,0x1189,0x2312,0x329b,0x4624,0x57ad,0x6536,0x74bf, - 0x8c48,0x9dc1,0xaf5a,0xbed3,0xca6c,0xdbe5,0xe97e,0xf8f7, - 0x1081,0x0108,0x3393,0x221a,0x56a5,0x472c,0x75b7,0x643e, - 0x9cc9,0x8d40,0xbfdb,0xae52,0xdaed,0xcb64,0xf9ff,0xe876, - 0x2102,0x308b,0x0210,0x1399,0x6726,0x76af,0x4434,0x55bd, - 0xad4a,0xbcc3,0x8e58,0x9fd1,0xeb6e,0xfae7,0xc87c,0xd9f5, - 0x3183,0x200a,0x1291,0x0318,0x77a7,0x662e,0x54b5,0x453c, - 0xbdcb,0xac42,0x9ed9,0x8f50,0xfbef,0xea66,0xd8fd,0xc974, - 0x4204,0x538d,0x6116,0x709f,0x0420,0x15a9,0x2732,0x36bb, - 0xce4c,0xdfc5,0xed5e,0xfcd7,0x8868,0x99e1,0xab7a,0xbaf3, - 0x5285,0x430c,0x7197,0x601e,0x14a1,0x0528,0x37b3,0x263a, - 0xdecd,0xcf44,0xfddf,0xec56,0x98e9,0x8960,0xbbfb,0xaa72, - 0x6306,0x728f,0x4014,0x519d,0x2522,0x34ab,0x0630,0x17b9, - 0xef4e,0xfec7,0xcc5c,0xddd5,0xa96a,0xb8e3,0x8a78,0x9bf1, - 0x7387,0x620e,0x5095,0x411c,0x35a3,0x242a,0x16b1,0x0738, - 0xffcf,0xee46,0xdcdd,0xcd54,0xb9eb,0xa862,0x9af9,0x8b70, - 0x8408,0x9581,0xa71a,0xb693,0xc22c,0xd3a5,0xe13e,0xf0b7, - 0x0840,0x19c9,0x2b52,0x3adb,0x4e64,0x5fed,0x6d76,0x7cff, - 0x9489,0x8500,0xb79b,0xa612,0xd2ad,0xc324,0xf1bf,0xe036, - 0x18c1,0x0948,0x3bd3,0x2a5a,0x5ee5,0x4f6c,0x7df7,0x6c7e, - 0xa50a,0xb483,0x8618,0x9791,0xe32e,0xf2a7,0xc03c,0xd1b5, - 0x2942,0x38cb,0x0a50,0x1bd9,0x6f66,0x7eef,0x4c74,0x5dfd, - 0xb58b,0xa402,0x9699,0x8710,0xf3af,0xe226,0xd0bd,0xc134, - 0x39c3,0x284a,0x1ad1,0x0b58,0x7fe7,0x6e6e,0x5cf5,0x4d7c, - 0xc60c,0xd785,0xe51e,0xf497,0x8028,0x91a1,0xa33a,0xb2b3, - 0x4a44,0x5bcd,0x6956,0x78df,0x0c60,0x1de9,0x2f72,0x3efb, - 0xd68d,0xc704,0xf59f,0xe416,0x90a9,0x8120,0xb3bb,0xa232, - 0x5ac5,0x4b4c,0x79d7,0x685e,0x1ce1,0x0d68,0x3ff3,0x2e7a, - 0xe70e,0xf687,0xc41c,0xd595,0xa12a,0xb0a3,0x8238,0x93b1, - 0x6b46,0x7acf,0x4854,0x59dd,0x2d62,0x3ceb,0x0e70,0x1ff9, - 0xf78f,0xe606,0xd49d,0xc514,0xb1ab,0xa022,0x92b9,0x8330, - 0x7bc7,0x6a4e,0x58d5,0x495c,0x3de3,0x2c6a,0x1ef1,0x0f78 -}; - //**************************************** //*** MULTI protocol serial definition *** //**************************************** From 7438545a161b02dcf967cfde37b53c8cbab47e12 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 15 Aug 2016 11:52:43 +0200 Subject: [PATCH 133/293] Invert serial, optimization and SFHSS --- Multiprotocol/A7105_SPI.ino | 6 +- Multiprotocol/CC2500_SPI.ino | 6 +- Multiprotocol/CYRF6936_SPI.ino | 6 +- Multiprotocol/DSM2_cyrf6936.ino | 8 +- Multiprotocol/Devo_cyrf6936.ino | 96 ++++--- Multiprotocol/FlySky_a7105.ino | 7 +- Multiprotocol/FrSkyX_cc2500.ino | 13 +- Multiprotocol/Multiprotocol.h | 4 + Multiprotocol/Multiprotocol.ino | 126 ++++----- Multiprotocol/NRF24l01_SPI.ino | 6 +- Multiprotocol/SFHSS_cc2500.ino | 39 +-- Multiprotocol/Symax_nrf24l01.ino | 2 +- Multiprotocol/Telemetry.ino | 444 ++++++++++++++++++++++++++++--- Multiprotocol/_Config.h | 25 +- 14 files changed, 611 insertions(+), 177 deletions(-) diff --git a/Multiprotocol/A7105_SPI.ino b/Multiprotocol/A7105_SPI.ino index 15c0b56..6582876 100644 --- a/Multiprotocol/A7105_SPI.ino +++ b/Multiprotocol/A7105_SPI.ino @@ -155,7 +155,11 @@ void A7105_SetPower() power=IS_POWER_FLAG_on?A7105_HIGH_POWER:A7105_LOW_POWER; if(IS_RANGE_FLAG_on) power=A7105_RANGE_POWER; - A7105_WriteReg(0x28, power); + if(prev_power != power) + { + A7105_WriteReg(0x28, power); + prev_power=power; + } } void A7105_Strobe(uint8_t address) { diff --git a/Multiprotocol/CC2500_SPI.ino b/Multiprotocol/CC2500_SPI.ino index 67ea66c..410d8e3 100644 --- a/Multiprotocol/CC2500_SPI.ino +++ b/Multiprotocol/CC2500_SPI.ino @@ -125,7 +125,11 @@ void CC2500_SetPower() power=IS_POWER_FLAG_on?CC2500_HIGH_POWER:CC2500_LOW_POWER; if(IS_RANGE_FLAG_on) power=CC2500_RANGE_POWER; - CC2500_WriteReg(CC2500_3E_PATABLE, power); + if(prev_power != power) + { + CC2500_WriteReg(CC2500_3E_PATABLE, power); + prev_power=power; + } } void CC2500_SetTxRxMode(uint8_t mode) diff --git a/Multiprotocol/CYRF6936_SPI.ino b/Multiprotocol/CYRF6936_SPI.ino index 51a9b08..3699e9e 100644 --- a/Multiprotocol/CYRF6936_SPI.ino +++ b/Multiprotocol/CYRF6936_SPI.ino @@ -128,7 +128,11 @@ void CYRF_SetPower(uint8_t val) power=IS_POWER_FLAG_on?CYRF_HIGH_POWER:CYRF_LOW_POWER; if(IS_RANGE_FLAG_on) power=CYRF_RANGE_POWER; - CYRF_WriteRegister(CYRF_03_TX_CFG, val | power); + if(prev_power != power) + { + CYRF_WriteRegister(CYRF_03_TX_CFG, val | power); + prev_power=power; + } } /* diff --git a/Multiprotocol/DSM2_cyrf6936.ino b/Multiprotocol/DSM2_cyrf6936.ino index b51279a..429dd60 100644 --- a/Multiprotocol/DSM2_cyrf6936.ino +++ b/Multiprotocol/DSM2_cyrf6936.ino @@ -416,7 +416,7 @@ uint16_t ReadDsm2() #define DSM_CH1_CH2_DELAY 4010 // Time between write of channel 1 and channel 2 #define DSM_WRITE_DELAY 1550 // Time after write to verify write complete #define DSM_READ_DELAY 600 // Time before write to check read state, and switch channels. Was 400 but 500 seems what the 328p needs to read a packet - uint32_t start; + uint16_t start; switch(cyrf_state) { @@ -458,7 +458,7 @@ uint16_t ReadDsm2() case DSM2_CH1_CHECK_A: case DSM2_CH1_CHECK_B: start=micros(); - while (micros()-start < 500) // Wait max 500µs + while ((uint16_t)micros()-start < 500) // Wait max 500µs if(CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02) break; set_sop_data_crc(); @@ -467,7 +467,7 @@ uint16_t ReadDsm2() case DSM2_CH2_CHECK_A: case DSM2_CH2_CHECK_B: start=micros(); - while (micros()-start < 500) // Wait max 500µs + while ((uint16_t)micros()-start < 500) // Wait max 500µs if(CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02) break; if (cyrf_state == DSM2_CH2_CHECK_A) @@ -501,7 +501,7 @@ uint16_t ReadDsm2() //Force end read state CYRF_WriteRegister(CYRF_0F_XACT_CFG, (CYRF_ReadRegister(CYRF_0F_XACT_CFG) | 0x20)); // Force end state start=micros(); - while (micros()-start < 100) // Wait max 100 µs + while ((uint16_t)micros()-start < 100) // Wait max 100 µs if((CYRF_ReadRegister(CYRF_0F_XACT_CFG) & 0x20) == 0) break; cyrf_state = DSM2_CH2_READ_B; diff --git a/Multiprotocol/Devo_cyrf6936.ino b/Multiprotocol/Devo_cyrf6936.ino index e569cb9..e7b446a 100644 --- a/Multiprotocol/Devo_cyrf6936.ino +++ b/Multiprotocol/Devo_cyrf6936.ino @@ -116,24 +116,28 @@ static void __attribute__((unused)) build_beacon_pkt(uint8_t upper) add_pkt_suffix(); } +#define FORCE_INDIRECT(ptr) __asm__ __volatile__ ("" : "=e" (ptr) : "0" (ptr)) + static void __attribute__((unused)) build_bind_pkt() { - packet[0] = (DEVO_NUM_CHANNELS << 4) | 0x0a; - packet[1] = bind_counter & 0xff; - packet[2] = (bind_counter >> 8); - packet[3] = *hopping_frequency_ptr; - packet[4] = *(hopping_frequency_ptr + 1); - packet[5] = *(hopping_frequency_ptr + 2); - packet[6] = cyrfmfg_id[0]; - packet[7] = cyrfmfg_id[1]; - packet[8] = cyrfmfg_id[2]; - packet[9] = cyrfmfg_id[3]; + uint8_t *p = packet ; + FORCE_INDIRECT(p) ; + p[0] = (DEVO_NUM_CHANNELS << 4) | 0x0a; + p[1] = bind_counter & 0xff; + p[2] = (bind_counter >> 8); + p[3] = *hopping_frequency_ptr; + p[4] = *(hopping_frequency_ptr + 1); + p[5] = *(hopping_frequency_ptr + 2); + p[6] = cyrfmfg_id[0]; + p[7] = cyrfmfg_id[1]; + p[8] = cyrfmfg_id[2]; + p[9] = cyrfmfg_id[3]; add_pkt_suffix(); //The fixed-id portion is scrambled in the bind packet //I assume it is ignored - packet[13] ^= cyrfmfg_id[0]; - packet[14] ^= cyrfmfg_id[1]; - packet[15] ^= cyrfmfg_id[2]; + p[13] ^= cyrfmfg_id[0]; + p[14] ^= cyrfmfg_id[1]; + p[15] ^= cyrfmfg_id[2]; } static void __attribute__((unused)) build_data_pkt() @@ -174,31 +178,57 @@ static void __attribute__((unused)) cyrf_set_bound_sop_code() CYRF_SetPower(0x08); } +const uint8_t PROGMEM devo_init_vals[][2] = { + {CYRF_06_RX_CFG, 0x4A }, + {CYRF_0B_PWR_CTRL, 0x00 }, + {CYRF_0D_IO_CFG, 0x04 }, + {CYRF_0E_GPIO_CTRL, 0x20 }, + {CYRF_10_FRAMING_CFG, 0xA4 }, + {CYRF_11_DATA32_THOLD, 0x05 }, + {CYRF_12_DATA64_THOLD, 0x0E }, + {CYRF_1B_TX_OFFSET_LSB, 0x55 }, + {CYRF_1C_TX_OFFSET_MSB, 0x05 }, + {CYRF_32_AUTO_CAL_TIME, 0x3C }, + {CYRF_35_AUTOCAL_OFFSET, 0x14 }, + {CYRF_39_ANALOG_CTRL, 0x01 }, + {CYRF_1E_RX_OVERRIDE, 0x10 }, + {CYRF_1F_TX_OVERRIDE, 0x00 }, + {CYRF_01_TX_LENGTH, 0x10 }, + {CYRF_0C_XTAL_CTRL, 0xC0 }, + {CYRF_0F_XACT_CFG, 0x10 }, + {CYRF_27_CLK_OVERRIDE, 0x02 }, + {CYRF_28_CLK_EN, 0x02 }, + {CYRF_0F_XACT_CFG, 0x28 } +}; + static void __attribute__((unused)) cyrf_init() { /* Initialise CYRF chip */ CYRF_WriteRegister(CYRF_1D_MODE_OVERRIDE, 0x39); CYRF_SetPower(0x08); - CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4A); - CYRF_WriteRegister(CYRF_0B_PWR_CTRL, 0x00); - CYRF_WriteRegister(CYRF_0D_IO_CFG, 0x04); - CYRF_WriteRegister(CYRF_0E_GPIO_CTRL, 0x20); - CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0xA4); - CYRF_WriteRegister(CYRF_11_DATA32_THOLD, 0x05); - CYRF_WriteRegister(CYRF_12_DATA64_THOLD, 0x0E); - CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, 0x55); - CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, 0x05); - CYRF_WriteRegister(CYRF_32_AUTO_CAL_TIME, 0x3C); - CYRF_WriteRegister(CYRF_35_AUTOCAL_OFFSET, 0x14); - CYRF_WriteRegister(CYRF_39_ANALOG_CTRL, 0x01); - CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x10); - CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x00); - CYRF_WriteRegister(CYRF_01_TX_LENGTH, 0x10); - CYRF_WriteRegister(CYRF_0C_XTAL_CTRL, 0xC0); - CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x10); - CYRF_WriteRegister(CYRF_27_CLK_OVERRIDE, 0x02); - CYRF_WriteRegister(CYRF_28_CLK_EN, 0x02); - CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x28); + for(uint8_t i = 0; i < sizeof(devo_init_vals) / 2; i++) + CYRF_WriteRegister(pgm_read_byte( &devo_init_vals[i][0]), pgm_read_byte( &devo_init_vals[i][1]) ); + +// CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4A); +// CYRF_WriteRegister(CYRF_0B_PWR_CTRL, 0x00); +// CYRF_WriteRegister(CYRF_0D_IO_CFG, 0x04); +// CYRF_WriteRegister(CYRF_0E_GPIO_CTRL, 0x20); +// CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0xA4); +// CYRF_WriteRegister(CYRF_11_DATA32_THOLD, 0x05); +// CYRF_WriteRegister(CYRF_12_DATA64_THOLD, 0x0E); +// CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, 0x55); +// CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, 0x05); +// CYRF_WriteRegister(CYRF_32_AUTO_CAL_TIME, 0x3C); +// CYRF_WriteRegister(CYRF_35_AUTOCAL_OFFSET, 0x14); +// CYRF_WriteRegister(CYRF_39_ANALOG_CTRL, 0x01); +// CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x10); +// CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x00); +// CYRF_WriteRegister(CYRF_01_TX_LENGTH, 0x10); +// CYRF_WriteRegister(CYRF_0C_XTAL_CTRL, 0xC0); +// CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x10); +// CYRF_WriteRegister(CYRF_27_CLK_OVERRIDE, 0x02); +// CYRF_WriteRegister(CYRF_28_CLK_EN, 0x02); +// CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x28); } static void __attribute__((unused)) set_radio_channels() diff --git a/Multiprotocol/FlySky_a7105.ino b/Multiprotocol/FlySky_a7105.ino index 92f723d..a7f4033 100644 --- a/Multiprotocol/FlySky_a7105.ino +++ b/Multiprotocol/FlySky_a7105.ino @@ -54,10 +54,11 @@ uint8_t chanrow; uint8_t chancol; uint8_t chanoffset; +const uint8_t PROGMEM V912_X17_SEQ[10] = { 0x14, 0x31, 0x40, 0x49, 0x49, // sometime first byte is 0x15 ? + 0x49, 0x49, 0x49, 0x49, 0x49, }; + static void __attribute__((unused)) flysky_apply_extension_flags() { - const uint8_t V912_X17_SEQ[10] = { 0x14, 0x31, 0x40, 0x49, 0x49, // sometime first byte is 0x15 ? - 0x49, 0x49, 0x49, 0x49, 0x49, }; static uint8_t seq_counter; switch(sub_protocol) { @@ -115,7 +116,7 @@ static void __attribute__((unused)) flysky_apply_extension_flags() packet[14] |= FLAG_V912_TOPBTN; packet[15] = 0x27; // [15] and [16] apparently hold an analog channel with a value lower than 1000 packet[16] = 0x03; // maybe it's there for a pitch channel for a CP copter ? - packet[17] = V912_X17_SEQ[seq_counter]; // not sure what [17] & [18] are for + packet[17] = pgm_read_byte( &V912_X17_SEQ[seq_counter] ) ; // not sure what [17] & [18] are for if(seq_counter == 0) // V912 Rx does not even read those bytes... [17-20] packet[18] = 0x02; else diff --git a/Multiprotocol/FrSkyX_cc2500.ino b/Multiprotocol/FrSkyX_cc2500.ino index ed40f28..d631821 100644 --- a/Multiprotocol/FrSkyX_cc2500.ino +++ b/Multiprotocol/FrSkyX_cc2500.ino @@ -89,6 +89,7 @@ static void __attribute__((unused)) frskyX_init() } CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x04); + prev_option = option ; CC2500_WriteReg(CC2500_0C_FSCTRL0, option); CC2500_Strobe(CC2500_SIDLE); // @@ -124,9 +125,12 @@ static void __attribute__((unused)) initialize_data(uint8_t adr) const uint16_t PROGMEM CRC_Short[]={ 0x0000, 0x1189, 0x2312, 0x329B, 0x4624, 0x57AD, 0x6536, 0x74BF, 0x8C48, 0x9DC1, 0xAF5A, 0xBED3, 0xCA6C, 0xDBE5, 0xE97E, 0xF8F7 }; -static uint16_t __attribute__((unused)) CRCTable(uint8_t val) +static uint16_t CRCTable(uint8_t val) { - return pgm_read_word(&CRC_Short[val&0x0F]) ^ (0x1081 * (val>>4)); + uint16_t word ; + word = pgm_read_word(&CRC_Short[val&0x0F]) ; + val /= 16 ; + return word ^ (0x1081 * val) ; } static uint16_t __attribute__((unused)) crc_x(uint8_t *data, uint8_t len) { @@ -253,6 +257,11 @@ uint16_t ReadFrSkyX() state++; break; case FRSKY_DATA1: + if ( prev_option != option ) + { + CC2500_WriteReg(CC2500_0C_FSCTRL0,option); // Frequency offset hack + prev_option = option ; + } LED_ON; CC2500_SetTxRxMode(TX_EN); set_start(channr); diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index f89b7ef..f9ffdbb 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -439,6 +439,10 @@ enum { PKT_TIMEOUT }; +// baudrate defines for serial +#define SPEED_100K 0 +#define SPEED_9600 1 + //**************************************** //*** MULTI protocol serial definition *** //**************************************** diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 8e0416a..882541a 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -36,6 +36,8 @@ uint32_t Model_fixed_id=0; uint32_t fixed_id; uint8_t cyrfmfg_id[6];//for dsm2 and devo uint32_t blink=0; +uint8_t prev_option; +uint8_t prev_power=0xFD; // unused power value // uint16_t counter; uint8_t channel; @@ -85,11 +87,19 @@ uint8_t protocol_flags=0,protocol_flags2=0; volatile uint16_t PPM_data[NUM_CHN]; // Serial variables +#ifdef INVERT_TELEMETRY +// enable bit bash for serial + #define BASH_SERIAL 1 + #define INVERT_SERIAL 1 +#endif +#define BAUD 100000 #define RXBUFFER_SIZE 25 -#define TXBUFFER_SIZE 20 +#define TXBUFFER_SIZE 32 volatile uint8_t rx_buff[RXBUFFER_SIZE]; volatile uint8_t rx_ok_buff[RXBUFFER_SIZE]; +#ifndef BASH_SERIAL volatile uint8_t tx_buff[TXBUFFER_SIZE]; +#endif volatile uint8_t idx = 0; //Serial protocol @@ -112,8 +122,10 @@ uint8_t pkt[MAX_PKT];//telemetry receiving packets #define HUB_TELEMETRY #endif uint8_t pktt[MAX_PKT];//telemetry receiving packets +#ifndef BASH_SERIAL volatile uint8_t tx_head=0; volatile uint8_t tx_tail=0; +#endif // BASH_SERIAL uint8_t v_lipo; int16_t RSSI_dBm; //const uint8_t RSSI_offset=72;//69 71.72 values db @@ -283,9 +295,11 @@ void loop() { for(uint8_t i=0;i4000) { // start to wait here as much as we can... next_callback=next_callback-2000; - cli(); // disable global int #ifdef XMEGA + cli(); // disable global int TCC1.CCA +=2000*2; // set compare A for callback TCC1.INTFLAGS = TC1_CCAIF_bm ; // clear compare A=callback flag sei(); // enable global int while((TCC1.INTFLAGS & TC1_CCAIF_bm) == 0); // wait 2ms... #else - OCR1A+=2000*2; // set compare A for callback + uint16_t temp ; + temp = OCR1A + 2000*2 ; + cli(); // disable global int + OCR1A = temp ; // set compare A for callback TIFR1=(1<=TXBUFFER_SIZE) - tx_head=0; - tx_buff[tx_head]=data; -#ifdef XMEGA - USARTC0.CTRLA = (USARTC0.CTRLA & 0xFC) | 0x01 ; -#else - UCSR0B |= (1<>1; - if(aPPM_MAX) a=PPM_MAX; - PPM_data[chan]=a; + uint16_t temp = Cur_TCNT1>>1; + if(tempPPM_MAX) temp=PPM_MAX; + PPM_data[chan]=temp; if(chan++>=NUM_CHN) chan=-1; // don't accept any new channels } @@ -1041,6 +1033,10 @@ ISR(USART_RX_vect) #ifdef XMEGA if((USARTC0.STATUS & 0x1C)==0) // Check frame error, data overrun and parity error #else + + UCSR0B &= ~(1<=TXBUFFER_SIZE)//head - tx_tail=0; -#ifdef XMEGA - USARTC0.DATA = tx_buff[tx_tail] ; -#else - UDR0=tx_buff[tx_tail]; -#endif - } - if (tx_tail == tx_head) -#ifdef XMEGA - USARTC0.CTRLA &= ~0x03 ; -#else - UCSR0B &= ~(1<= FRSKY_SPORT_PACKET_SIZE) {//8 bytes no crc - sport = 1;//ok to send + if ( sport ) + { + // overrun! + } + else + { + uint8_t i ; + for ( i = 0 ; i < FRSKY_SPORT_PACKET_SIZE ; i += 1 ) + { + pktx1[i] = pktx[i] ; // Double buffer + } + sport = 1;//ok to send + } pass = 0;//reset } } @@ -362,7 +395,62 @@ void proces_sport_data(uint8_t data) #endif void frskyUpdate() -{ +{ +#if defined SPORT_TELEMETRY + if ((cur_protocol[0]&0x1F)==MODE_FRSKYX) + { // FrSkyX + if(telemetry_link) + { + if(pktt[4] & 0x80) + rssi=pktt[4] & 0x7F ; + else + RxBt = (pktt[4]<<1) + 1 ; + for (uint8_t i=0; i < pktt[6]; i++) + proces_sport_data(pktt[7+i]); + telemetry_link=0; + } + } +#endif + + // check for space in tx buffer + +#ifdef BASH_SERIAL + uint8_t h ; + uint8_t t ; + h = SerialControl.head ; + t = SerialControl.tail ; + if ( h >= t ) + { + t += 64 - h ; + } + else + { + t -= h ; + } + if ( t < 32 ) + { + return ; + } + +#else + uint8_t h ; + uint8_t t ; + h = tx_head ; + t = tx_tail ; + if ( h >= t ) + { + t += TXBUFFER_SIZE - h ; + } + else + { + t -= h ; + } + if ( t < 16 ) + { + return ; + } +#endif + #if defined DSM_TELEMETRY if(telemetry_link && (cur_protocol[0]&0x1F) == MODE_DSM2 ) { // DSM2 @@ -387,24 +475,318 @@ void frskyUpdate() #if defined SPORT_TELEMETRY if ((cur_protocol[0]&0x1F)==MODE_FRSKYX) { // FrSkyX - if(telemetry_link) - { - if(pktt[4]>0x36) - rssi=pktt[4]>>1; - else - RxBt=pktt[4]; - for (uint8_t i=0; i < pktt[6]; i++) - proces_sport_data(pktt[7+i]); - telemetry_link=0; - } uint32_t now = micros(); if ((now - last) > SPORT_TIME) { sportSendFrame(); - last = now; + last += SPORT_TIME ; } } #endif } -#endif \ No newline at end of file + +/**************************/ +/**************************/ +/** Serial TX routines **/ +/**************************/ +/**************************/ + +#ifndef BASH_SERIAL +// Routines for normal serial output +void Serial_write(uint8_t data) +{ + cli(); // disable global int + if(++tx_head>=TXBUFFER_SIZE) + tx_head=0; + tx_buff[tx_head]=data; +#ifdef XMEGA + USARTC0.CTRLA = (USARTC0.CTRLA & 0xFC) | 0x01 ; +#else + UCSR0B |= (1<=TXBUFFER_SIZE)//head + tx_tail=0; +#ifdef XMEGA + USARTC0.DATA = tx_buff[tx_tail] ; +#else + UDR0=tx_buff[tx_tail]; +#endif + } + if (tx_tail == tx_head) +#ifdef XMEGA + USARTC0.CTRLA &= ~0x03 ; +#else + UCSR0B &= ~(1<>= 7 ; // Top bit + if ( SerialControl.speed == SPEED_100K ) + { +#ifdef INVERT_SERIAL + byteLo |= 0x02 ; // Parity bit +#else + byteLo |= 0xFC ; // Stop bits +#endif + // calc parity + temp = byte ; + temp >>= 4 ; + temp = byte ^ temp ; + temp1 = temp ; + temp1 >>= 2 ; + temp = temp ^ temp1 ; + temp1 = temp ; + temp1 <<= 1 ; + temp ^= temp1 ; + temp &= 0x02 ; +#ifdef INVERT_SERIAL + byteLo ^= temp ; +#else + byteLo |= temp ; +#endif + } + else + { + byteLo |= 0xFE ; // Stop bit + } + byte <<= 1 ; +#ifdef INVERT_SERIAL + byte |= 1 ; // Start bit +#endif + uint8_t next = (SerialControl.head + 2) & 0x3f ; + if ( next != SerialControl.tail ) + { + SerialControl.data[SerialControl.head] = byte ; + SerialControl.data[SerialControl.head+1] = byteLo ; + SerialControl.head = next ; + } + cli() ; + if ( SerialControl.busy == 0 ) + { + sei() ; + // Start the transmission here +#ifdef INVERT_SERIAL + GPIOR2 = 0 ; +#else + GPIOR2 = 0x01 ; +#endif + if ( SerialControl.speed == SPEED_100K ) + { + GPIOR1 = 1 ; + OCR0B = TCNT0 + 40 ; + OCR0A = OCR0B + 210 ; + TIFR0 = (1<>= 1 + GPIOR0 = byte ; + if ( --GPIOR1 == 0 ) + { + TIMSK0 &= ~(1<>= 1 + 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< 2 ) + { + byte = GPIOR0 ; + } + else + { + byte = GPIOR2 ; + } + if ( byte & 0x01 ) + { + PORTD |= 0x02 ; + } + else + { + PORTD &= ~0x02 ; + } + byte /= 2 ; // Generates shorter code than byte >>= 1 + if ( GPIOR1 > 2 ) + { + GPIOR0 = byte ; + } + else + { + GPIOR2 = byte ; + } + if ( --GPIOR1 == 0 ) + { + // prepare next byte + 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 = 10 ; + } + else + { + SerialControl.busy = 0 ; + TIMSK0 &= ~(1<2012µs) //#define TX_ER9X_TAER //ER9X TAER (988<->2012µs) @@ -22,6 +25,9 @@ //#define TX_SPEKTRUM //Spektrum TAER (1100<->1900µs) //#define TX_HISKY //HISKY AETR (1100<->1900µs) +/****************************/ +/*** PROTOCOLS TO INCLUDE ***/ +/****************************/ //Comment if a module is not installed #define A7105_INSTALLED #define CYRF6936_INSTALLED @@ -61,9 +67,15 @@ #define FQ777_NRF24L01_INO #endif +/**************************/ +/*** TELEMETRY SETTINGS ***/ +/**************************/ //Uncomment to enable telemetry #define TELEMETRY +//Uncomment to invert the telemetry serial signal, this is usefull for OpenTX on Taranis as an example +//#define INVERT_TELEMETRY 1 + //Comment to disable a specific telemetry #if defined(TELEMETRY) #if defined DSM2_CYRF6936_INO @@ -77,6 +89,9 @@ #endif #endif +/********************/ +/*** PPM SETTINGS ***/ +/********************/ //Update this table to set which protocol and all associated settings are called for the corresponding dial number const PPM_Parameters PPM_prot[15]= { // Dial Protocol Sub protocol RX_Num Power Auto Bind Option @@ -180,9 +195,9 @@ Auto Bind AUTOBIND or NO_AUTOBIND Option value between 0 and 255. 0xD7 or 0x00 for Frsky fine tuning. */ -//****************** -//TX definitions with timing endpoints and channels order - +/*******************/ +/*** TX SETTINGS ***/ +/*******************/ // Turnigy PPM and channels #if defined(TX_ER9X_AETR) #define PPM_MAX 2140 // 125% @@ -301,7 +316,3 @@ enum chan_order{ #define PPM_MIN_COMMAND 1250 #define PPM_SWITCH 1550 #define PPM_MAX_COMMAND 1750 - -//Uncoment the desired serial speed -#define BAUD 100000 -//#define BAUD 125000 From 181a70cb1f3df3075e721ea783cbc3571a80502e Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 16 Aug 2016 11:06:24 +0200 Subject: [PATCH 134/293] SFHSS fix? --- Multiprotocol/SFHSS_cc2500.ino | 38 +++++++++++++++++----------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/Multiprotocol/SFHSS_cc2500.ino b/Multiprotocol/SFHSS_cc2500.ino index 3984c04..b0cb911 100644 --- a/Multiprotocol/SFHSS_cc2500.ino +++ b/Multiprotocol/SFHSS_cc2500.ino @@ -27,11 +27,11 @@ uint8_t fhss_code; // 0-27 enum { - SFHSS_START = 0x101, - SFHSS_CAL = 0x102, - SFHSS_TUNE = 0x103, - SFHSS_DATA1 = 0x02, - SFHSS_DATA2 = 0x0b + SFHSS_START = 0x00, + SFHSS_CAL = 0x01, + SFHSS_DATA1 = 0x02, // do not change + SFHSS_DATA2 = 0x0B, // do not change + SFHSS_TUNE = 0x0F }; #define SFHSS_FREQ0_VAL 0xC4 @@ -82,7 +82,7 @@ static void __attribute__((unused)) SFHSS_rf_init() for (uint8_t i = 0; i < 39; ++i) CC2500_WriteReg(i, pgm_read_byte_near(&SFHSS_init_values[i])); - prev_option = option+1; + prev_option = 0; //CC2500_WriteReg(CC2500_0C_FSCTRL0, option); CC2500_SetTxRxMode(TX_EN); @@ -101,7 +101,7 @@ static void __attribute__((unused)) SFHSS_tune_chan_fast() CC2500_Strobe(CC2500_SIDLE); CC2500_WriteReg(CC2500_0A_CHANNR, rf_ch_num*6+16); CC2500_WriteRegisterMulti(CC2500_23_FSCAL3, calData[rf_ch_num], 3); - delayMicroseconds(6); + delayMicroseconds(100); //6); } #ifdef SFHSS_USE_TUNE_FREQ @@ -139,7 +139,7 @@ static void __attribute__((unused)) SFHSS_build_data_packet() { #define spacer1 0x02 //0b10 #define spacer2 (spacer1 << 4) - uint8_t ch_offset = state == SFHSS_DATA1 ? 0 : 4; + uint8_t ch_offset = phase == SFHSS_DATA1 ? 0 : 4; uint16_t ch1 = SFHSS_convert_channel(CH_AETR[ch_offset+0]); uint16_t ch2 = SFHSS_convert_channel(CH_AETR[ch_offset+1]); uint16_t ch3 = SFHSS_convert_channel(CH_AETR[ch_offset+2]); @@ -157,7 +157,7 @@ static void __attribute__((unused)) SFHSS_build_data_packet() packet[9] = (ch3 >> 1); packet[10] = (ch3 << 7) | spacer2 | ((ch4 >> 5) & 0x1F /*0b11111*/); packet[11] = (ch4 << 3) | ((fhss_code >> 2) & 0x07 /*0b111 */); - packet[12] = (fhss_code << 6) | state; + packet[12] = (fhss_code << 6) | phase; } static void __attribute__((unused)) SFHSS_send_packet() @@ -168,12 +168,12 @@ static void __attribute__((unused)) SFHSS_send_packet() uint16_t ReadSFHSS() { - switch(state) + switch(phase) { case SFHSS_START: rf_ch_num = 0; SFHSS_tune_chan(); - state = SFHSS_CAL; + phase = SFHSS_CAL; return 2000; case SFHSS_CAL: CC2500_ReadRegisterMulti(CC2500_23_FSCAL3, calData[rf_ch_num], 3); @@ -182,7 +182,7 @@ uint16_t ReadSFHSS() else { rf_ch_num = 0; - state = SFHSS_DATA1; + phase = SFHSS_DATA1; } return 2000; @@ -190,38 +190,38 @@ uint16_t ReadSFHSS() case SFHSS_DATA1: SFHSS_build_data_packet(); SFHSS_send_packet(); - state = SFHSS_DATA2; + phase = SFHSS_DATA2; return 1650; case SFHSS_DATA2: SFHSS_build_data_packet(); SFHSS_send_packet(); SFHSS_calc_next_chan(); - state = SFHSS_TUNE; + phase = SFHSS_TUNE; return 2000; case SFHSS_TUNE: #ifdef SFHSS_USE_TUNE_FREQ SFHSS_tune_freq(); #endif CC2500_SetPower(); - state = SFHSS_DATA1; + phase = SFHSS_DATA1; return 3150; /* case SFHSS_DATA1: SFHSS_build_data_packet(); SFHSS_send_packet(); - state = SFHSS_DATA2; + phase = SFHSS_DATA2; return 1650; case SFHSS_DATA2: SFHSS_build_data_packet(); SFHSS_send_packet(); - state = SFHSS_CAL2; + phase = SFHSS_CAL2; return 500; case SFHSS_CAL2: SFHSS_tune_freq(); // CC2500_SetPower(); SFHSS_calc_next_chan(); SFHSS_tune_chan(); - state = SFHSS_DATA1; + phase = SFHSS_DATA1; return 4650; */ } @@ -266,7 +266,7 @@ uint16_t initSFHSS() fhss_code=rx_tx_addr[2]%28; // Initialize it to random 0-27 inclusive SFHSS_rf_init(); - state = SFHSS_START; + phase = SFHSS_START; return 10000; } From 0a4ce2350a399767f462bb86cbe120f6751a645d Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 16 Aug 2016 16:27:53 +0200 Subject: [PATCH 135/293] SFHSS fix? --- Multiprotocol/CC2500_SPI.ino | 102 +++++++++++++++++---------------- Multiprotocol/SFHSS_cc2500.ino | 2 +- 2 files changed, 53 insertions(+), 51 deletions(-) diff --git a/Multiprotocol/CC2500_SPI.ino b/Multiprotocol/CC2500_SPI.ino index 410d8e3..85a3cf4 100644 --- a/Multiprotocol/CC2500_SPI.ino +++ b/Multiprotocol/CC2500_SPI.ino @@ -19,22 +19,50 @@ //------------------------------- #include "iface_cc2500.h" -void CC2500_ReadData(uint8_t *dpbuffer, uint8_t len) +//---------------------------- +void CC2500_WriteReg(uint8_t address, uint8_t data) { - CC2500_ReadRegisterMulti(CC2500_3F_RXFIFO | CC2500_READ_BURST, dpbuffer, len); -} + CC25_CSN_off; + SPI_Write(address); + NOP(); + SPI_Write(data); + CC25_CSN_on; +} //---------------------- static void CC2500_ReadRegisterMulti(uint8_t address, uint8_t data[], uint8_t length) { CC25_CSN_off; - SPI_Write(address); + SPI_Write(CC2500_READ_BURST | address); for(uint8_t i = 0; i < length; i++) data[i] = SPI_Read(); CC25_CSN_on; } +//-------------------------------------------- +static uint8_t CC2500_ReadReg(uint8_t address) +{ + uint8_t result; + CC25_CSN_off; + SPI_Write(CC2500_READ_SINGLE | address); + result = SPI_Read(); + CC25_CSN_on; + return(result); +} + +//------------------------ +void CC2500_ReadData(uint8_t *dpbuffer, uint8_t len) +{ + CC2500_ReadRegisterMulti(CC2500_3F_RXFIFO, dpbuffer, len); +} + //********************************************* +void CC2500_Strobe(uint8_t state) +{ + CC25_CSN_off; + SPI_Write(state); + CC25_CSN_on; +} static void CC2500_WriteRegisterMulti(uint8_t address, const uint8_t data[], uint8_t length) { @@ -47,38 +75,31 @@ static void CC2500_WriteRegisterMulti(uint8_t address, const uint8_t data[], uin void CC2500_WriteData(uint8_t *dpbuffer, uint8_t len) { - CC2500_Strobe(CC2500_SFTX);//0x3B + CC2500_Strobe(CC2500_SFTX); CC2500_WriteRegisterMulti(CC2500_3F_TXFIFO, dpbuffer, len); - CC2500_Strobe(CC2500_STX);//0x35 + CC2500_Strobe(CC2500_STX); } -//---------------------------- -void CC2500_WriteReg(uint8_t address, uint8_t data) {//same as 7105 - CC25_CSN_off; - SPI_Write(address); - NOP(); - SPI_Write(data); - CC25_CSN_on; -} - -//-------------------------------------------- -static uint8_t CC2500_ReadReg(uint8_t address) -{ - uint8_t result; - CC25_CSN_off; - address |=0x80; //bit 7 =1 for reading - SPI_Write(address); - result = SPI_Read(); - CC25_CSN_on; - return(result); -} -//------------------------ -void CC2500_Strobe(uint8_t address) +void CC2500_SetTxRxMode(uint8_t mode) { - CC25_CSN_off; - SPI_Write(address); - CC25_CSN_on; + if(mode == TX_EN) + {//from deviation firmware + CC2500_WriteReg(CC2500_02_IOCFG0, 0x2F | 0x40); + CC2500_WriteReg(CC2500_00_IOCFG2, 0x2F); + } + else + if (mode == RX_EN) + { + CC2500_WriteReg(CC2500_02_IOCFG0, 0x2F); + CC2500_WriteReg(CC2500_00_IOCFG2, 0x2F | 0x40); + } + else + { + CC2500_WriteReg(CC2500_02_IOCFG0, 0x2F); + CC2500_WriteReg(CC2500_00_IOCFG2, 0x2F); + } } + //------------------------ /*static void cc2500_resetChip(void) { @@ -132,22 +153,3 @@ void CC2500_SetPower() } } -void CC2500_SetTxRxMode(uint8_t mode) -{ - if(mode == TX_EN) - {//from deviation firmware - CC2500_WriteReg(CC2500_02_IOCFG0, 0x2F | 0x40); - CC2500_WriteReg(CC2500_00_IOCFG2, 0x2F); - } - else - if (mode == RX_EN) - { - CC2500_WriteReg(CC2500_02_IOCFG0, 0x2F); - CC2500_WriteReg(CC2500_00_IOCFG2, 0x2F | 0x40); - } - else - { - CC2500_WriteReg(CC2500_02_IOCFG0, 0x2F); - CC2500_WriteReg(CC2500_00_IOCFG2, 0x2F); - } -} diff --git a/Multiprotocol/SFHSS_cc2500.ino b/Multiprotocol/SFHSS_cc2500.ino index b0cb911..f16ba20 100644 --- a/Multiprotocol/SFHSS_cc2500.ino +++ b/Multiprotocol/SFHSS_cc2500.ino @@ -101,7 +101,7 @@ static void __attribute__((unused)) SFHSS_tune_chan_fast() CC2500_Strobe(CC2500_SIDLE); CC2500_WriteReg(CC2500_0A_CHANNR, rf_ch_num*6+16); CC2500_WriteRegisterMulti(CC2500_23_FSCAL3, calData[rf_ch_num], 3); - delayMicroseconds(100); //6); + delayMicroseconds(6); } #ifdef SFHSS_USE_TUNE_FREQ From 7c127acf17b132dea8c762e777df55365629dd06 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 17 Aug 2016 13:44:20 +0200 Subject: [PATCH 136/293] Another SFHSS trial... --- Multiprotocol/CYRF6936_SPI.ino | 3 ++- Multiprotocol/SFHSS_cc2500.ino | 9 +++++---- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/Multiprotocol/CYRF6936_SPI.ino b/Multiprotocol/CYRF6936_SPI.ino index 3699e9e..f381990 100644 --- a/Multiprotocol/CYRF6936_SPI.ino +++ b/Multiprotocol/CYRF6936_SPI.ino @@ -128,9 +128,10 @@ void CYRF_SetPower(uint8_t val) power=IS_POWER_FLAG_on?CYRF_HIGH_POWER:CYRF_LOW_POWER; if(IS_RANGE_FLAG_on) power=CYRF_RANGE_POWER; + power|=val; if(prev_power != power) { - CYRF_WriteRegister(CYRF_03_TX_CFG, val | power); + CYRF_WriteRegister(CYRF_03_TX_CFG,power); prev_power=power; } } diff --git a/Multiprotocol/SFHSS_cc2500.ino b/Multiprotocol/SFHSS_cc2500.ino index f16ba20..8c1eba2 100644 --- a/Multiprotocol/SFHSS_cc2500.ino +++ b/Multiprotocol/SFHSS_cc2500.ino @@ -82,8 +82,8 @@ static void __attribute__((unused)) SFHSS_rf_init() for (uint8_t i = 0; i < 39; ++i) CC2500_WriteReg(i, pgm_read_byte_near(&SFHSS_init_values[i])); - prev_option = 0; - //CC2500_WriteReg(CC2500_0C_FSCTRL0, option); + prev_option = option; + CC2500_WriteReg(CC2500_0C_FSCTRL0, option); CC2500_SetTxRxMode(TX_EN); CC2500_SetPower(); @@ -130,9 +130,10 @@ static void __attribute__((unused)) SFHSS_calc_next_chan() } // Channel values are 10-bit values between 86 and 906, 496 is the middle. +// Values grow down and to the right, so we just revert every channel. static uint16_t __attribute__((unused)) SFHSS_convert_channel(uint8_t num) { - return (uint16_t) (map(limit_channel_100(num),PPM_MIN_100,PPM_MAX_100,86,906)); + return (uint16_t) (map(limit_channel_100(num),PPM_MIN_100,PPM_MAX_100,906,86)); } static void __attribute__((unused)) SFHSS_build_data_packet() @@ -145,7 +146,7 @@ static void __attribute__((unused)) SFHSS_build_data_packet() uint16_t ch3 = SFHSS_convert_channel(CH_AETR[ch_offset+2]); uint16_t ch4 = SFHSS_convert_channel(CH_AETR[ch_offset+3]); - packet[0] = 0x81; // can be 80, 81, 81 for Orange, only 81 for XK + packet[0] = 0x81; // can be 80 or 81 for Orange, only 81 for XK packet[1] = rx_tx_addr[0]; packet[2] = rx_tx_addr[1]; packet[3] = 0; From 7d37236d78d3a72bceca934bdaec5cc5dd47f8fb Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 17 Aug 2016 14:28:25 +0200 Subject: [PATCH 137/293] SFHSS again --- Multiprotocol/SFHSS_cc2500.ino | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/Multiprotocol/SFHSS_cc2500.ino b/Multiprotocol/SFHSS_cc2500.ino index 8c1eba2..6f6bdb4 100644 --- a/Multiprotocol/SFHSS_cc2500.ino +++ b/Multiprotocol/SFHSS_cc2500.ino @@ -114,6 +114,7 @@ static void __attribute__((unused)) SFHSS_tune_freq() { CC2500_WriteReg(CC2500_0C_FSCTRL0, option); CC2500_WriteReg(CC2500_0F_FREQ0, SFHSS_FREQ0_VAL + SFHSS_COARSE); prev_option = option ; + phase = SFHSS_START; // Restart the tune process if option is changed } } #endif @@ -163,7 +164,6 @@ static void __attribute__((unused)) SFHSS_build_data_packet() static void __attribute__((unused)) SFHSS_send_packet() { - SFHSS_tune_chan_fast(); CC2500_WriteData(packet, SFHSS_PACKET_LEN); } @@ -200,11 +200,12 @@ uint16_t ReadSFHSS() phase = SFHSS_TUNE; return 2000; case SFHSS_TUNE: + phase = SFHSS_DATA1; #ifdef SFHSS_USE_TUNE_FREQ SFHSS_tune_freq(); #endif + SFHSS_tune_chan_fast(); CC2500_SetPower(); - phase = SFHSS_DATA1; return 3150; /* case SFHSS_DATA1: From cd6d10e428953bdd478a7bfd3e10d35ed653b582 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 17 Aug 2016 15:50:59 +0200 Subject: [PATCH 138/293] SFHSS finally fixed --- Multiprotocol/SFHSS_cc2500.ino | 40 +++++----------------------------- 1 file changed, 6 insertions(+), 34 deletions(-) diff --git a/Multiprotocol/SFHSS_cc2500.ino b/Multiprotocol/SFHSS_cc2500.ino index 6f6bdb4..9680825 100644 --- a/Multiprotocol/SFHSS_cc2500.ino +++ b/Multiprotocol/SFHSS_cc2500.ino @@ -18,7 +18,6 @@ #include "iface_cc2500.h" -#define SFHSS_USE_TUNE_FREQ #define SFHSS_COARSE 0 #define SFHSS_PACKET_LEN 13 @@ -29,8 +28,8 @@ uint8_t fhss_code; // 0-27 enum { SFHSS_START = 0x00, SFHSS_CAL = 0x01, - SFHSS_DATA1 = 0x02, // do not change - SFHSS_DATA2 = 0x0B, // do not change + SFHSS_DATA1 = 0x02, // do not change this value + SFHSS_DATA2 = 0x0B, // do not change this value SFHSS_TUNE = 0x0F }; @@ -78,7 +77,6 @@ static void __attribute__((unused)) SFHSS_rf_init() CC2500_Reset(); CC2500_Strobe(CC2500_SIDLE); - //CC2500_WriteRegisterMulti(CC2500_00_IOCFG2, init_values, sizeof(init_values)); for (uint8_t i = 0; i < 39; ++i) CC2500_WriteReg(i, pgm_read_byte_near(&SFHSS_init_values[i])); @@ -101,23 +99,18 @@ static void __attribute__((unused)) SFHSS_tune_chan_fast() CC2500_Strobe(CC2500_SIDLE); CC2500_WriteReg(CC2500_0A_CHANNR, rf_ch_num*6+16); CC2500_WriteRegisterMulti(CC2500_23_FSCAL3, calData[rf_ch_num], 3); - delayMicroseconds(6); } -#ifdef SFHSS_USE_TUNE_FREQ -static void __attribute__((unused)) SFHSS_tune_freq() { -// May be we'll need this tuning routine - some receivers are more sensitive to -// frequency impreciseness, and though CC2500 has a procedure to handle it it -// may not be applied in receivers, so we need to compensate for it on TX +static void __attribute__((unused)) SFHSS_tune_freq() +{ if ( prev_option != option ) { CC2500_WriteReg(CC2500_0C_FSCTRL0, option); CC2500_WriteReg(CC2500_0F_FREQ0, SFHSS_FREQ0_VAL + SFHSS_COARSE); prev_option = option ; - phase = SFHSS_START; // Restart the tune process if option is changed + phase = SFHSS_START; // Restart the tune process if option is changed to get good tuned values } } -#endif static void __attribute__((unused)) SFHSS_calc_next_chan() { @@ -201,31 +194,10 @@ uint16_t ReadSFHSS() return 2000; case SFHSS_TUNE: phase = SFHSS_DATA1; -#ifdef SFHSS_USE_TUNE_FREQ SFHSS_tune_freq(); -#endif SFHSS_tune_chan_fast(); CC2500_SetPower(); return 3150; - /* - case SFHSS_DATA1: - SFHSS_build_data_packet(); - SFHSS_send_packet(); - phase = SFHSS_DATA2; - return 1650; - case SFHSS_DATA2: - SFHSS_build_data_packet(); - SFHSS_send_packet(); - phase = SFHSS_CAL2; - return 500; - case SFHSS_CAL2: - SFHSS_tune_freq(); - // CC2500_SetPower(); - SFHSS_calc_next_chan(); - SFHSS_tune_chan(); - phase = SFHSS_DATA1; - return 4650; - */ } return 0; } @@ -262,7 +234,7 @@ static void __attribute__((unused)) SFHSS_get_tx_id() uint16_t initSFHSS() { - BIND_DONE; // No bind protocol + BIND_DONE; // Not a TX bind protocol SFHSS_get_tx_id(); fhss_code=rx_tx_addr[2]%28; // Initialize it to random 0-27 inclusive From 3189d8d43ebb5116f5ef32686a3c6130ae4716a7 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 18 Aug 2016 14:15:15 +0200 Subject: [PATCH 139/293] FQ777 --- Multiprotocol/CC2500_SPI.ino | 2 +- Multiprotocol/FQ777_nrf24l01.ino | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Multiprotocol/CC2500_SPI.ino b/Multiprotocol/CC2500_SPI.ino index 85a3cf4..2fcf4e7 100644 --- a/Multiprotocol/CC2500_SPI.ino +++ b/Multiprotocol/CC2500_SPI.ino @@ -117,7 +117,7 @@ void CC2500_SetTxRxMode(uint8_t mode) uint8_t CC2500_Reset() { CC2500_Strobe(CC2500_SRES); - delayMicroseconds(1000); + delay(1); CC2500_SetTxRxMode(TXRX_OFF); return CC2500_ReadReg(CC2500_0E_FREQ1) == 0xC4;//check if reset } diff --git a/Multiprotocol/FQ777_nrf24l01.ino b/Multiprotocol/FQ777_nrf24l01.ino index e2b23f4..f82085b 100644 --- a/Multiprotocol/FQ777_nrf24l01.ino +++ b/Multiprotocol/FQ777_nrf24l01.ino @@ -32,7 +32,7 @@ enum { }; const uint8_t ssv_xor[] = {0x80,0x44,0x64,0x75,0x6C,0x71,0x2A,0x36,0x7C,0xF1,0x6E,0x52,0x9,0x9D,0x1F,0x78,0x3F,0xE1,0xEE,0x16,0x6D,0xE8,0x73,0x9,0x15,0xD7,0x92,0xE7,0x3,0xBA}; -uint8_t FQ777_bind_addr [] = {0xe7,0xe7,0xe7,0xe7,0x67}; +const uint8_t FQ777_bind_addr [] = {0xe7,0xe7,0xe7,0xe7,0x67}; static void __attribute__((unused)) ssv_pack_dpl(uint8_t addr[], uint8_t pid, uint8_t* len, uint8_t* payload, uint8_t* packed_payload) { @@ -141,7 +141,7 @@ static void __attribute__((unused)) FQ777_send_packet(uint8_t bind) checksum += packet_ori[i]; packet_ori[7] = checksum; - //packet_count++; + packet_count++; } ssv_pack_dpl( (0 == bind) ? rx_tx_addr : FQ777_bind_addr, hopping_frequency_no, &packet_len, packet_ori, packet); From 4090f950984552814c84c943bedd096989ab7d15 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 18 Aug 2016 22:01:24 +0200 Subject: [PATCH 140/293] Update Protocols_Details.md --- Protocols_Details.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index 572fcd6..a3bdc2b 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -245,6 +245,7 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 A|E|T|R|FLIP|RTH|HEADLESS|EXPERT|CALIBRATE ##FQ777 +Model: FQ777-124 CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- From fc1429fae5a156ce168b31195ae9e184981d20c8 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sat, 20 Aug 2016 09:13:36 +0200 Subject: [PATCH 141/293] FQ777 fixed --- Multiprotocol/FQ777_nrf24l01.ino | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/Multiprotocol/FQ777_nrf24l01.ino b/Multiprotocol/FQ777_nrf24l01.ino index f82085b..c5e920b 100644 --- a/Multiprotocol/FQ777_nrf24l01.ino +++ b/Multiprotocol/FQ777_nrf24l01.ino @@ -102,7 +102,7 @@ static void __attribute__((unused)) FQ777_send_packet(uint8_t bind) packet_ori[4] = rx_tx_addr[0]; packet_ori[5] = rx_tx_addr[1]; packet_ori[6] = rx_tx_addr[2]; - packet_ori[7] = packet[4] + packet[5] + packet[6]; + packet_ori[7] = packet_ori[4] + packet_ori[5] + packet_ori[6]; } else { @@ -197,7 +197,6 @@ uint16_t initFQ777(void) BIND_IN_PROGRESS; // autobind protocol bind_counter = FQ777_BIND_COUNT; packet_count=0; - memset(packet,0,32); hopping_frequency[0] = 0x4D; hopping_frequency[1] = 0x43; hopping_frequency[2] = 0x27; From adaa89a9632b6b186c1fcba3936767dbb0482eac Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sun, 21 Aug 2016 17:54:12 +0200 Subject: [PATCH 142/293] ASSAN protocol, FQ777 compilation fix on older Arduino --- Multiprotocol/ASSAN_nrf24l01.ino | 174 ++++++++++++++++++++++++++++++ Multiprotocol/CYRF6936_SPI.ino | 20 ++-- Multiprotocol/FQ777_nrf24l01.ino | 2 +- Multiprotocol/Multiprotocol.h | 9 +- Multiprotocol/Multiprotocol.ino | 8 +- Multiprotocol/SHENQI_nrf24l01.ino | 15 +++ Multiprotocol/_Config.h | 3 + 7 files changed, 215 insertions(+), 16 deletions(-) create mode 100644 Multiprotocol/ASSAN_nrf24l01.ino diff --git a/Multiprotocol/ASSAN_nrf24l01.ino b/Multiprotocol/ASSAN_nrf24l01.ino new file mode 100644 index 0000000..d91d2bf --- /dev/null +++ b/Multiprotocol/ASSAN_nrf24l01.ino @@ -0,0 +1,174 @@ +/* + 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(ASSAN_NRF24L01_INO) + +#include "iface_nrf24l01.h" + +#define ASSAN_PACKET_SIZE 20 +#define ASSAN_RF_BIND_CHANNEL 0x03 +#define ASSAN_ADDRESS_LENGTH 4 + +enum { + ASSAN_BIND0=0, + ASSAN_BIND1, + ASSAN_BIND2, + ASSAN_DATA0, + ASSAN_DATA1, + ASSAN_DATA2, + ASSAN_DATA3, + ASSAN_DATA4, + ASSAN_DATA5 +}; + +void ASSAN_init() +{ + NRF24L01_Initialize(); + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x02); // 4 bytes rx/tx address + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, (uint8_t *)"\x80\x80\x80\xB8", ASSAN_ADDRESS_LENGTH); // Bind address + NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, (uint8_t *)"\x80\x80\x80\xB8", ASSAN_ADDRESS_LENGTH); // Bind address + 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_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only + NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, ASSAN_PACKET_SIZE); + NRF24L01_SetPower(); +} + +void ASSAN_send_packet() +{ + uint16_t temp; + for(uint8_t i=0;i<10;i++) + { + temp=Servo_data[i]<<3; + packet[2*i]=temp>>8; + packet[2*i+1]=temp; + } + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit + NRF24L01_FlushTx(); + NRF24L01_WritePayload(packet, ASSAN_PACKET_SIZE); +} + +uint16_t ASSAN_callback() +{ + switch (phase) + { + // Bind + case ASSAN_BIND0: + //Config RX @1M + NRF24L01_WriteReg(NRF24L01_05_RF_CH, ASSAN_RF_BIND_CHANNEL); + NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps + NRF24L01_SetTxRxMode(RX_EN); + phase++; + case ASSAN_BIND1: + //Wait for RX to send the frames + if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR)) + { //Something has been received + NRF24L01_ReadPayload(packet, ASSAN_PACKET_SIZE); + if(packet[19]==0x13) + { //Last packet received + phase++; + //Switch to TX + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_SetTxRxMode(TX_EN); + //Prepare packet + memset(packet,0x05,ASSAN_PACKET_SIZE-5); + packet[15]=0x99; + for(uint8_t i=0;i<4;i++) + packet[16+i]=packet[23-i]; + packet_count=0; + delay(260); + return 10000; // Wait 270ms in total... + } + } + return 1000; + case ASSAN_BIND2: + // Send 20 packets + packet_count++; + if(packet_count==20) + packet[15]=0x13; // different value for last packet + NRF24L01_WritePayload(packet, ASSAN_PACKET_SIZE); + if(packet_count==20) + { + phase++; + delay(2165); + } + return 22520; + // Normal operation + case ASSAN_DATA0: + // Bind Done + BIND_DONE; + NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250Kbps + NRF24L01_SetTxRxMode(TXRX_OFF); + NRF24L01_SetTxRxMode(TX_EN); + case ASSAN_DATA1: + case ASSAN_DATA4: + // Change ID and RF channel + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR,packet+20+4*hopping_frequency_no, ASSAN_ADDRESS_LENGTH); + NRF24L01_WriteReg(NRF24L01_05_RF_CH, hopping_frequency[hopping_frequency_no]); + hopping_frequency_no^=0x01; + NRF24L01_SetPower(); + phase=ASSAN_DATA2; + return 2000; + case ASSAN_DATA2: + case ASSAN_DATA3: + ASSAN_send_packet(); + phase++; // DATA 3 or 4 + return 5000; + } + return 0; +} + +static void __attribute__((unused)) ASSAN_initialize_txid() +{ +/* //Renaud TXID with Freq=36 and alternate freq 67 or 68 or 69 or 70 or 71 or 73 or 74 or 75 or 78 and may be more... + packet[23]=0x22; + packet[22]=0x37; + packet[21]=0xFA; + packet[20]=0x53; */ + // Using packet[20..23] to store the ID1 and packet[24..27] to store the ID2 + uint8_t freq=0; + for(uint8_t i=0;i<4;i++) + { + uint8_t temp=rx_tx_addr[0]; + packet[i+20]=temp; + packet[i+24]=temp+1; + freq+=temp; + } + + // Main frequency + freq=((freq%25)+2)<<1; + if(freq&0x02) freq|=0x01; + hopping_frequency[0]=freq; + // Alternate frequency + hopping_frequency[1]=freq*2-6; + hopping_frequency[1]+=analogRead(A6)%12; // Add some random to the second channel +} + +uint16_t initASSAN() +{ + ASSAN_initialize_txid(); + ASSAN_init(); + hopping_frequency_no = 0; + + if(IS_AUTOBIND_FLAG_on) + phase=ASSAN_BIND0; + else + phase=ASSAN_DATA0; + return 1000; +} + +#endif \ No newline at end of file diff --git a/Multiprotocol/CYRF6936_SPI.ino b/Multiprotocol/CYRF6936_SPI.ino index f381990..24a5f30 100644 --- a/Multiprotocol/CYRF6936_SPI.ino +++ b/Multiprotocol/CYRF6936_SPI.ino @@ -58,17 +58,17 @@ uint8_t CYRF_ReadRegister(uint8_t address) uint8_t CYRF_Reset() { - CYRF_WriteRegister(CYRF_1D_MODE_OVERRIDE, 0x01);//software reset - delayMicroseconds(200);// - // RS_HI; - // delayMicroseconds(100); - // RS_LO; - // delayMicroseconds(100); - CYRF_WriteRegister(CYRF_0C_XTAL_CTRL, 0xC0); //Enable XOUT as GPIO - CYRF_WriteRegister(CYRF_0D_IO_CFG, 0x04); //Enable PACTL as GPIO + CYRF_RST_HI; //Hardware reset + delayMicroseconds(100); + CYRF_RST_LO; + delayMicroseconds(100); +/* CYRF_WriteRegister(CYRF_1D_MODE_OVERRIDE, 0x01); //Software reset + delayMicroseconds(200); +*/ CYRF_WriteRegister(CYRF_0C_XTAL_CTRL, 0xC0); //Enable XOUT as GPIO + CYRF_WriteRegister(CYRF_0D_IO_CFG, 0x04); //Enable PACTL as GPIO CYRF_SetTxRxMode(TXRX_OFF); - //Verify the CYRD chip is responding - return (CYRF_ReadRegister(CYRF_10_FRAMING_CFG) == 0xa5);//return if reset + //Verify the CYRF chip is responding + return (CYRF_ReadRegister(CYRF_10_FRAMING_CFG) == 0xa5); } /* diff --git a/Multiprotocol/FQ777_nrf24l01.ino b/Multiprotocol/FQ777_nrf24l01.ino index c5e920b..369812f 100644 --- a/Multiprotocol/FQ777_nrf24l01.ino +++ b/Multiprotocol/FQ777_nrf24l01.ino @@ -32,7 +32,7 @@ enum { }; const uint8_t ssv_xor[] = {0x80,0x44,0x64,0x75,0x6C,0x71,0x2A,0x36,0x7C,0xF1,0x6E,0x52,0x9,0x9D,0x1F,0x78,0x3F,0xE1,0xEE,0x16,0x6D,0xE8,0x73,0x9,0x15,0xD7,0x92,0xE7,0x3,0xBA}; -const uint8_t FQ777_bind_addr [] = {0xe7,0xe7,0xe7,0xe7,0x67}; +uint8_t FQ777_bind_addr [] = {0xe7,0xe7,0xe7,0xe7,0x67}; static void __attribute__((unused)) ssv_pack_dpl(uint8_t addr[], uint8_t pid, uint8_t* len, uint8_t* payload, uint8_t* packed_payload) { diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index f9ffdbb..9ecfddf 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -51,7 +51,8 @@ enum PROTOCOLS MODE_FY326=20, // =>NRF24L01 MODE_SFHSS=21, // =>CC2500 MODE_J6PRO=22, // =>CYRF6936 - MODE_FQ777=23 // =>NRF24L01 + MODE_FQ777=23, // =>NRF24L01 + MODE_ASSAN=24 // =>NRF24L01 }; enum Flysky @@ -238,6 +239,8 @@ struct PPM_Parameters #else #define CYRF_CSN_on PORTB |= _BV(1) //D9 #define CYRF_CSN_off PORTB &= ~_BV(1) //D9 +#define CYRF_RST_HI PORTC|=_BV(5) //reset cyrf +#define CYRF_RST_LO PORTB &= ~_BV(5) // #endif // #ifdef XMEGA @@ -248,9 +251,6 @@ struct PPM_Parameters #define SDO_0 (PIND & (1< 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 882541a..c8c6170 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -584,6 +584,12 @@ static void protocol_init() next_callback=initFQ777(); remote_callback = FQ777_callback; break; +#endif +#if defined(ASSAN_NRF24L01_INO) + case MODE_ASSAN: + next_callback=initASSAN(); + remote_callback = ASSAN_callback; + break; #endif } @@ -674,7 +680,7 @@ static void module_reset() case MODE_J6PRO: CYRF_Reset(); break; - default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY, MODE_MT99XX, MODE_MJXQ, MODE_SHENQI, MODE_FY326, MODE_FQ777 + default: // MODE_HISKY, MODE_V2X2, MODE_YD717, MODE_KN, MODE_SYMAX, MODE_SLT, MODE_CX10, MODE_CG023, MODE_BAYANG, MODE_ESKY, MODE_MT99XX, MODE_MJXQ, MODE_SHENQI, MODE_FY326, MODE_FQ777, MODE_ASSAN NRF24L01_Reset(); break; } diff --git a/Multiprotocol/SHENQI_nrf24l01.ino b/Multiprotocol/SHENQI_nrf24l01.ino index c829f7e..293e30b 100644 --- a/Multiprotocol/SHENQI_nrf24l01.ino +++ b/Multiprotocol/SHENQI_nrf24l01.ino @@ -1,3 +1,18 @@ +/* + 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(SHENQI_NRF24L01_INO) #include "iface_nrf24l01.h" diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 449829c..52f8cc9 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -65,6 +65,7 @@ #define SHENQI_NRF24L01_INO #define FY326_NRF24L01_INO #define FQ777_NRF24L01_INO + #define ASSAN_NRF24L01_INO #endif /**************************/ @@ -185,6 +186,8 @@ const PPM_Parameters PPM_prot[15]= { NONE MODE_FQ777 NONE + MODE_ASSAN + NONE RX_Num value between 0 and 15 From 35b97c4f45a11b6941951cb0b59ff1a92b9426af Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sun, 21 Aug 2016 18:05:16 +0200 Subject: [PATCH 143/293] Fixed disable telemetry compilation issue --- Multiprotocol/Multiprotocol.ino | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index c8c6170..d3a2b9f 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -779,9 +779,11 @@ static void Mprotocol_serial_init() #ifdef DEBUG_TX TX_SET_OUTPUT; #else + #if defined(TELEMETRY) initTXSerial( SPEED_100K ) ; -#endif -#endif + #endif //TELEMETRY +#endif //DEBUG_TX +#endif //XMEGA } #if defined(TELEMETRY) From b2579538fab8bc4f5e95fc792217022aebbacc5f Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sun, 21 Aug 2016 19:23:41 +0200 Subject: [PATCH 144/293] Fix Cyrf reset... --- Multiprotocol/Multiprotocol.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 9ecfddf..b54affa 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -239,8 +239,8 @@ struct PPM_Parameters #else #define CYRF_CSN_on PORTB |= _BV(1) //D9 #define CYRF_CSN_off PORTB &= ~_BV(1) //D9 -#define CYRF_RST_HI PORTC|=_BV(5) //reset cyrf -#define CYRF_RST_LO PORTB &= ~_BV(5) // +#define CYRF_RST_HI PORTC|= _BV(5) //reset cyrf +#define CYRF_RST_LO PORTC&=~_BV(5) // #endif // #ifdef XMEGA @@ -424,7 +424,7 @@ enum CYRF_POWER #define CYRF_HIGH_POWER CYRF_POWER_7 #define CYRF_LOW_POWER CYRF_POWER_3 #define CYRF_RANGE_POWER CYRF_POWER_1 // 1/30 of the full power distance -#define CYRF_BIND_POWER CYRF_POWER_0 +#define CYRF_BIND_POWER CYRF_POWER_1 enum TXRX_State { TXRX_OFF, From 195f91854399066492f0a480657a04b68af81a9a Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 22 Aug 2016 18:17:14 +0200 Subject: [PATCH 145/293] DSM2 bind improvement? --- Multiprotocol/A7105_SPI.ino | 2 +- Multiprotocol/ASSAN_nrf24l01.ino | 6 ++-- Multiprotocol/CC2500_SPI.ino | 2 +- Multiprotocol/CYRF6936_SPI.ino | 8 ++++-- Multiprotocol/DSM2_cyrf6936.ino | 6 ++-- Multiprotocol/Devo_cyrf6936.ino | 4 +-- Multiprotocol/MultiOrange.cpp.xmega | 4 +-- Multiprotocol/Multiprotocol.ino | 43 ++++++++++------------------- 8 files changed, 31 insertions(+), 44 deletions(-) diff --git a/Multiprotocol/A7105_SPI.ino b/Multiprotocol/A7105_SPI.ino index 6582876..af4cbcb 100644 --- a/Multiprotocol/A7105_SPI.ino +++ b/Multiprotocol/A7105_SPI.ino @@ -103,7 +103,7 @@ uint8_t A7105_Reset() uint8_t result; A7105_WriteReg(0x00, 0x00); - delayMicroseconds(1000); + delayMilliseconds(1); A7105_SetTxRxMode(TXRX_OFF); //Set both GPIO as output and low result=A7105_ReadReg(0x10) == 0x9E; //check if is reset. A7105_Strobe(A7105_STANDBY); diff --git a/Multiprotocol/ASSAN_nrf24l01.ino b/Multiprotocol/ASSAN_nrf24l01.ino index d91d2bf..4bbf348 100644 --- a/Multiprotocol/ASSAN_nrf24l01.ino +++ b/Multiprotocol/ASSAN_nrf24l01.ino @@ -90,7 +90,7 @@ uint16_t ASSAN_callback() for(uint8_t i=0;i<4;i++) packet[16+i]=packet[23-i]; packet_count=0; - delay(260); + delayMilliseconds(260); return 10000; // Wait 270ms in total... } } @@ -104,7 +104,7 @@ uint16_t ASSAN_callback() if(packet_count==20) { phase++; - delay(2165); + delayMilliseconds(2165); } return 22520; // Normal operation @@ -134,7 +134,7 @@ uint16_t ASSAN_callback() static void __attribute__((unused)) ASSAN_initialize_txid() { -/* //Renaud TXID with Freq=36 and alternate freq 67 or 68 or 69 or 70 or 71 or 73 or 74 or 75 or 78 and may be more... +/* //Renaud TXID with Freq=36 and alternate Freq 67 or 68 or 69 or 70 or 71 or 73 or 74 or 75 or 78 and may be more... packet[23]=0x22; packet[22]=0x37; packet[21]=0xFA; diff --git a/Multiprotocol/CC2500_SPI.ino b/Multiprotocol/CC2500_SPI.ino index 2fcf4e7..4628b03 100644 --- a/Multiprotocol/CC2500_SPI.ino +++ b/Multiprotocol/CC2500_SPI.ino @@ -117,7 +117,7 @@ void CC2500_SetTxRxMode(uint8_t mode) uint8_t CC2500_Reset() { CC2500_Strobe(CC2500_SRES); - delay(1); + delayMilliseconds(1); CC2500_SetTxRxMode(TXRX_OFF); return CC2500_ReadReg(CC2500_0E_FREQ1) == 0xC4;//check if reset } diff --git a/Multiprotocol/CYRF6936_SPI.ino b/Multiprotocol/CYRF6936_SPI.ino index 24a5f30..dcf06e1 100644 --- a/Multiprotocol/CYRF6936_SPI.ino +++ b/Multiprotocol/CYRF6936_SPI.ino @@ -58,13 +58,15 @@ uint8_t CYRF_ReadRegister(uint8_t address) uint8_t CYRF_Reset() { +#ifdef CYRF_RST_HI CYRF_RST_HI; //Hardware reset delayMicroseconds(100); CYRF_RST_LO; delayMicroseconds(100); -/* CYRF_WriteRegister(CYRF_1D_MODE_OVERRIDE, 0x01); //Software reset +#endif + CYRF_WriteRegister(CYRF_1D_MODE_OVERRIDE, 0x01); //Software reset delayMicroseconds(200); -*/ CYRF_WriteRegister(CYRF_0C_XTAL_CTRL, 0xC0); //Enable XOUT as GPIO + CYRF_WriteRegister(CYRF_0C_XTAL_CTRL, 0xC0); //Enable XOUT as GPIO CYRF_WriteRegister(CYRF_0D_IO_CFG, 0x04); //Enable PACTL as GPIO CYRF_SetTxRxMode(TXRX_OFF); //Verify the CYRF chip is responding @@ -231,7 +233,7 @@ void CYRF_FindBestChannels(uint8_t *channels, uint8_t len, uint8_t minspace, uin CYRF_ConfigCRCSeed(0x0000); CYRF_SetTxRxMode(RX_EN); //Wait for pre-amp to switch from send to receive - delayMicroseconds(1000); + delayMilliseconds(1); for(i = 0; i < NUM_FREQ; i++) { CYRF_ConfigRFChannel(i); diff --git a/Multiprotocol/DSM2_cyrf6936.ino b/Multiprotocol/DSM2_cyrf6936.ino index 429dd60..9ab5ead 100644 --- a/Multiprotocol/DSM2_cyrf6936.ino +++ b/Multiprotocol/DSM2_cyrf6936.ino @@ -213,10 +213,8 @@ static void __attribute__((unused)) build_data_packet(uint8_t upper)// for (i = 0; i < 7; i++) { uint8_t idx = ch_map[upper * 7 + i];//1,5,2,3,0,4 - uint16_t value; - if (idx == 0xff) - value = 0xffff; - else + uint16_t value = 0xffff;; + if (idx != 0xff) { if (binding) { // Failsafe position during binding diff --git a/Multiprotocol/Devo_cyrf6936.ino b/Multiprotocol/Devo_cyrf6936.ino index e7b446a..eee0231 100644 --- a/Multiprotocol/Devo_cyrf6936.ino +++ b/Multiprotocol/Devo_cyrf6936.ino @@ -385,9 +385,9 @@ Model_fixed_id=0; eeprom_write_block((const void*)0,(void*)40,4); while(1){ LED_ON; -delay(100); +delayMilliseconds(100); LED_OFF; -delay(100); +delayMilliseconds(100); } } else{ diff --git a/Multiprotocol/MultiOrange.cpp.xmega b/Multiprotocol/MultiOrange.cpp.xmega index eed1110..2a331fa 100644 --- a/Multiprotocol/MultiOrange.cpp.xmega +++ b/Multiprotocol/MultiOrange.cpp.xmega @@ -200,7 +200,7 @@ unsigned long micros() return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond()); } -void delay(unsigned long ms) +void delayMilliseconds(unsigned long ms) { uint16_t start = (uint16_t)micros(); @@ -419,7 +419,7 @@ int analogRead(uint8_t pin) #endif // without a delay, we seem to read from the wrong channel - //delay(1); + //delayMilliseconds(1); #if defined(ADCSRA) && defined(ADCL) // start the conversion diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index d3a2b9f..33a85a2 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -199,7 +199,7 @@ void setup() memcpy((void *)PPM_data,Servo_data, sizeof(Servo_data)); //Wait for every component to start - delay(100); + delayMilliseconds(100); // Read status of bind button #ifdef XMEGA @@ -595,8 +595,9 @@ static void protocol_init() if(next_callback>32000) { // next_callback should not be more than 32767 so we will wait here... - delayMicroseconds(next_callback-2000); - next_callback=2000; + uint16_t temp=next_callback>>10-2; + delayMilliseconds(temp); + next_callback-=temp<<10; // between 2-3ms left at this stage } cli(); // disable global int #ifdef XMEGA @@ -765,7 +766,6 @@ static void Mprotocol_serial_init() USARTC0.CTRLC = 0x2B ; USARTC0.DATA ; #else - #include UBRR0H = UBRRH_VALUE; UBRR0L = UBRRL_VALUE; @@ -844,8 +844,10 @@ void SPI_Write(uint8_t command) else SDI_off; SCK_on; + NOP(); command = command << 1; SCK_off; + NOP(); } while(--n) ; SDI_on; @@ -853,8 +855,7 @@ void SPI_Write(uint8_t command) uint8_t SPI_Read(void) { - uint8_t result; - uint8_t i; + uint8_t result=0,i; for(i=0;i<8;i++) { result=result<<1; @@ -863,6 +864,7 @@ uint8_t SPI_Read(void) SCK_on; NOP(); SCK_off; + NOP(); } return result; } @@ -939,7 +941,7 @@ uint32_t millis() return TotalMillis ; } -void delay(unsigned long ms) +void delayMilliseconds(unsigned long ms) { uint16_t start = (uint16_t)micros(); uint16_t lms = ms ; @@ -952,29 +954,15 @@ void delay(unsigned long ms) } } -/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */ +/* Important notes: + - Max value is 16000µs + - delay is not accurate due to interrupts happening */ void delayMicroseconds(unsigned int us) { - // calling avrlib's delay_us() function with low values (e.g. 1 or - // 2 microseconds) gives delays longer than desired. - //delay_us(us); - - // for the 16 MHz clock on most Arduino boards - - // for a one-microsecond delay, simply return. the overhead - // of the function call yields a delay of approximately 1 1/8 us. if (--us == 0) return; - - // the following loop takes a quarter of a microsecond (4 cycles) - // per iteration, so execute it four times for each microsecond of - // delay requested. - us <<= 2; - - // account for the time taken in the preceeding commands. - us -= 2; - - // busy wait + us <<= 2; // * 4 + us -= 2; // - 2 __asm__ __volatile__ ( "1: sbiw %0,1" "\n\t" // 2 cycles "brne 1b" : "=w" (us) : "0" (us) // 2 cycles @@ -983,8 +971,7 @@ void delayMicroseconds(unsigned int us) void init() { - // this needs to be called before setup() or some functions won't - // work there + // this needs to be called before setup() or some functions won't work there sei(); } From 392f7098bccb4b4e6c1cb4026bad59ad206d7b0e Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 23 Aug 2016 12:56:04 +0200 Subject: [PATCH 146/293] ASSAN protocol addition --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d6a44f0..05c85e0 100644 --- a/README.md +++ b/README.md @@ -209,7 +209,6 @@ CG023| |YD829 |H8_3D Bayang| -FrskyX||CC2500 ESky| MT99XX| |MT @@ -224,6 +223,7 @@ MJXQ| Shenqi| FY326| FQ777| +ASSAN| Note: - The dial should be set to 0 for serial. Which means all protocol selection pins should be left unconnected. From c78e8d83589dcdcd80998225c5d2bdfc087ff6b0 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 23 Aug 2016 13:06:14 +0200 Subject: [PATCH 147/293] ASSAN protocol and FRSKY/FRSKYX/SFHSS option --- Protocols_Details.md | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index a3bdc2b..ac18a65 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -51,7 +51,7 @@ Extended limits supported Telemetry enabled for A0, A1, RSSI, TSSI and Hub -Option=fine frequency tuning, usually 0 or -41 based on the manufacturer boards +Option=fine frequency tuning. This value is dependant of the board. To determine the option value, find the two limits where the Rx loses connection then set the option value to half way between them. CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- @@ -64,7 +64,7 @@ Extended limits supported Telemetry enabled for A1 (RxBatt), A2, RSSI, TSSI and Hub -Option=fine frequency tuning, usually 0 or -41 based on the manufacturer boards +Option=fine frequency tuning. This value is dependant of the board. To determine the option value, find the two limits where the Rx loses connection then set the option value to half way between them. ###Sub_protocol CH_16 CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16 @@ -79,7 +79,7 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ##SFHSS Models: Futaba RXs and XK models. -Option=fine frequency tuning, usually 0 or -41 based on the manufacturer boards +Option=fine frequency tuning. This value is dependant of the board. To determine the option value, find the two limits where the Rx loses connection then set the option value to half way between them. CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- @@ -135,6 +135,15 @@ A|E|T|R|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 *** #NRF24L01 RF Module +##ASSAN +Extended limits supported + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10 +---|---|---|---|---|---|---|---|---|--- +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10 + +The transmitter must be close to the receiver while binding. + ##BAYANG Models: EAchine H8(C) mini, BayangToys X6/X7/X9, JJRC JJ850, Floureon H101 ... From af8a0ea9c0b56aa908dd206333e81160d42c8a40 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 23 Aug 2016 13:07:37 +0200 Subject: [PATCH 148/293] Update Protocols_Details.md --- Protocols_Details.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index ac18a65..2c3fd8b 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -51,7 +51,7 @@ Extended limits supported Telemetry enabled for A0, A1, RSSI, TSSI and Hub -Option=fine frequency tuning. This value is dependant of the board. To determine the option value, find the two limits where the Rx loses connection then set the option value to half way between them. +Option=fine frequency tuning. This value is different for each board. To determine the option value, find the two limits where the RX loses connection then set the option value to half way between them. CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- @@ -64,7 +64,7 @@ Extended limits supported Telemetry enabled for A1 (RxBatt), A2, RSSI, TSSI and Hub -Option=fine frequency tuning. This value is dependant of the board. To determine the option value, find the two limits where the Rx loses connection then set the option value to half way between them. +Option=fine frequency tuning. This value is different for each board. To determine the option value, find the two limits where the RX loses connection then set the option value to half way between them. ###Sub_protocol CH_16 CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16 @@ -79,7 +79,7 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ##SFHSS Models: Futaba RXs and XK models. -Option=fine frequency tuning. This value is dependant of the board. To determine the option value, find the two limits where the Rx loses connection then set the option value to half way between them. +Option=fine frequency tuning. This value is different for each board. To determine the option value, find the two limits where the RX loses connection then set the option value to half way between them. CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- From 988d28f2fdfab42c599438fef94ae3adde411c2e Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 23 Aug 2016 13:39:10 +0200 Subject: [PATCH 149/293] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 05c85e0..72baff4 100644 --- a/README.md +++ b/README.md @@ -350,9 +350,9 @@ To upload the latest provided hex file under [Release](https://github.com/pascal ###Set fuses Use a tool like [AVR Burn-O-Mat](http://avr8-burn-o-mat.aaabbb.de/) to set the fuses of the Atmega328 to: -- Low Fuse 0xFF -- High Fuse 0xD2 - Extended Fuse 0x05 (or 0xFD which is the same) +- High Fuse 0xD2 +- Low Fuse 0xFF This will make sure your ATMEGA328 is well configured and the global TX ID is not erased at each updates. From 061c97caca66fc8293b9bdf0bd7f7214f767df5e Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 24 Aug 2016 14:52:47 +0200 Subject: [PATCH 150/293] New _Config.h file, MJXQ fix, 16 bit regs --- Multiprotocol/A7105_SPI.ino | 5 +- Multiprotocol/ASSAN_nrf24l01.ino | 6 +- Multiprotocol/DSM2_cyrf6936.ino | 45 +++-- Multiprotocol/Devo_cyrf6936.ino | 2 +- Multiprotocol/FrSkyX_cc2500.ino | 2 +- Multiprotocol/Hisky_nrf24l01.ino | 2 +- Multiprotocol/MJXQ_nrf24l01.ino | 35 ++-- Multiprotocol/Multiprotocol.h | 287 +++++++++++++++---------------- Multiprotocol/Multiprotocol.ino | 69 ++++---- Multiprotocol/SFHSS_cc2500.ino | 2 +- Multiprotocol/TX_Def.h | 255 +++++++++++++++++++++++++++ Multiprotocol/Telemetry.ino | 3 +- Multiprotocol/_Config.h | 220 ++++++++--------------- 13 files changed, 563 insertions(+), 370 deletions(-) create mode 100644 Multiprotocol/TX_Def.h diff --git a/Multiprotocol/A7105_SPI.ino b/Multiprotocol/A7105_SPI.ino index af4cbcb..30c022b 100644 --- a/Multiprotocol/A7105_SPI.ino +++ b/Multiprotocol/A7105_SPI.ino @@ -62,10 +62,9 @@ uint8_t A7105_ReadReg(uint8_t address) { uint8_t A7105_Read(void) { - uint8_t result; - uint8_t i; + uint8_t result=0; SDI_SET_INPUT; - for(i=0;i<8;i++) + for(uint8_t i=0;i<8;i++) { result=result<<1; if(SDI_1) ///if SDIO =1 diff --git a/Multiprotocol/ASSAN_nrf24l01.ino b/Multiprotocol/ASSAN_nrf24l01.ino index 4bbf348..3356e2f 100644 --- a/Multiprotocol/ASSAN_nrf24l01.ino +++ b/Multiprotocol/ASSAN_nrf24l01.ino @@ -74,17 +74,17 @@ uint16_t ASSAN_callback() NRF24L01_SetTxRxMode(RX_EN); phase++; case ASSAN_BIND1: - //Wait for RX to send the frames + //Wait for receiver to send the frames if( NRF24L01_ReadReg(NRF24L01_07_STATUS) & BV(NRF24L01_07_RX_DR)) { //Something has been received NRF24L01_ReadPayload(packet, ASSAN_PACKET_SIZE); if(packet[19]==0x13) - { //Last packet received + { //Last frame received phase++; //Switch to TX NRF24L01_SetTxRxMode(TXRX_OFF); NRF24L01_SetTxRxMode(TX_EN); - //Prepare packet + //Prepare bind packet memset(packet,0x05,ASSAN_PACKET_SIZE-5); packet[15]=0x99; for(uint8_t i=0;i<4;i++) diff --git a/Multiprotocol/DSM2_cyrf6936.ino b/Multiprotocol/DSM2_cyrf6936.ino index 9ab5ead..85f8029 100644 --- a/Multiprotocol/DSM2_cyrf6936.ino +++ b/Multiprotocol/DSM2_cyrf6936.ino @@ -108,7 +108,6 @@ static void __attribute__((unused)) read_code(uint8_t *buf, uint8_t row, uint8_t // uint8_t sop_col; uint8_t data_col; -uint16_t cyrf_state; uint8_t binding; static void __attribute__((unused)) build_bind_packet() @@ -146,7 +145,7 @@ static void __attribute__((unused)) build_bind_packet() static uint8_t __attribute__((unused)) PROTOCOL_SticksMoved(uint8_t init) { -#define STICK_MOVEMENT 15*(PPM_MAX-PPM_MIN)/100 // defines when the bind dialog should be interrupted (stick movement STICK_MOVEMENT %) +#define STICK_MOVEMENT 15*(servo_max_125-servo_min_125)/100 // defines when the bind dialog should be interrupted (stick movement STICK_MOVEMENT %) static uint16_t ele_start, ail_start; uint16_t ele = Servo_data[ELEVATOR];//CHAN_ReadInput(MIXER_MapChannel(INP_ELEVATOR)); uint16_t ail = Servo_data[AILERON];//CHAN_ReadInput(MIXER_MapChannel(INP_AILERON)); @@ -263,7 +262,7 @@ static void __attribute__((unused)) build_data_packet(uint8_t upper)// value=Servo_data[AUX8]; break; } - value=map(value,PPM_MIN,PPM_MAX,0,max-1); + value=map(value,servo_min_125,servo_max_125,0,max-1); } value |= (upper && i == 0 ? 0x8000 : 0) | (idx << bits); } @@ -416,12 +415,12 @@ uint16_t ReadDsm2() #define DSM_READ_DELAY 600 // Time before write to check read state, and switch channels. Was 400 but 500 seems what the 328p needs to read a packet uint16_t start; - switch(cyrf_state) + switch(state) { default: //Binding - cyrf_state++; - if(cyrf_state & 1) + state++; + if(state & 1) { //Send packet on even states //Note state has already incremented, so this is actually 'even' state @@ -441,17 +440,17 @@ uint16_t ReadDsm2() cyrf_configdata(); CYRF_SetTxRxMode(TX_EN); hopping_frequency_no = 0; - cyrf_state = DSM2_CH1_WRITE_A; // in fact cyrf_state++ + state = DSM2_CH1_WRITE_A; // in fact state++ set_sop_data_crc(); return 10000; case DSM2_CH1_WRITE_A: case DSM2_CH1_WRITE_B: case DSM2_CH2_WRITE_A: case DSM2_CH2_WRITE_B: - build_data_packet(cyrf_state == DSM2_CH1_WRITE_B);// build lower or upper channels + build_data_packet(state == DSM2_CH1_WRITE_B);// build lower or upper channels CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS); // clear IRQ flags CYRF_WriteDataPacket(packet); - cyrf_state++; // change from WRITE to CHECK mode + state++; // change from WRITE to CHECK mode return DSM_WRITE_DELAY; case DSM2_CH1_CHECK_A: case DSM2_CH1_CHECK_B: @@ -460,7 +459,7 @@ uint16_t ReadDsm2() if(CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02) break; set_sop_data_crc(); - cyrf_state++; // change from CH1_CHECK to CH2_WRITE + state++; // change from CH1_CHECK to CH2_WRITE return DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY; case DSM2_CH2_CHECK_A: case DSM2_CH2_CHECK_B: @@ -468,10 +467,10 @@ uint16_t ReadDsm2() while ((uint16_t)micros()-start < 500) // Wait max 500µs if(CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02) break; - if (cyrf_state == DSM2_CH2_CHECK_A) + if (state == DSM2_CH2_CHECK_A) CYRF_SetPower(0x28); //Keep transmit power in sync #if defined DSM_TELEMETRY - cyrf_state++; // change from CH2_CHECK to CH2_READ + state++; // change from CH2_CHECK to CH2_READ if(option<=3 || option>7) { // disable telemetry for option between 4 and 7 ie 4,5,6,7 channels @11ms since it does not work... CYRF_SetTxRxMode(RX_EN); //Receive mode @@ -494,7 +493,7 @@ uint16_t ReadDsm2() pkt[0]=CYRF_ReadRegister(CYRF_13_RSSI)&0x1F; // store RSSI of the received telemetry signal telemetry_link=1; } - if (cyrf_state == DSM2_CH2_READ_A && option <= 3) // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms + if (state == DSM2_CH2_READ_A && option <= 3) // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms { //Force end read state CYRF_WriteRegister(CYRF_0F_XACT_CFG, (CYRF_ReadRegister(CYRF_0F_XACT_CFG) | 0x20)); // Force end state @@ -502,35 +501,35 @@ uint16_t ReadDsm2() while ((uint16_t)micros()-start < 100) // Wait max 100 µs if((CYRF_ReadRegister(CYRF_0F_XACT_CFG) & 0x20) == 0) break; - cyrf_state = DSM2_CH2_READ_B; + state = DSM2_CH2_READ_B; CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive return 11000; } - if (cyrf_state == DSM2_CH2_READ_A && option>7) - cyrf_state = DSM2_CH1_WRITE_B; //Transmit upper + if (state == DSM2_CH2_READ_A && option>7) + state = DSM2_CH1_WRITE_B; //Transmit upper else - cyrf_state = DSM2_CH1_WRITE_A; //Force 11ms if option>3 ie 4,5,6,7 channels @11ms + state = DSM2_CH1_WRITE_A; //Force 11ms if option>3 ie 4,5,6,7 channels @11ms CYRF_SetTxRxMode(TX_EN); //Write mode set_sop_data_crc(); return DSM_READ_DELAY; #else // No telemetry set_sop_data_crc(); - if (cyrf_state == DSM2_CH2_CHECK_A) + if (state == DSM2_CH2_CHECK_A) { if(option < 8) { - cyrf_state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper) + state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper) if(option>3) return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ; // force 11ms if option>3 ie 4,5,6,7 channels @11ms else return 22000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ; // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms } else - cyrf_state = DSM2_CH1_WRITE_B; // change from CH2_CHECK_A to CH1_WRITE_A (to transmit upper) + state = DSM2_CH1_WRITE_B; // change from CH2_CHECK_A to CH1_WRITE_A (to transmit upper) } else - cyrf_state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_B to CH1_WRITE_A (upper already transmitted so transmit lower) + state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_B to CH1_WRITE_A (upper already transmitted so transmit lower) return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY; #endif } @@ -581,14 +580,14 @@ uint16_t initDsm2() // if(IS_AUTOBIND_FLAG_on) { - cyrf_state = DSM2_BIND; + state = DSM2_BIND; PROTOCOL_SticksMoved(1); //Initialize Stick position initialize_bind_state(); binding = 1; } else { - cyrf_state = DSM2_CHANSEL;// + state = DSM2_CHANSEL;// binding = 0; } return 10000; diff --git a/Multiprotocol/Devo_cyrf6936.ino b/Multiprotocol/Devo_cyrf6936.ino index eee0231..e535095 100644 --- a/Multiprotocol/Devo_cyrf6936.ino +++ b/Multiprotocol/Devo_cyrf6936.ino @@ -148,7 +148,7 @@ static void __attribute__((unused)) build_data_pkt() for (i = 0; i < 4; i++) { // - int16_t value= map(Servo_data[ch_idx * 4 + i],PPM_MIN,PPM_MAX,-1600,1600);//range -1600...+1600 + int16_t value= map(Servo_data[ch_idx * 4 + i],servo_min_125,servo_max_125,-1600,1600);//range -1600...+1600 //s32 value = (s32)Channels[ch_idx * 4 + i] * 0x640 / CHAN_MAX_VALUE;//10000 if(value < 0) { diff --git a/Multiprotocol/FrSkyX_cc2500.ino b/Multiprotocol/FrSkyX_cc2500.ino index d631821..452f23f 100644 --- a/Multiprotocol/FrSkyX_cc2500.ino +++ b/Multiprotocol/FrSkyX_cc2500.ino @@ -145,7 +145,7 @@ static uint16_t __attribute__((unused)) crc_x(uint8_t *data, uint8_t len) static uint16_t __attribute__((unused)) scaleForPXX( uint8_t i ) { //mapped 860,2140(125%) range to 64,1984(PXX values); - return (uint16_t)(((Servo_data[i]-PPM_MIN)*3)>>1)+64; + return (uint16_t)(((Servo_data[i]-servo_min_125)*3)>>1)+64; } static void __attribute__((unused)) frskyX_build_bind_packet() diff --git a/Multiprotocol/Hisky_nrf24l01.ino b/Multiprotocol/Hisky_nrf24l01.ino index 36c35b8..ddf935b 100644 --- a/Multiprotocol/Hisky_nrf24l01.ino +++ b/Multiprotocol/Hisky_nrf24l01.ino @@ -122,7 +122,7 @@ static void __attribute__((unused)) build_ch_data() uint8_t i,j; for (i = 0; i< 8; i++) { j=CH_AETR[i]; - temp=map(limit_channel_100(j),PPM_MIN_100,PPM_MAX_100,0,1000); + temp=map(limit_channel_100(j),servo_min_100,servo_max_100,0,1000); if (j == THROTTLE) // It is clear that hisky's throttle stick is made reversely, so I adjust it here on purpose temp = 1000 -temp; if (j == AUX3) diff --git a/Multiprotocol/MJXQ_nrf24l01.ino b/Multiprotocol/MJXQ_nrf24l01.ino index 484e798..e57cdf6 100644 --- a/Multiprotocol/MJXQ_nrf24l01.ino +++ b/Multiprotocol/MJXQ_nrf24l01.ino @@ -26,6 +26,17 @@ #define MJXQ_RF_NUM_CHANNELS 4 #define MJXQ_ADDRESS_LENGTH 5 +// haven't figured out txid<-->rf channel mapping for MJX models +const uint8_t PROGMEM MJXQ_map_rfchan[][4] = { + {0x0A, 0x46, 0x3A, 0x42}, + {0x0A, 0x3C, 0x36, 0x3F}, + {0x0A, 0x43, 0x36, 0x3F} }; +const uint8_t PROGMEM MJXQ_map_txid[][3] = { + {0xF8, 0x4F, 0x1C}, + {0xC8, 0x6E, 0x02}, + {0x48, 0x6A, 0x40} }; + + #define MJXQ_PAN_TILT_COUNT 16 // for H26D - match stock tx timing #define MJXQ_PAN_DOWN 0x08 #define MJXQ_PAN_UP 0x04 @@ -39,14 +50,14 @@ static uint8_t __attribute__((unused)) MJXQ_pan_tilt_value() packet_count++; if(packet_count & MJXQ_PAN_TILT_COUNT) { - if(Servo_AUX8) + if(Servo_data[AUX8]>PPM_MAX_COMMAND) pan=MJXQ_PAN_UP; if(Servo_data[AUX8]PPM_MIN_COMMAND) - pan=MJXQ_TILT_UP; + if(Servo_data[AUX9]>PPM_MAX_COMMAND) + pan+=MJXQ_TILT_UP; if(Servo_data[AUX9]rf channel mapping for MJX models - static const uint8_t rf_map[][4] = { - {0x0A, 0x46, 0x3A, 0x42}, - {0x0A, 0x3C, 0x36, 0x3F}, - {0x0A, 0x43, 0x36, 0x3F} }; if (sub_protocol == H26D) memcpy(hopping_frequency, "\x32\x3e\x42\x4e", MJXQ_RF_NUM_CHANNELS); else if (sub_protocol == WLH08) - memcpy(hopping_frequency, rf_map[rx_tx_addr[0]%3], MJXQ_RF_NUM_CHANNELS); + for(uint8_t i=0;irf channel mapping for MJX models - static const uint8_t tx_map[][3]={ - {0xF8, 0x4F, 0x1C}, - {0xC8, 0x6E, 0x02}, - {0x48, 0x6A, 0x40} }; if (sub_protocol == WLH08) rx_tx_addr[0]&=0xF8; // txid must be multiple of 8 else - memcpy(rx_tx_addr,tx_map[rx_tx_addr[0]%3],3); + for(uint8_t i=0;i<3;i++) + rx_tx_addr[i]=pgm_read_byte_near( &MJXQ_map_txid[rx_tx_addr[4]%3][i] ); } uint16_t MJXQ_callback() diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index b54affa..4e30d40 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -28,83 +28,84 @@ //****************** enum PROTOCOLS { - MODE_SERIAL = 0, // Serial commands - MODE_FLYSKY = 1, // =>A7105 - MODE_HUBSAN = 2, // =>A7105 - MODE_FRSKY = 3, // =>CC2500 - MODE_HISKY = 4, // =>NRF24L01 - MODE_V2X2 = 5, // =>NRF24L01 - MODE_DSM2 = 6, // =>CYRF6936 - MODE_DEVO =7, // =>CYRF6936 - MODE_YD717 = 8, // =>NRF24L01 - MODE_KN = 9, // =>NRF24L01 - MODE_SYMAX = 10, // =>NRF24L01 - MODE_SLT = 11, // =>NRF24L01 - MODE_CX10 = 12, // =>NRF24L01 - MODE_CG023 = 13, // =>NRF24L01 - MODE_BAYANG = 14, // =>NRF24L01 - MODE_FRSKYX = 15, // =>CC2500 - MODE_ESKY = 16, // =>NRF24L01 - MODE_MT99XX=17, // =>NRF24L01 - MODE_MJXQ=18, // =>NRF24L01 - MODE_SHENQI=19, // =>NRF24L01 - MODE_FY326=20, // =>NRF24L01 - MODE_SFHSS=21, // =>CC2500 - MODE_J6PRO=22, // =>CYRF6936 - MODE_FQ777=23, // =>NRF24L01 - MODE_ASSAN=24 // =>NRF24L01 + MODE_SERIAL = 0, // Serial commands + MODE_FLYSKY = 1, // =>A7105 + MODE_HUBSAN = 2, // =>A7105 + MODE_FRSKY = 3, // =>CC2500 + MODE_HISKY = 4, // =>NRF24L01 + MODE_V2X2 = 5, // =>NRF24L01 + MODE_DSM2 = 6, // =>CYRF6936 + MODE_DEVO = 7, // =>CYRF6936 + MODE_YD717 = 8, // =>NRF24L01 + MODE_KN = 9, // =>NRF24L01 + MODE_SYMAX = 10, // =>NRF24L01 + MODE_SLT = 11, // =>NRF24L01 + MODE_CX10 = 12, // =>NRF24L01 + MODE_CG023 = 13, // =>NRF24L01 + MODE_BAYANG = 14, // =>NRF24L01 + MODE_FRSKYX = 15, // =>CC2500 + MODE_ESKY = 16, // =>NRF24L01 + MODE_MT99XX = 17, // =>NRF24L01 + MODE_MJXQ = 18, // =>NRF24L01 + MODE_SHENQI = 19, // =>NRF24L01 + MODE_FY326 = 20, // =>NRF24L01 + MODE_SFHSS = 21, // =>CC2500 + MODE_J6PRO = 22, // =>CYRF6936 + MODE_FQ777 = 23, // =>NRF24L01 + MODE_ASSAN = 24 // =>NRF24L01 }; enum Flysky { - Flysky=0, - V9X9=1, - V6X6=2, - V912=3 + Flysky = 0, + V9X9 = 1, + V6X6 = 2, + V912 = 3 }; enum Hisky { - Hisky=0, - HK310=1 + Hisky = 0, + HK310 = 1 }; -enum DSM2{ - DSM2=0, - DSMX=1 +enum DSM2 +{ + DSM2 = 0, + DSMX = 1 }; enum YD717 { - YD717=0, - SKYWLKR=1, - SYMAX4=2, - XINXUN=3, - NIHUI=4 + YD717 = 0, + SKYWLKR = 1, + SYMAX4 = 2, + XINXUN = 3, + NIHUI = 4 }; enum KN { - WLTOYS=0, - FEILUN=1 + WLTOYS = 0, + FEILUN = 1 }; enum SYMAX { - SYMAX=0, - SYMAX5C=1 + SYMAX = 0, + SYMAX5C = 1 }; enum CX10 { - CX10_GREEN = 0, - CX10_BLUE=1, // also compatible with CX10-A, CX12 - DM007=2, - Q282=3, - JC3015_1=4, - JC3015_2=5, - MK33041=6, - Q242=7 + CX10_GREEN = 0, + CX10_BLUE = 1, // also compatible with CX10-A, CX12 + DM007 = 2, + Q282 = 3, + JC3015_1 = 4, + JC3015_2 = 5, + MK33041 = 6, + Q242 = 7 }; enum CG023 { - CG023 = 0, - YD829 = 1, - H8_3D = 2 + CG023 = 0, + YD829 = 1, + H8_3D = 2 }; enum MT99XX { @@ -146,126 +147,118 @@ struct PPM_Parameters //******************* //*** Pinouts *** //******************* -//#define BIND_pin 13 -#define LED_pin 13 //Promini original led on B5 -// -#define PPM_pin 3 //PPM -D3 +#define LED_pin 13 //Promini original led on B5 +#define PPM_pin 3 //PPM-D3 #ifdef XMEGA -#define SDI_pin 6 //SDIO-D6 + #define SDI_pin 6 //SDIO-D6 #else -#define SDI_pin 5 //SDIO-D5 + #define SDI_pin 5 //SDIO-D5 #endif -#define SCLK_pin 4 //SCK-D4 -#define CS_pin 2 //CS-D2 -#define SDO_pin 6 //D6 -// -#define CTRL1 1 //C1 (A1) -#define CTRL2 2 //C2 (A2) -// -#ifdef XMEGA -#define CTRL1_on -#define CTRL1_off -// -#define CTRL2_on -#define CTRL2_off -#else -#define CTRL1_on PORTC |= _BV(1) -#define CTRL1_off PORTC &= ~_BV(1) -// -#define CTRL2_on PORTC |= _BV(2) -#define CTRL2_off PORTC &= ~_BV(2) -#endif -// -#ifdef XMEGA -#define CS_on PORTD.OUTSET = _BV(4) //D4 -#define CS_off PORTD.OUTCLR = _BV(4) //D4 -#else -#define CS_on PORTD |= _BV(2) //D2 -#define CS_off PORTD &= ~_BV(2) //D2 -#endif -// -#ifdef XMEGA -#define SCK_on PORTD.OUTSET = _BV(7) //D7 -#define SCK_off PORTD.OUTCLR = _BV(7) //D7 -#else -#define SCK_on PORTD |= _BV(4) //D4 -#define SCK_off PORTD &= ~_BV(4) //D4 -#endif -// -#ifdef XMEGA -#define SDI_on PORTD.OUTSET = _BV(5) //D5 -#define SDI_off PORTD.OUTCLR = _BV(5) //D5 -#else -#define SDI_on PORTD |= _BV(5) //D5 -#define SDI_off PORTD &= ~_BV(5) //D5 -#endif - -#ifdef XMEGA -#define SDI_1 (PORTD.IN & (1<>2)&0x07 ) | ( (PINC<<3)&0x08) );//encoder dip switches 1,2,4,8=>B2,B3,B4,C0 #endif -//********************************** -//mode_select=1; // here to test PPM -//********************************** // Update LED LED_OFF; @@ -242,6 +243,7 @@ void setup() NRF24L01_Reset(); #endif +#ifdef ENABLE_PPM //Protocol and interrupts initialization if(mode_select != MODE_SERIAL) { // PPM @@ -254,6 +256,8 @@ void setup() if(PPM_prot[mode_select].power) POWER_FLAG_on; if(PPM_prot[mode_select].autobind) AUTOBIND_FLAG_on; mode_select++; + servo_max_100=PPM_MAX_100; servo_min_100=PPM_MIN_100; + servo_max_125=PPM_MAX_125; servo_min_125=PPM_MIN_125; protocol_init(); @@ -268,17 +272,23 @@ void setup() #endif } else +#endif //ENABLE_PPM { // Serial +#ifdef ENABLE_SERIAL cur_protocol[0]=0; cur_protocol[1]=0; prev_protocol=0; + servo_max_100=SERIAL_MAX_100; servo_min_100=SERIAL_MIN_100; + servo_max_125=SERIAL_MAX_125; servo_min_125=SERIAL_MIN_125; Mprotocol_serial_init(); // Configure serial and enable RX interrupt +#endif //ENABLE_SERIAL } } // Main void loop() { +#ifdef ENABLE_SERIAL if(mode_select==MODE_SERIAL && IS_RX_FLAG_on) // Serial mode and something has been received { update_serial_data(); // Update protocol and data @@ -291,6 +301,8 @@ void loop() CHANGE_PROTOCOL_FLAG_off; //done } } +#endif //ENABLE_SERIAL +#ifdef ENABLE_PPM if(mode_select!=MODE_SERIAL && IS_PPM_FLAG_on) // PPM mode and a full frame has been received { for(uint8_t i=0;iPPM_MAX_125) temp_ppm=PPM_MAX_125; Servo_data[i]= temp_ppm ; } update_aux_flags(); PPM_FLAG_off; // wait for next frame before update } +#endif //ENABLE_PPM update_led_status(); #if defined(TELEMETRY) if( ((cur_protocol[0]&0x1F)==MODE_FRSKY) || ((cur_protocol[0]&0x1F)==MODE_HUBSAN) || ((cur_protocol[0]&0x1F)==MODE_FRSKYX) || ((cur_protocol[0]&0x1F)==MODE_DSM2) ) @@ -362,10 +377,8 @@ static void CheckTimer(uint16_t (*cb)(void)) #else if( (TIFR1 & (1<32000) { // next_callback should not be more than 32767 so we will wait here... - uint16_t temp=next_callback>>10-2; + uint16_t temp=(next_callback>>10)-2; delayMilliseconds(temp); next_callback-=temp<<10; // between 2-3ms left at this stage } @@ -612,7 +623,7 @@ static void protocol_init() BIND_BUTTON_FLAG_off; // do not bind/reset id anymore even if protocol change } -static void update_serial_data() +void update_serial_data() { if(rx_ok_buff[0]&0x20) //check range RANGE_FLAG_on; @@ -660,7 +671,7 @@ static void update_serial_data() RX_FLAG_off; //data has been processed } -static void module_reset() +void module_reset() { if(remote_callback) { // previous protocol loaded @@ -703,13 +714,13 @@ int16_t map( int16_t x, int16_t in_min, int16_t in_max, int16_t out_min, int16_t // Channel value is converted to 8bit values full scale uint8_t convert_channel_8b(uint8_t num) { - return (uint8_t) (map(limit_channel_100(num),PPM_MIN_100,PPM_MAX_100,0,255)); + return (uint8_t) (map(limit_channel_100(num),servo_min_100,servo_max_100,0,255)); } // Channel value is converted to 8bit values to provided values scale uint8_t convert_channel_8b_scale(uint8_t num,uint8_t min,uint8_t max) { - return (uint8_t) (map(limit_channel_100(num),PPM_MIN_100,PPM_MAX_100,min,max)); + return (uint8_t) (map(limit_channel_100(num),servo_min_100,servo_max_100,min,max)); } // Channel value is converted sign + magnitude 8bit values @@ -723,7 +734,7 @@ uint8_t convert_channel_s8b(uint8_t num) // Channel value is converted to 10bit values uint16_t convert_channel_10b(uint8_t num) { - return (uint16_t) (map(limit_channel_100(num),PPM_MIN_100,PPM_MAX_100,1,1023)); + return (uint16_t) (map(limit_channel_100(num),servo_min_100,servo_max_100,1,1023)); } // Channel value is multiplied by 1.5 @@ -743,15 +754,15 @@ void convert_channel_HK310(uint8_t num, uint8_t *low, uint8_t *high) // Channel value is limited to PPM_100 uint16_t limit_channel_100(uint8_t ch) { - if(Servo_data[ch]>PPM_MAX_100) - return PPM_MAX_100; + if(Servo_data[ch]>servo_max_100) + return servo_max_100; else - if (Servo_data[ch]>1; - if(tempPPM_MAX) temp=PPM_MAX; - PPM_data[chan]=temp; + PPM_data[chan]= Cur_TCNT1>>1;; if(chan++>=NUM_CHN) chan=-1; // don't accept any new channels } Prev_TCNT1+=Cur_TCNT1; } +#endif //ENABLE_PPM //Serial RX +#ifdef ENABLE_SERIAL #ifdef XMEGA ISR(USARTC0_RXC_vect) #else @@ -1071,8 +1083,7 @@ ISR(USART_RX_vect) #endif if(!IS_RX_FLAG_on) { //Good frame received and main has finished with previous buffer - uint8_t i ; - for(i=0;i0 && pktt[6]<=10) {//only valid hub frames diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 52f8cc9..eb075a1 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -13,28 +13,32 @@ along with Multiprotocol. If not, see . */ +/**********************************************/ /** Multiprotocol module configuration file ***/ +/**********************************************/ /*******************/ /*** TX SETTINGS ***/ /*******************/ -//Uncomment your TX type -#define TX_ER9X_AETR //ER9X AETR (988<->2012µs) -//#define TX_ER9X_TAER //ER9X TAER (988<->2012µs) -//#define TX_DEVO7 //DEVO7 EATR (1120<->1920µs) -//#define TX_SPEKTRUM //Spektrum TAER (1100<->1900µs) -//#define TX_HISKY //HISKY AETR (1100<->1900µs) +//Modify the channel order based on your TX: AETR, TAER, RETA... +//For example a JR/Spektrum radio is TAER. Default is AETR. +#define AETR + /****************************/ /*** PROTOCOLS TO INCLUDE ***/ /****************************/ -//Comment if a module is not installed +//In this section select the protocols you want to be accessible when using the module. +//All the protocols will not fit in the module so you need to pick and choose. + +//There are 4 RF components supported. If one of them is not installed you must comment it using "//". +//This is also a quick way to reduce the number of protocols and save Flash space. #define A7105_INSTALLED #define CYRF6936_INSTALLED #define CC2500_INSTALLED #define NFR24L01_INSTALLED -//Comment a protocol to exclude it from compilation +//Bellow is the list of all available protocols. Comment the protocols you are not using with "//" to save Flash space. #ifdef A7105_INSTALLED #define FLYSKY_A7105_INO #define HUBSAN_A7105_INO @@ -68,16 +72,20 @@ #define ASSAN_NRF24L01_INO #endif + /**************************/ /*** TELEMETRY SETTINGS ***/ /**************************/ -//Uncomment to enable telemetry +//In this section you can configure the telemetry. + +//If you do not plan using the telemetry comment this global setting using "//" and skip to the next section. #define TELEMETRY -//Uncomment to invert the telemetry serial signal, this is usefull for OpenTX on Taranis as an example +//Uncomment to invert the polarity of the telemetry serial signal. +//For ER9X and ERSKY9X it must be commented. For OpenTX it must be uncommented. //#define INVERT_TELEMETRY 1 -//Comment to disable a specific telemetry +//Comment a line to disable a protocol telemetry #if defined(TELEMETRY) #if defined DSM2_CYRF6936_INO #define DSM_TELEMETRY @@ -90,18 +98,59 @@ #endif #endif -/********************/ -/*** PPM SETTINGS ***/ -/********************/ -//Update this table to set which protocol and all associated settings are called for the corresponding dial number + +/****************************/ +/*** SERIAL MODE SETTINGS ***/ +/****************************/ +//In this section you can configure the serial mode. +//The serial mode enables full editing of all the parameters in the GUI of the radio. +//This is available natively for ER9X and ERSKY9X. It is available for OpenTX on Taranis with a special version. + +//If you do not plan to use the Serial mode comment this line using "//" to save Flash space +#define ENABLE_SERIAL + + +/*************************/ +/*** PPM MODE SETTINGS ***/ +/*************************/ +//In this section you can configure all details about PPM. +//If you do not plan to use the PPM mode comment this line using "//" to save Flash space, you don't need to configure anything below in this case +#define ENABLE_PPM + +/*** TX END POINTS ***/ +//It is important for the module to know the endpoints of your radio. +//Below are some standard transmitters already preconfigured. +//Uncomment only the one which matches your transmitter. +#define TX_ER9X //ER9X/ERSKY9X/OpenTX ( 988<->2012µs) +//#define TX_DEVO7 //DEVO (1120<->1920µs) +//#define TX_SPEKTRUM //Spektrum (1100<->1900µs) +//#define TX_HISKY //HISKY (1100<->1900µs) +//#define TX_CUSTOM //Custom + +// The lines below are used to set the end points in microseconds (µs) if you have selected TX_CUSTOM. +// A few things to considered: +// - If you put too big values compared to your TX you won't be able to reach the extremes which is bad for throttle as an example +// - If you put too low values you won't be able to use your full stick range, it will be maxed out before reaching the end +// - Centered stick value is usually 1500. It should match the middle between MIN and MAX, ie Center=(MAX-MIN)/2+MIN. If your TX is not centered you can adjust the value MIN or MAX. +// - 100% is the value when the model is by default, 125% is the value when you extend the servo travel which is only used by some protocols +#if defined(TX_CUSTOM) + #define PPM_MAX_100 1900 // 100% + #define PPM_MIN_100 1100 // 100% + #define PPM_MAX_125 2000 // 125% + #define PPM_MIN_125 1000 // 125% +#endif + +//The table below indicates which protocol to run when a specific position on the dial has been selected. +//All fields and values are explained below. Everything is configurable from here like in the Serial mode. +//Example: You can associate multiple times the same protocol to different dial positions to take advantage of the model match (RX_Num) const PPM_Parameters PPM_prot[15]= { // Dial Protocol Sub protocol RX_Num Power Auto Bind Option /* 1 */ {MODE_FLYSKY, Flysky , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 2 */ {MODE_HUBSAN, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, -/* 3 */ {MODE_FRSKY , 0 , 0 , P_HIGH , NO_AUTOBIND , 0xD7 }, // D7 fine tuning +/* 3 */ {MODE_FRSKY , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, // option=fine freq tuning /* 4 */ {MODE_HISKY , Hisky , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 5 */ {MODE_V2X2 , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, -/* 6 */ {MODE_DSM2 , DSM2 , 0 , P_HIGH , NO_AUTOBIND , 6 }, // 6 channels @ 11ms +/* 6 */ {MODE_DSM2 , DSM2 , 0 , P_HIGH , NO_AUTOBIND , 2 }, // option=2=6 channels @ 22ms /* 7 */ {MODE_DEVO , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 8 */ {MODE_YD717 , YD717 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 9 */ {MODE_KN , WLTOYS , 0 , P_HIGH , NO_AUTOBIND , 0 }, @@ -112,7 +161,7 @@ const PPM_Parameters PPM_prot[15]= { /* 14 */ {MODE_BAYANG, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 15 */ {MODE_SYMAX , SYMAX5C , 0 , P_HIGH , NO_AUTOBIND , 0 } }; -/* Available protocols and associated sub protocols: +/* Available protocols and associated sub protocols to pick and choose from MODE_FLYSKY Flysky V9X9 @@ -188,134 +237,17 @@ const PPM_Parameters PPM_prot[15]= { NONE MODE_ASSAN NONE - -RX_Num value between 0 and 15 - -Power P_HIGH or P_LOW - -Auto Bind AUTOBIND or NO_AUTOBIND - -Option value between 0 and 255. 0xD7 or 0x00 for Frsky fine tuning. */ -/*******************/ -/*** TX SETTINGS ***/ -/*******************/ -// Turnigy PPM and channels -#if defined(TX_ER9X_AETR) -#define PPM_MAX 2140 // 125% -#define PPM_MIN 860 // 125% -#define PPM_MAX_100 2012 // 100% -#define PPM_MIN_100 988 // 100% -enum chan_order{ - AILERON =0, - ELEVATOR, - THROTTLE, - RUDDER, - AUX1, - AUX2, - AUX3, - AUX4, - AUX5, - AUX6, - AUX7, - AUX8, - AUX9 -}; -#endif +// RX_Num is used for model match. Using RX_Num values different for each receiver will prevent starting a model with the false config loaded... +// RX_Num value is between 0 and 15. -// Turnigy PPM and channels -#if defined(TX_ER9X_TAER) -#define PPM_MAX 2140 // 125% -#define PPM_MIN 860 // 125% -#define PPM_MAX_100 2012 // 100% -#define PPM_MIN_100 988 // 100% -enum chan_order{ - THROTTLE =0, - AILERON, - ELEVATOR, - RUDDER, - AUX1, - AUX2, - AUX3, - AUX4, - AUX5, - AUX6, - AUX7, - AUX8, - AUX9 -}; -#endif +// Power P_HIGH or P_LOW: High or low power setting for the transmission. +// For indoor P_LOW is more than enough. -// Devo PPM and channels -#if defined(TX_DEVO7) -#define PPM_MAX 2100 // 125% -#define PPM_MIN 900 // 125% -#define PPM_MAX_100 1920 // 100% -#define PPM_MIN_100 1120 // 100% -enum chan_order{ - ELEVATOR=0, - AILERON, - THROTTLE, - RUDDER, - AUX1, - AUX2, - AUX3, - AUX4, - AUX5, - AUX6, - AUX7, - AUX8, - AUX9 -}; -#endif +// Auto Bind AUTOBIND or NO_AUTOBIND +// For protocols which does not require binding at each power up (like Flysky, FrSky...), you might still want a bind to be initiated each time you power up the TX. +// As an exxample, it's usefull for the WLTOYS F929/F939/F949/F959 (all using the Flysky protocol) which requires a bind at each power up. -// SPEKTRUM PPM and channels -#if defined(TX_SPEKTRUM) -#define PPM_MAX 2000 // 125% -#define PPM_MIN 1000 // 125% -#define PPM_MAX_100 1900 // 100% -#define PPM_MIN_100 1100 // 100% -enum chan_order{ - THROTTLE=0, - AILERON, - ELEVATOR, - RUDDER, - AUX1, - AUX2, - AUX3, - AUX4, - AUX5, - AUX6, - AUX7, - AUX8, - AUX9 -}; -#endif - -// HISKY -#if defined(TX_HISKY) -#define PPM_MAX 2000 // 125% -#define PPM_MIN 1000 // 125% -#define PPM_MAX_100 1900 // 100% -#define PPM_MIN_100 1100 // 100% -enum chan_order{ - AILERON =0, - ELEVATOR, - THROTTLE, - RUDDER, - AUX1, - AUX2, - AUX3, - AUX4, - AUX5, - AUX6, - AUX7, - AUX8, - AUX9 -}; -#endif - -#define PPM_MIN_COMMAND 1250 -#define PPM_SWITCH 1550 -#define PPM_MAX_COMMAND 1750 +// Option: the value is between -127 and +127. +// The option value is only valid for some protocols, read this page for more information: https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Protocols_Details.md \ No newline at end of file From e63f71d3a76a926cf24eef37dc6ec754d5a30948 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 24 Aug 2016 15:05:24 +0200 Subject: [PATCH 151/293] . --- Multiprotocol/Multiprotocol.ino | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 4cba479..e62befa 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -1050,12 +1050,11 @@ ISR(USART_RX_vect) if(idx==0) { // Let's try to sync at this point #ifdef XMEGA - if(USARTC0.DATA==0x55) // If 1st byte is 0x55 it looks ok + if(USARTC0.DATA==0x55) // If 1st byte is 0x55 it looks ok #else if(UDR0==0x55) // If 1st byte is 0x55 it looks ok #endif { - idx++; #ifdef XMEGA TCC1.CCB = TCC1.CNT+(6500L) ; // Full message should be received within timer of 3250us TCC1.INTFLAGS = TC1_CCBIF_bm ; // clear OCR1B match flag @@ -1065,6 +1064,7 @@ ISR(USART_RX_vect) TIFR1=(1< Date: Thu, 25 Aug 2016 11:26:08 +0200 Subject: [PATCH 152/293] Couples of fixes and improvements --- Multiprotocol/Multiprotocol.h | 8 ++ Multiprotocol/Multiprotocol.ino | 170 +++++++++++++++++--------------- 2 files changed, 100 insertions(+), 78 deletions(-) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 4e30d40..bf25279 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -310,6 +310,14 @@ struct PPM_Parameters #define BAD_PROTO_on protocol_flags2 |= _BV(0) #define IS_BAD_PROTO_on ( ( protocol_flags2 & _BV(0) ) !=0 ) +#define RX_DONOTUPDTAE_off protocol_flags2 &= ~_BV(1) +#define RX_DONOTUPDTAE_on protocol_flags2 |= _BV(1) +#define IS_RX_DONOTUPDTAE_on ( ( protocol_flags2 & _BV(1) ) !=0 ) + +#define RX_MISSED_BUFF_off protocol_flags2 &= ~_BV(2) +#define RX_MISSED_BUFF_on protocol_flags2 |= _BV(2) +#define IS_RX_MISSED_BUFF_on ( ( protocol_flags2 & _BV(2) ) !=0 ) + #define BLINK_BIND_TIME 100 #define BLINK_SERIAL_TIME 500 #define BLINK_BAD_PROTO_TIME_LOW 1000 diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index e62befa..bcae55c 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -102,7 +102,7 @@ volatile uint8_t rx_ok_buff[RXBUFFER_SIZE]; #ifndef BASH_SERIAL volatile uint8_t tx_buff[TXBUFFER_SIZE]; #endif -volatile uint8_t idx = 0; +volatile uint8_t discard_frame = 0; //Serial protocol uint8_t sub_protocol; @@ -368,54 +368,53 @@ static void CheckTimer(uint16_t (*cb)(void)) #ifdef XMEGA if( (TCC1.INTFLAGS & TC1_CCAIF_bm) != 0) { - cli(); // disable global int + cli(); // Disable global int due to RW of 16 bits registers TCC1.CCA = TCC1.CNT ; // Callback should already have been called... Use "now" as new sync point. - sei(); // enable global int + sei(); // Enable global int } else while((TCC1.INTFLAGS & TC1_CCAIF_bm) == 0); // wait before callback #else if( (TIFR1 & (1<4000) - { // start to wait here as much as we can... - next_callback=next_callback-2000; + { // start to wait here as much as we can... + next_callback-=2000; // We will wait below for 2ms #ifdef XMEGA - cli(); // disable global int + cli(); // Disable global int due to RW of 16 bits registers TCC1.CCA +=2000*2; // set compare A for callback TCC1.INTFLAGS = TC1_CCAIF_bm ; // clear compare A=callback flag sei(); // enable global int while((TCC1.INTFLAGS & TC1_CCAIF_bm) == 0); // wait 2ms... #else - cli(); // disable global int + cli(); // Disable global int due to RW of 16 bits registers OCR1A = OCR1A + 2000*2 ; // set compare A for callback TIFR1=(1<>4)& 0x07; //subprotocol no (0-7) bits 4-6 - RX_num=rx_ok_buff[1]& 0x0F; - MProtocol_id=MProtocol_id_master+RX_num; //personalized RX bind + rx num // rx_num bits 0---3 - } - else - if( ((rx_ok_buff[0]&0x80)!=0) && ((cur_protocol[0]&0x80)==0) ) // Bind flag has been set - CHANGE_PROTOCOL_FLAG_on; //restart protocol with bind - cur_protocol[0] = rx_ok_buff[0]; //store current protocol - - // decode channel values - volatile uint8_t *p=rx_ok_buff+2; - uint8_t dec=-3; - for(uint8_t i=0;i=8) - { - dec-=8; - p++; - } - p++; - Servo_data[i]=((((*((uint32_t *)p))>>dec)&0x7FF)*5)/8+860; //value range 860<->2140 -125%<->+125% - } RX_FLAG_off; //data has been processed + do + { + cli(); + if(IS_RX_MISSED_BUFF_on) // If the buffer is still valid + memcpy((void*)rx_ok_buff,(const void*)rx_buff,RXBUFFER_SIZE);// Duplicate the buffer + sei(); + RX_MISSED_BUFF_off; + RX_DONOTUPDTAE_on; + if(rx_ok_buff[0]&0x20) //check range + RANGE_FLAG_on; + else + RANGE_FLAG_off; + if(rx_ok_buff[0]&0xC0) //check autobind(0x40) & bind(0x80) together + AUTOBIND_FLAG_on; + else + AUTOBIND_FLAG_off; + if(rx_ok_buff[1]&0x80) //if rx_ok_buff[1] ==1,power is low ,0-power high + POWER_FLAG_off; //power low + else + POWER_FLAG_on; //power high + + option=rx_ok_buff[2]; + + if( ((rx_ok_buff[0]&0x5F) != (cur_protocol[0]&0x5F)) || ( (rx_ok_buff[1]&0x7F) != cur_protocol[1] ) ) + { // New model has been selected + prev_protocol=cur_protocol[0]&0x1F; //store previous protocol so we can reset the module + cur_protocol[1] = rx_ok_buff[1]&0x7F; //store current protocol + CHANGE_PROTOCOL_FLAG_on; //change protocol + sub_protocol=(rx_ok_buff[1]>>4)& 0x07; //subprotocol no (0-7) bits 4-6 + RX_num=rx_ok_buff[1]& 0x0F; + MProtocol_id=MProtocol_id_master+RX_num;//personalized RX bind + rx num // rx_num bits 0---3 + } + else + if( ((rx_ok_buff[0]&0x80)!=0) && ((cur_protocol[0]&0x80)==0) ) // Bind flag has been set + CHANGE_PROTOCOL_FLAG_on; //restart protocol with bind + cur_protocol[0] = rx_ok_buff[0]; //store current protocol + + // decode channel values + volatile uint8_t *p=rx_ok_buff+2; + uint8_t dec=-3; + for(uint8_t i=0;i=8) + { + dec-=8; + p++; + } + p++; + Servo_data[i]=((((*((uint32_t *)p))>>dec)&0x7FF)*5)/8+860; //value range 860<->2140 -125%<->+125% + } + RX_DONOTUPDTAE_off; + } + while(IS_RX_MISSED_BUFF_on); // We've just processed an old frame... } void module_reset() @@ -1037,18 +1047,20 @@ ISR(USARTC0_RXC_vect) ISR(USART_RX_vect) #endif { // RX interrupt + static uint8_t idx=0; #ifdef XMEGA - if((USARTC0.STATUS & 0x1C)==0) // Check frame error, data overrun and parity error + if((USARTC0.STATUS & 0x1C)==0) // Check frame error, data overrun and parity error #else - UCSR0B &= ~(1< Date: Thu, 25 Aug 2016 11:40:38 +0200 Subject: [PATCH 153/293] Removed duplicate Telemetry defines --- Multiprotocol/Multiprotocol.ino | 9 --------- 1 file changed, 9 deletions(-) diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index bcae55c..67729aa 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -114,15 +114,6 @@ uint8_t prev_protocol=0; #define MAX_PKT 27 uint8_t pkt[MAX_PKT];//telemetry receiving packets #if defined(TELEMETRY) - #if defined DSM2_CYRF6936_INO - #define DSM_TELEMETRY - #endif - #if defined FRSKYX_CC2500_INO - #define SPORT_TELEMETRY - #endif - #if defined FRSKY_CC2500_INO - #define HUB_TELEMETRY - #endif uint8_t pktt[MAX_PKT];//telemetry receiving packets #ifndef BASH_SERIAL volatile uint8_t tx_head=0; From e7ed80d3e0efe78590bfc1b75f20895e1ca40c9e Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 25 Aug 2016 13:42:21 +0200 Subject: [PATCH 154/293] Devo fix --- Multiprotocol/Devo_cyrf6936.ino | 321 ++++++++++++-------------------- 1 file changed, 115 insertions(+), 206 deletions(-) diff --git a/Multiprotocol/Devo_cyrf6936.ino b/Multiprotocol/Devo_cyrf6936.ino index e535095..d2ed525 100644 --- a/Multiprotocol/Devo_cyrf6936.ino +++ b/Multiprotocol/Devo_cyrf6936.ino @@ -21,16 +21,13 @@ //For Debug //#define NO_SCRAMBLE -#define PKTS_PER_CHANNEL 4 -#define DEVO_BIND_COUNT 0x1388 -//#define TELEMETRY_ENABLE 0x30 -#define NUM_WAIT_LOOPS (100 / 5) //each loop is ~5us. Do not wait more than 100us -// -//#define TELEM_ON 0 -//#define TELEM_OFF 1 -enum Devo_PhaseState -{ +#define DEVO_PKTS_PER_CHANNEL 4 +#define DEVO_BIND_COUNT 0x1388 + +#define DEVO_NUM_WAIT_LOOPS (100 / 5) //each loop is ~5us. Do not wait more than 100us + +enum { DEVO_BIND, DEVO_BIND_SENDCH, DEVO_BOUND, @@ -46,7 +43,7 @@ enum Devo_PhaseState DEVO_BOUND_10, }; -const uint8_t sopcodes[][8] = { +const uint8_t PROGMEM DEVO_sopcodes[][8] = { /* Note these are in order transmitted (LSB 1st) */ /* 0 */ {0x3C,0x37,0xCC,0x91,0xE2,0xF8,0xCC,0x91}, //0x91CCF8E291CC373C /* 1 */ {0x9B,0xC5,0xA1,0x0F,0xAD,0x39,0xA2,0x0F}, //0x0FA239AD0FA1C59B @@ -60,36 +57,37 @@ const uint8_t sopcodes[][8] = { /* 9 */ {0x97,0xE5,0x14,0x72,0x7F,0x1A,0x14,0x72}, //0x72141A7F7214E597 }; -uint8_t txState; -uint8_t pkt_num; -uint8_t ch_idx; -uint8_t use_fixed_id; -uint8_t failsafe_pkt; +static void __attribute__((unused)) DEVO_ConfigSOPCode(uint8_t val) +{ + uint8_t code[8]; + for(uint8_t i=0;i<8;i++) + code[i]=pgm_read_byte_near(&DEVO_sopcodes[val][i]); + CYRF_ConfigSOPCode(code); +} -static void __attribute__((unused)) scramble_pkt() +static void __attribute__((unused)) DEVO_scramble_pkt() { #ifdef NO_SCRAMBLE return; #else - uint8_t i; - for(i = 0; i < 15; i++) + for(uint8_t i = 0; i < 15; i++) packet[i + 1] ^= cyrfmfg_id[i % 4]; #endif } -static void __attribute__((unused)) add_pkt_suffix() +static void __attribute__((unused)) DEVO_add_pkt_suffix() { - uint8_t bind_state; - if (use_fixed_id) + uint8_t bind_state; + if (option) { - if (bind_counter > 0) - bind_state = 0xc0; - else - bind_state = 0x80; - } + if (bind_counter > 0) + bind_state = 0xc0; + else + bind_state = 0x80; + } else - bind_state = 0x00; - packet[10] = bind_state | (PKTS_PER_CHANNEL - pkt_num - 1); + bind_state = 0x00; + packet[10] = bind_state | (DEVO_PKTS_PER_CHANNEL - packet_count - 1); packet[11] = *(hopping_frequency_ptr + 1); packet[12] = *(hopping_frequency_ptr + 2); packet[13] = fixed_id & 0xff; @@ -97,59 +95,50 @@ static void __attribute__((unused)) add_pkt_suffix() packet[15] = (fixed_id >> 16) & 0xff; } -static void __attribute__((unused)) build_beacon_pkt(uint8_t upper) +static void __attribute__((unused)) DEVO_build_beacon_pkt(uint8_t upper) { - packet[0] = ((DEVO_NUM_CHANNELS << 4) | 0x07); -// uint8_t enable = 0; + packet[0] = (DEVO_NUM_CHANNELS << 4) | 0x07; uint8_t max = 8; -// int offset = 0; if (upper) { packet[0] += 1; max = 4; -// offset = 8; } for(uint8_t i = 0; i < max; i++) packet[i+1] = 0; -// packet[9] = enable; packet[9] = 0; - add_pkt_suffix(); + DEVO_add_pkt_suffix(); } -#define FORCE_INDIRECT(ptr) __asm__ __volatile__ ("" : "=e" (ptr) : "0" (ptr)) - -static void __attribute__((unused)) build_bind_pkt() +static void __attribute__((unused)) DEVO_build_bind_pkt() { - uint8_t *p = packet ; - FORCE_INDIRECT(p) ; - p[0] = (DEVO_NUM_CHANNELS << 4) | 0x0a; - p[1] = bind_counter & 0xff; - p[2] = (bind_counter >> 8); - p[3] = *hopping_frequency_ptr; - p[4] = *(hopping_frequency_ptr + 1); - p[5] = *(hopping_frequency_ptr + 2); - p[6] = cyrfmfg_id[0]; - p[7] = cyrfmfg_id[1]; - p[8] = cyrfmfg_id[2]; - p[9] = cyrfmfg_id[3]; - add_pkt_suffix(); + packet[0] = (DEVO_NUM_CHANNELS << 4) | 0x0a; + packet[1] = bind_counter & 0xff; + packet[2] = (bind_counter >> 8); + packet[3] = *hopping_frequency_ptr; + packet[4] = *(hopping_frequency_ptr + 1); + packet[5] = *(hopping_frequency_ptr + 2); + packet[6] = cyrfmfg_id[0]; + packet[7] = cyrfmfg_id[1]; + packet[8] = cyrfmfg_id[2]; + packet[9] = cyrfmfg_id[3]; + DEVO_add_pkt_suffix(); //The fixed-id portion is scrambled in the bind packet //I assume it is ignored - p[13] ^= cyrfmfg_id[0]; - p[14] ^= cyrfmfg_id[1]; - p[15] ^= cyrfmfg_id[2]; + packet[13] ^= cyrfmfg_id[0]; + packet[14] ^= cyrfmfg_id[1]; + packet[15] ^= cyrfmfg_id[2]; } -static void __attribute__((unused)) build_data_pkt() +static void __attribute__((unused)) DEVO_build_data_pkt() { - uint8_t i; + static uint8_t ch_idx=0; + packet[0] = (DEVO_NUM_CHANNELS << 4) | (0x0b + ch_idx); uint8_t sign = 0x0b; - for (i = 0; i < 4; i++) + for (uint8_t i = 0; i < 4; i++) { - // - int16_t value= map(Servo_data[ch_idx * 4 + i],servo_min_125,servo_max_125,-1600,1600);//range -1600...+1600 - //s32 value = (s32)Channels[ch_idx * 4 + i] * 0x640 / CHAN_MAX_VALUE;//10000 + int16_t value=map(Servo_data[ch_idx * 4 + i],servo_min_125,servo_max_125,-1600,1600);//range -1600..+1600 if(value < 0) { value = -value; @@ -159,13 +148,13 @@ static void __attribute__((unused)) build_data_pkt() packet[2 * i + 2] = (value >> 8) & 0xff; } packet[9] = sign; - ch_idx = ch_idx + 1; + ch_idx++; if (ch_idx * 4 >= DEVO_NUM_CHANNELS) ch_idx = 0; - add_pkt_suffix(); + DEVO_add_pkt_suffix(); } -static void __attribute__((unused)) cyrf_set_bound_sop_code() +static void __attribute__((unused)) DEVO_cyrf_set_bound_sop_code() { /* crc == 0 isn't allowed, so use 1 if the math results in 0 */ uint8_t crc = (cyrfmfg_id[0] + (cyrfmfg_id[1] >> 6) + cyrfmfg_id[2]); @@ -174,94 +163,62 @@ static void __attribute__((unused)) cyrf_set_bound_sop_code() uint8_t sopidx = (0xff &((cyrfmfg_id[0] << 2) + cyrfmfg_id[1] + cyrfmfg_id[2])) % 10; CYRF_SetTxRxMode(TX_EN); CYRF_ConfigCRCSeed((crc << 8) + crc); - CYRF_ConfigSOPCode(sopcodes[sopidx]); + DEVO_ConfigSOPCode(sopidx); CYRF_SetPower(0x08); } -const uint8_t PROGMEM devo_init_vals[][2] = { - {CYRF_06_RX_CFG, 0x4A }, - {CYRF_0B_PWR_CTRL, 0x00 }, - {CYRF_0D_IO_CFG, 0x04 }, - {CYRF_0E_GPIO_CTRL, 0x20 }, - {CYRF_10_FRAMING_CFG, 0xA4 }, - {CYRF_11_DATA32_THOLD, 0x05 }, - {CYRF_12_DATA64_THOLD, 0x0E }, - {CYRF_1B_TX_OFFSET_LSB, 0x55 }, - {CYRF_1C_TX_OFFSET_MSB, 0x05 }, - {CYRF_32_AUTO_CAL_TIME, 0x3C }, - {CYRF_35_AUTOCAL_OFFSET, 0x14 }, - {CYRF_39_ANALOG_CTRL, 0x01 }, - {CYRF_1E_RX_OVERRIDE, 0x10 }, - {CYRF_1F_TX_OVERRIDE, 0x00 }, - {CYRF_01_TX_LENGTH, 0x10 }, - {CYRF_0C_XTAL_CTRL, 0xC0 }, - {CYRF_0F_XACT_CFG, 0x10 }, - {CYRF_27_CLK_OVERRIDE, 0x02 }, - {CYRF_28_CLK_EN, 0x02 }, - {CYRF_0F_XACT_CFG, 0x28 } +const uint8_t PROGMEM DEVO_init_vals[][2] = { + { CYRF_1D_MODE_OVERRIDE, 0x38 }, + { CYRF_03_TX_CFG, 0x08 }, + { CYRF_06_RX_CFG, 0x4A }, + { CYRF_0B_PWR_CTRL, 0x00 }, + { CYRF_10_FRAMING_CFG, 0xA4 }, + { CYRF_11_DATA32_THOLD, 0x05 }, + { CYRF_12_DATA64_THOLD, 0x0E }, + { CYRF_1B_TX_OFFSET_LSB, 0x55 }, + { CYRF_1C_TX_OFFSET_MSB, 0x05 }, + { CYRF_32_AUTO_CAL_TIME, 0x3C }, + { CYRF_35_AUTOCAL_OFFSET, 0x14 }, + { CYRF_39_ANALOG_CTRL, 0x01 }, + { CYRF_1E_RX_OVERRIDE, 0x10 }, + { CYRF_1F_TX_OVERRIDE, 0x00 }, + { CYRF_01_TX_LENGTH, 0x10 }, + { CYRF_0F_XACT_CFG, 0x10 }, + { CYRF_27_CLK_OVERRIDE, 0x02 }, + { CYRF_28_CLK_EN, 0x02 }, + { CYRF_0F_XACT_CFG, 0x28 } }; -static void __attribute__((unused)) cyrf_init() +static void __attribute__((unused)) DEVO_cyrf_init() { /* Initialise CYRF chip */ - CYRF_WriteRegister(CYRF_1D_MODE_OVERRIDE, 0x39); - CYRF_SetPower(0x08); - for(uint8_t i = 0; i < sizeof(devo_init_vals) / 2; i++) - CYRF_WriteRegister(pgm_read_byte( &devo_init_vals[i][0]), pgm_read_byte( &devo_init_vals[i][1]) ); - -// CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4A); -// CYRF_WriteRegister(CYRF_0B_PWR_CTRL, 0x00); -// CYRF_WriteRegister(CYRF_0D_IO_CFG, 0x04); -// CYRF_WriteRegister(CYRF_0E_GPIO_CTRL, 0x20); -// CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0xA4); -// CYRF_WriteRegister(CYRF_11_DATA32_THOLD, 0x05); -// CYRF_WriteRegister(CYRF_12_DATA64_THOLD, 0x0E); -// CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, 0x55); -// CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, 0x05); -// CYRF_WriteRegister(CYRF_32_AUTO_CAL_TIME, 0x3C); -// CYRF_WriteRegister(CYRF_35_AUTOCAL_OFFSET, 0x14); -// CYRF_WriteRegister(CYRF_39_ANALOG_CTRL, 0x01); -// CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x10); -// CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x00); -// CYRF_WriteRegister(CYRF_01_TX_LENGTH, 0x10); -// CYRF_WriteRegister(CYRF_0C_XTAL_CTRL, 0xC0); -// CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x10); -// CYRF_WriteRegister(CYRF_27_CLK_OVERRIDE, 0x02); -// CYRF_WriteRegister(CYRF_28_CLK_EN, 0x02); -// CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x28); + for(uint8_t i = 0; i < sizeof(DEVO_init_vals) / 2; i++) + CYRF_WriteRegister(pgm_read_byte( &DEVO_init_vals[i][0]), pgm_read_byte( &DEVO_init_vals[i][1]) ); } -static void __attribute__((unused)) set_radio_channels() +static void __attribute__((unused)) DEVO_set_radio_channels() { - //int i; CYRF_FindBestChannels(hopping_frequency, 3, 4, 4, 80); - //printf("Radio Channels:"); - // for (i = 0; i < 3; i++) { - // printf(" %02x", radio_ch[i]); - - //Serial.print(radio_ch[i]); - // } - // printf("\n"); - //Makes code a little easier to duplicate these here hopping_frequency[3] = hopping_frequency[0]; hopping_frequency[4] = hopping_frequency[1]; } static void __attribute__((unused)) DEVO_BuildPacket() { + static uint8_t failsafe_pkt=0; switch(phase) { case DEVO_BIND: - if(bind_counter>0) + if(bind_counter) bind_counter--; - build_bind_pkt(); + DEVO_build_bind_pkt(); phase = DEVO_BIND_SENDCH; break; case DEVO_BIND_SENDCH: - if(bind_counter>0) + if(bind_counter) bind_counter--; - build_data_pkt(); - scramble_pkt(); + DEVO_build_data_pkt(); + DEVO_scramble_pkt(); if (bind_counter == 0) { phase = DEVO_BOUND; @@ -280,10 +237,10 @@ static void __attribute__((unused)) DEVO_BuildPacket() case DEVO_BOUND_7: case DEVO_BOUND_8: case DEVO_BOUND_9: - build_data_pkt(); - scramble_pkt(); + DEVO_build_data_pkt(); + DEVO_scramble_pkt(); phase++; - if (bind_counter > 0) + if (bind_counter) { bind_counter--; if (bind_counter == 0) @@ -291,19 +248,20 @@ static void __attribute__((unused)) DEVO_BuildPacket() } break; case DEVO_BOUND_10: - build_beacon_pkt(DEVO_NUM_CHANNELS > 8 ? failsafe_pkt : 0); + DEVO_build_beacon_pkt(DEVO_NUM_CHANNELS > 8 ? failsafe_pkt : 0); failsafe_pkt = failsafe_pkt ? 0 : 1; - scramble_pkt(); + DEVO_scramble_pkt(); phase = DEVO_BOUND_1; break; } - pkt_num++; - if(pkt_num == PKTS_PER_CHANNEL) - pkt_num = 0; + packet_count++; + if(packet_count == DEVO_PKTS_PER_CHANNEL) + packet_count = 0; } uint16_t devo_callback() { + static uint8_t txState=0; if (txState == 0) { txState = 1; @@ -314,107 +272,58 @@ uint16_t devo_callback() txState = 0; uint8_t i = 0; while (! (CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02)) - if(++i > NUM_WAIT_LOOPS) + if(++i > DEVO_NUM_WAIT_LOOPS) return 1200; if (phase == DEVO_BOUND) { /* exit binding state */ phase = DEVO_BOUND_3; - cyrf_set_bound_sop_code(); + DEVO_cyrf_set_bound_sop_code(); } - if(pkt_num == 0) + if(packet_count == 0) { - //Keep tx power updated - CYRF_SetPower(0x08); + CYRF_SetPower(0x08); //Keep tx power updated hopping_frequency_ptr = hopping_frequency_ptr == &hopping_frequency[2] ? hopping_frequency : hopping_frequency_ptr + 1; CYRF_ConfigRFChannel(*hopping_frequency_ptr); } return 1200; } -/*static void __attribute__((unused)) devo_bind() -{ - fixed_id = Model_fixed_id; - bind_counter = DEVO_BIND_COUNT; - use_fixed_id = 1; - //PROTOCOL_SetBindState(0x1388 * 2400 / 1000); //msecs 12000ms -} - - -static void __attribute__((unused)) generate_fixed_id_bind(){ -if(BIND_0){ -//randomSeed((uint32_t)analogRead(A6)<<10|analogRead(A7));//seed -uint8_t txid[4]; -//Model_fixed_id = random(0xfefefefe) + ((uint32_t)random(0xfefefefe) << 16); -Model_fixed_id=0x332211; -txid[0]= (id &0xFF); -txid[1] = ((id >> 8) & 0xFF); -txid[2] = ((id >> 16) & 0xFF); -//txid[3] = ((id >> 24) & 0xFF); -eeprom_write_block((const void*)txid,(void*)40,3); -devo_bind(); -} -} -*/ - - uint16_t DevoInit() { - CYRF_Reset(); - cyrf_init(); + DEVO_cyrf_init(); CYRF_GetMfgData(cyrfmfg_id); CYRF_SetTxRxMode(TX_EN); CYRF_ConfigCRCSeed(0x0000); - CYRF_ConfigSOPCode(sopcodes[0]); - set_radio_channels(); - use_fixed_id = 0; - failsafe_pkt = 0; + DEVO_ConfigSOPCode(0); + DEVO_set_radio_channels(); + hopping_frequency_ptr = hopping_frequency; - // CYRF_ConfigRFChannel(*hopping_frequency_ptr); - //FIXME: Properly setnumber of channels; - pkt_num = 0; - ch_idx = 0; - txState = 0; - //uint8_t txid[4]; - // - - /* -if(BIND_0){ -Model_fixed_id=0; -eeprom_write_block((const void*)0,(void*)40,4); -while(1){ -LED_ON; -delayMilliseconds(100); -LED_OFF; -delayMilliseconds(100); -} -} -else{ -eeprom_read_block((void*)txid,(const void*)40,3); -Model_fixed_id=(txid[0] | ((uint32_t)txid[1]<<8) | ((uint32_t)txid[2]<<16)); -} -*/ - - if(! Model_fixed_id) - {//model fixed ID =0 - fixed_id = ((uint32_t)(hopping_frequency[0] ^ cyrfmfg_id[0] ^ cyrfmfg_id[3]) << 16) - | ((uint32_t)(hopping_frequency[1] ^ cyrfmfg_id[1] ^ cyrfmfg_id[4]) << 8) - | ((uint32_t)(hopping_frequency[2] ^ cyrfmfg_id[2] ^ cyrfmfg_id[5]) << 0); - fixed_id = fixed_id % 1000000; + + packet_count = 0; + + if(option==0) + { + MProtocol_id = ((uint32_t)(hopping_frequency[0] ^ cyrfmfg_id[0] ^ cyrfmfg_id[3]) << 16) + | ((uint32_t)(hopping_frequency[1] ^ cyrfmfg_id[1] ^ cyrfmfg_id[4]) << 8) + | ((uint32_t)(hopping_frequency[2] ^ cyrfmfg_id[2] ^ cyrfmfg_id[5]) << 0); bind_counter = DEVO_BIND_COUNT; phase = DEVO_BIND; - //PROTOCOL_SetBindState(0x1388 * 2400 / 1000); //msecs + BIND_IN_PROGRESS; } else { - fixed_id = Model_fixed_id; - use_fixed_id = 1; phase = DEVO_BOUND_1; bind_counter = 0; - cyrf_set_bound_sop_code(); + DEVO_cyrf_set_bound_sop_code(); } + MProtocol_id %= 1000000; + if(IS_AUTOBIND_FLAG_on) + { + bind_counter = DEVO_BIND_COUNT; + } return 2400; } From 840a583a0b9e0978d63357e9f8fa60e57df89789 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 25 Aug 2016 14:48:48 +0200 Subject: [PATCH 155/293] Devo fix --- Multiprotocol/Devo_cyrf6936.ino | 21 +++++++++++---------- Multiprotocol/Multiprotocol.ino | 4 +--- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/Multiprotocol/Devo_cyrf6936.ino b/Multiprotocol/Devo_cyrf6936.ino index d2ed525..24c91e9 100644 --- a/Multiprotocol/Devo_cyrf6936.ino +++ b/Multiprotocol/Devo_cyrf6936.ino @@ -78,7 +78,12 @@ static void __attribute__((unused)) DEVO_scramble_pkt() static void __attribute__((unused)) DEVO_add_pkt_suffix() { uint8_t bind_state; - if (option) + if(prev_option!=option) + { + MProtocol_id = RX_num + MProtocol_id_master; + bind_counter=DEVO_BIND_COUNT; + } + if (option) { if (bind_counter > 0) bind_state = 0xc0; @@ -90,9 +95,9 @@ static void __attribute__((unused)) DEVO_add_pkt_suffix() packet[10] = bind_state | (DEVO_PKTS_PER_CHANNEL - packet_count - 1); packet[11] = *(hopping_frequency_ptr + 1); packet[12] = *(hopping_frequency_ptr + 2); - packet[13] = fixed_id & 0xff; - packet[14] = (fixed_id >> 8) & 0xff; - packet[15] = (fixed_id >> 16) & 0xff; + packet[13] = MProtocol_id & 0xff; + packet[14] = (MProtocol_id >> 8) & 0xff; + packet[15] = (MProtocol_id >> 16) & 0xff; } static void __attribute__((unused)) DEVO_build_beacon_pkt(uint8_t upper) @@ -303,11 +308,13 @@ uint16_t DevoInit() packet_count = 0; + prev_option=option; if(option==0) { MProtocol_id = ((uint32_t)(hopping_frequency[0] ^ cyrfmfg_id[0] ^ cyrfmfg_id[3]) << 16) | ((uint32_t)(hopping_frequency[1] ^ cyrfmfg_id[1] ^ cyrfmfg_id[4]) << 8) | ((uint32_t)(hopping_frequency[2] ^ cyrfmfg_id[2] ^ cyrfmfg_id[5]) << 0); + MProtocol_id %= 1000000; bind_counter = DEVO_BIND_COUNT; phase = DEVO_BIND; BIND_IN_PROGRESS; @@ -318,12 +325,6 @@ uint16_t DevoInit() bind_counter = 0; DEVO_cyrf_set_bound_sop_code(); } - MProtocol_id %= 1000000; - - if(IS_AUTOBIND_FLAG_on) - { - bind_counter = DEVO_BIND_COUNT; - } return 2400; } diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 67729aa..e4fde0b 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -33,9 +33,6 @@ //Global constants/variables uint32_t MProtocol_id;//tx id, uint32_t MProtocol_id_master; -uint32_t Model_fixed_id=0; -uint32_t fixed_id; -uint8_t cyrfmfg_id[6];//for dsm2 and devo uint32_t blink=0; uint8_t prev_option; uint8_t prev_power=0xFD; // unused power value @@ -51,6 +48,7 @@ uint8_t Servo_AUX; uint16_t servo_max_100,servo_min_100,servo_max_125,servo_min_125; // Protocol variables +uint8_t cyrfmfg_id[6];//for dsm2 and devo uint8_t rx_tx_addr[5]; uint8_t phase; uint16_t bind_counter; From 6332a37f5b0a6a861978bdbb0294d84f0ad987ed Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 25 Aug 2016 15:28:57 +0200 Subject: [PATCH 156/293] DEVO bind procedure --- Protocols_Details.md | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 2c3fd8b..e5ee5fd 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -4,6 +4,7 @@ Legend: - Extended limits supported: -125%..+125% can be used and will be transmitted. Otherwise the default is -100%..+100% only. - Autobind protocol: you do not need to press the bind button at power up to bind, this is done automatically. +The AETR mentionned here for all protocols depends on the compilation option. *** #A7105 RF Module @@ -93,7 +94,19 @@ Extended limits supported CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- -CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +A|E|T|R|CH5|CH6|CH7|CH8 + +Bind procedure: +- With the TX off, put the binding plug in and power on the RX, then power it down and remove the binding plug. Receiver should now be in autobind mode. +- Turn on the TX, set protocol = Devo with option=0, turn off the TX (TX is now in autobind mode). +- Tun on RX. +- Turn on TX. +- Wait for bind on the TX to complete, bind LED solid. +- Make sure to set the RX_Num value for model match. +- Change option to 1 to use the global ID. +- Do not touch option/RX_Num anymore. + +Note that the ouput on the RX will be EATR. ##DSM2 Extended limits supported @@ -123,6 +136,8 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 ---|---|---|---|---|---|---|---|---|----|----|---- A|E|T|R|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 +Note that the ouput on the RX will be TAER. + ###Sub_protocol DSMX Same as above From d4f9752cd431c3147adf8846bc1ff2899cf6140e Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 25 Aug 2016 15:29:14 +0200 Subject: [PATCH 157/293] Update Protocols_Details.md --- Protocols_Details.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index e5ee5fd..201b230 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -4,6 +4,7 @@ Legend: - Extended limits supported: -125%..+125% can be used and will be transmitted. Otherwise the default is -100%..+100% only. - Autobind protocol: you do not need to press the bind button at power up to bind, this is done automatically. + The AETR mentionned here for all protocols depends on the compilation option. *** From 8b60c7cc09f8a22861bccd556a94d61220e7d284 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 25 Aug 2016 15:30:57 +0200 Subject: [PATCH 158/293] Update Protocols_Details.md --- Protocols_Details.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 201b230..198fa5c 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -5,7 +5,7 @@ Legend: - Extended limits supported: -125%..+125% can be used and will be transmitted. Otherwise the default is -100%..+100% only. - Autobind protocol: you do not need to press the bind button at power up to bind, this is done automatically. -The AETR mentionned here for all protocols depends on the compilation option. +The AETR mentionned here for all protocols depends on the TX settings compilation option set in _Config.h. *** #A7105 RF Module From 1c1f6e21c55a9b46b7b03c409d93e193bb8531ea Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 25 Aug 2016 15:40:01 +0200 Subject: [PATCH 159/293] Update Protocols_Details.md --- Protocols_Details.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 198fa5c..65924cb 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -98,11 +98,11 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 A|E|T|R|CH5|CH6|CH7|CH8 Bind procedure: -- With the TX off, put the binding plug in and power on the RX, then power it down and remove the binding plug. Receiver should now be in autobind mode. +- With the TX off, put the binding plug in and power on the RX (RX LED slow blink), then power it down and remove the binding plug. Receiver should now be in autobind mode. - Turn on the TX, set protocol = Devo with option=0, turn off the TX (TX is now in autobind mode). -- Tun on RX. -- Turn on TX. -- Wait for bind on the TX to complete, bind LED solid. +- Tun on RX (RX LED fast blink). +- Turn on TX (RX LED solid, TX LED fast blink). +- Wait for bind on the TX to complete (TX LED solid). - Make sure to set the RX_Num value for model match. - Change option to 1 to use the global ID. - Do not touch option/RX_Num anymore. From 3b3b61f52ce3926fe89f340225340d7b65a360a7 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 25 Aug 2016 15:44:02 +0200 Subject: [PATCH 160/293] DEVO channel order --- Multiprotocol/Devo_cyrf6936.ino | 2 +- Multiprotocol/Multiprotocol.ino | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/Multiprotocol/Devo_cyrf6936.ino b/Multiprotocol/Devo_cyrf6936.ino index 24c91e9..924a779 100644 --- a/Multiprotocol/Devo_cyrf6936.ino +++ b/Multiprotocol/Devo_cyrf6936.ino @@ -143,7 +143,7 @@ static void __attribute__((unused)) DEVO_build_data_pkt() uint8_t sign = 0x0b; for (uint8_t i = 0; i < 4; i++) { - int16_t value=map(Servo_data[ch_idx * 4 + i],servo_min_125,servo_max_125,-1600,1600);//range -1600..+1600 + int16_t value=map(Servo_data[CH_EATR[ch_idx * 4 + i]],servo_min_125,servo_max_125,-1600,1600);//range -1600..+1600 if(value < 0) { value = -value; diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index e4fde0b..eb9e605 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -78,6 +78,7 @@ uint8_t calData[48][3]; const uint8_t CH_AETR[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8}; //const uint8_t CH_TAER[]={THROTTLE, AILERON, ELEVATOR, RUDDER, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8}; //const uint8_t CH_RETA[]={RUDDER, ELEVATOR, THROTTLE, AILERON, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8}; +const uint8_t CH_EATR[]={ELEVATOR, AILERON, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8}; // Mode_select variables uint8_t mode_select; From fae37fe67d78d2086ea5c3531b0ca0b81e070ac0 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 25 Aug 2016 19:39:08 +0200 Subject: [PATCH 161/293] Update Protocols_Details.md --- Protocols_Details.md | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 65924cb..ebff328 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -17,6 +17,8 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- A|E|T|R|CH5|CH6|CH7|CH8 +Note that the RX ouput will be AETR. + ###Sub_protocol V9X9 CH5|CH6|CH7|CH8 ---|---|---|--- @@ -107,7 +109,7 @@ Bind procedure: - Change option to 1 to use the global ID. - Do not touch option/RX_Num anymore. -Note that the ouput on the RX will be EATR. +Note that the RX ouput will be EATR. ##DSM2 Extended limits supported @@ -137,7 +139,7 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 ---|---|---|---|---|---|---|---|---|----|----|---- A|E|T|R|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 -Note that the ouput on the RX will be TAER. +Note that the RX ouput will be TAER. ###Sub_protocol DSMX Same as above @@ -196,7 +198,7 @@ JJRC H20: OPT1=Headless, OPT2=RTH JJRC H22: OPT1=RTH, OPT2=180/360° flip mode -H8 3D: OPT1=RTH + headless, OPT2=180/360° flip mode +H8 3D: OPT1=RTH then press a direction to enter headless mode (like stock TX), OPT2=switch 180/360° flip mode CAL: calibrate accelerometers From 3b5471b97cf91a4691c94d8bd9198f00998f3a3f Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 25 Aug 2016 21:22:33 +0200 Subject: [PATCH 162/293] Update Protocols_Details.md --- Protocols_Details.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index ebff328..fae3fd0 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -99,7 +99,7 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- A|E|T|R|CH5|CH6|CH7|CH8 -Bind procedure: +Bind procedure using serial: - With the TX off, put the binding plug in and power on the RX (RX LED slow blink), then power it down and remove the binding plug. Receiver should now be in autobind mode. - Turn on the TX, set protocol = Devo with option=0, turn off the TX (TX is now in autobind mode). - Tun on RX (RX LED fast blink). @@ -109,6 +109,13 @@ Bind procedure: - Change option to 1 to use the global ID. - Do not touch option/RX_Num anymore. +Bind procedure using PPM: +- With the TX off, put the binding plug in and power on the RX (RX LED slow blink), then power it down and remove the binding plug. Receiver should now be in autobind mode. +- Turn on the TX, set protocol = Devo with option=0, turn off the TX (TX is now in autobind mode). +- Tun on RX (RX LED fast blink). +- Turn on TX (RX LED solid, TX LED fast blink). +Fixed ID is not supported yet. + Note that the RX ouput will be EATR. ##DSM2 From a5b084f506d4bcbb2870f41c75f2182a2913e320 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 26 Aug 2016 10:55:13 +0200 Subject: [PATCH 163/293] Update README.md --- README.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/README.md b/README.md index 72baff4..5df17b6 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,5 @@ # DIY-Multiprotocol-TX-Module + Multiprotocol is a 2.4GHz transmitter which enables any TX to control lot of different models available on the market. The source code is partly based on the Deviation TX project, thanks to all the developpers for their great job on protocols. @@ -9,6 +10,8 @@ The source code is partly based on the Deviation TX project, thanks to all the d **To download the latest compiled version (hex file), click on [Release](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases) on the top menu.** +If you wish to support the development of this free firmware [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=RT7738FE98HMY) + ##Contents [Compatible TX](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#compatible-tx) From bbf9331bafc16af36161b5c83555169ba3608a51 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 26 Aug 2016 10:56:27 +0200 Subject: [PATCH 164/293] Update README.md --- README.md | 2 -- 1 file changed, 2 deletions(-) diff --git a/README.md b/README.md index 5df17b6..794e7b5 100644 --- a/README.md +++ b/README.md @@ -10,8 +10,6 @@ The source code is partly based on the Deviation TX project, thanks to all the d **To download the latest compiled version (hex file), click on [Release](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases) on the top menu.** -If you wish to support the development of this free firmware [![Donate](https://img.shields.io/badge/Donate-PayPal-green.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=RT7738FE98HMY) - ##Contents [Compatible TX](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#compatible-tx) From 059c6baa4efa50ee5324d21edd705e4a16f16251 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 26 Aug 2016 16:18:50 +0200 Subject: [PATCH 165/293] FrSkyX/SFHSS rfcal & second channel ASSAN --- Multiprotocol/ASSAN_nrf24l01.ino | 14 +++++++--- Multiprotocol/FrSkyX_cc2500.ino | 44 ++++++++++++-------------------- Multiprotocol/Multiprotocol.ino | 6 ++--- Multiprotocol/SFHSS_cc2500.ino | 4 +-- 4 files changed, 32 insertions(+), 36 deletions(-) diff --git a/Multiprotocol/ASSAN_nrf24l01.ino b/Multiprotocol/ASSAN_nrf24l01.ino index 3356e2f..3add45a 100644 --- a/Multiprotocol/ASSAN_nrf24l01.ino +++ b/Multiprotocol/ASSAN_nrf24l01.ino @@ -140,7 +140,7 @@ static void __attribute__((unused)) ASSAN_initialize_txid() packet[21]=0xFA; packet[20]=0x53; */ // Using packet[20..23] to store the ID1 and packet[24..27] to store the ID2 - uint8_t freq=0; + uint8_t freq=0,freq2; for(uint8_t i=0;i<4;i++) { uint8_t temp=rx_tx_addr[0]; @@ -153,9 +153,15 @@ static void __attribute__((unused)) ASSAN_initialize_txid() freq=((freq%25)+2)<<1; if(freq&0x02) freq|=0x01; hopping_frequency[0]=freq; - // Alternate frequency - hopping_frequency[1]=freq*2-6; - hopping_frequency[1]+=analogRead(A6)%12; // Add some random to the second channel + // Alternate frequency has some random + do + { + randomSeed((uint32_t)analogRead(A6) << 10 | analogRead(A7)); + freq2=random(0xfefefefe)%9; + freq2+=freq*2-5; + } + while( (freq2>118) || (freq2>2; //for test*************** diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index eb9e605..4124685 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -71,13 +71,13 @@ uint8_t len; uint8_t RX_num; #if defined(FRSKYX_CC2500_INO) || defined(SFHSS_CC2500_INO) -uint8_t calData[48][3]; +uint8_t calData[48]; #endif //Channel mapping for protocols const uint8_t CH_AETR[]={AILERON, ELEVATOR, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8}; -//const uint8_t CH_TAER[]={THROTTLE, AILERON, ELEVATOR, RUDDER, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8}; -//const uint8_t CH_RETA[]={RUDDER, ELEVATOR, THROTTLE, AILERON, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8}; +const uint8_t CH_TAER[]={THROTTLE, AILERON, ELEVATOR, RUDDER, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8}; +const uint8_t CH_RETA[]={RUDDER, ELEVATOR, THROTTLE, AILERON, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8}; const uint8_t CH_EATR[]={ELEVATOR, AILERON, THROTTLE, RUDDER, AUX1, AUX2, AUX3, AUX4, AUX5, AUX6, AUX7, AUX8}; // Mode_select variables diff --git a/Multiprotocol/SFHSS_cc2500.ino b/Multiprotocol/SFHSS_cc2500.ino index 47537ce..a9b793a 100644 --- a/Multiprotocol/SFHSS_cc2500.ino +++ b/Multiprotocol/SFHSS_cc2500.ino @@ -98,7 +98,7 @@ static void __attribute__((unused)) SFHSS_tune_chan_fast() { CC2500_Strobe(CC2500_SIDLE); CC2500_WriteReg(CC2500_0A_CHANNR, rf_ch_num*6+16); - CC2500_WriteRegisterMulti(CC2500_23_FSCAL3, calData[rf_ch_num], 3); + CC2500_WriteReg(CC2500_25_FSCAL1, calData[rf_ch_num]); } static void __attribute__((unused)) SFHSS_tune_freq() @@ -170,7 +170,7 @@ uint16_t ReadSFHSS() phase = SFHSS_CAL; return 2000; case SFHSS_CAL: - CC2500_ReadRegisterMulti(CC2500_23_FSCAL3, calData[rf_ch_num], 3); + calData[rf_ch_num]=CC2500_ReadReg(CC2500_25_FSCAL1); if (++rf_ch_num < 30) SFHSS_tune_chan(); else From 5969902263dcd3a315e6a74c6a33ba696966b3d4 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 26 Aug 2016 17:21:21 +0200 Subject: [PATCH 166/293] MJXQ fix --- Multiprotocol/MJXQ_nrf24l01.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Multiprotocol/MJXQ_nrf24l01.ino b/Multiprotocol/MJXQ_nrf24l01.ino index e57cdf6..9ca6f5e 100644 --- a/Multiprotocol/MJXQ_nrf24l01.ino +++ b/Multiprotocol/MJXQ_nrf24l01.ino @@ -174,7 +174,7 @@ static void __attribute__((unused)) MJXQ_init() else { memcpy(hopping_frequency, "\x0a\x35\x42\x3d", MJXQ_RF_NUM_CHANNELS); - memcpy(addr, "\x6d\x6a\x73\x73\x73", MJXQ_RF_NUM_CHANNELS); + memcpy(addr, "\x6d\x6a\x73\x73\x73", MJXQ_ADDRESS_LENGTH); } From e5d378dc93337796741aae54ae8931d1281f666d Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 26 Aug 2016 18:46:03 +0200 Subject: [PATCH 167/293] Update Protocols_Details.md --- Protocols_Details.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index fae3fd0..f452a8f 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -102,7 +102,7 @@ A|E|T|R|CH5|CH6|CH7|CH8 Bind procedure using serial: - With the TX off, put the binding plug in and power on the RX (RX LED slow blink), then power it down and remove the binding plug. Receiver should now be in autobind mode. - Turn on the TX, set protocol = Devo with option=0, turn off the TX (TX is now in autobind mode). -- Tun on RX (RX LED fast blink). +- Turn on RX (RX LED fast blink). - Turn on TX (RX LED solid, TX LED fast blink). - Wait for bind on the TX to complete (TX LED solid). - Make sure to set the RX_Num value for model match. From fb022970b5c013abdcabf18ad1e796bad5364b8d Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 26 Aug 2016 21:02:50 +0200 Subject: [PATCH 168/293] Update Protocols_Details.md --- Protocols_Details.md | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index f452a8f..f1f8d51 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -99,6 +99,8 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- A|E|T|R|CH5|CH6|CH7|CH8 +Note that the RX ouput will be EATR. + Bind procedure using serial: - With the TX off, put the binding plug in and power on the RX (RX LED slow blink), then power it down and remove the binding plug. Receiver should now be in autobind mode. - Turn on the TX, set protocol = Devo with option=0, turn off the TX (TX is now in autobind mode). @@ -111,12 +113,14 @@ Bind procedure using serial: Bind procedure using PPM: - With the TX off, put the binding plug in and power on the RX (RX LED slow blink), then power it down and remove the binding plug. Receiver should now be in autobind mode. -- Turn on the TX, set protocol = Devo with option=0, turn off the TX (TX is now in autobind mode). -- Tun on RX (RX LED fast blink). -- Turn on TX (RX LED solid, TX LED fast blink). -Fixed ID is not supported yet. - -Note that the RX ouput will be EATR. +- Turn on RX (RX LED fast blink). +- Turn the dial to the model number running protocol DEVO on the module. +- Press the bind button and turn on the TX. TX is now in autobind mode. +- Release bind button after 1 second: RX LED solid, TX LED fast blink. +- Wait for bind on the TX to complete (TX LED solid). +- Press the bind button for 1 second. TX/RX is now in fixed ID mode. +- To verify that the TX is in fixed mode: power cycle the TX, the module LED should be solid ON (no blink). +- Note: Autobind/fixed ID mode is linked to the dial number. Which means that you can have multiple dial numbers set to the same protocol DEVO with different RX_Num and have different bind modes at the same time. It enables PPM users to get model match under DEVO. ##DSM2 Extended limits supported From 78ee77444fb7e4b5144d6ece1306a90693fcbcfd Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sat, 27 Aug 2016 08:26:05 +0200 Subject: [PATCH 169/293] Update README.md --- README.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 794e7b5..20680e6 100644 --- a/README.md +++ b/README.md @@ -379,7 +379,9 @@ This will make sure your ATMEGA328 is well configured and the global TX ID is no Make sure to follow this procedure: press the bind button, apply power and then release it after 1sec. The LED should be blinking fast indicating a bind status and then fixed on when the bind period is over. It's normal that the LED turns off when you press the bind button, this behavior is not controlled by the Atmega328. For serial, the preffered method is to bind via the GUI protocol page. -It migth happen that your module is always binding at power up. If this is the case, there is a big chance that you are using an Arduino Pro Mini with an external status LED. To work around this issue connect a 10K resistor between D13 and 3.3V. +If your module is always/sometime binding at power up without pressing the button: + - Arduino Pro Mini with an external status LED: to work around this issue connect a 10K resistor between D13 and 3.3V. + - 4in1 module V1 (check 4in1 pictures): to solve this issue, replacing the BIND led resistor (on the board back) of 1.2K by a 4.7K. ###Report issues You can report your problem using the [GitHub issue](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/issues) system or go to the [Main thread on RCGROUPS](http://www.rcgroups.com/forums/showthread.php?t=2165676) to ask your question. From f6c52523764419abc96672df40efb446e03d3c1a Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 26 Aug 2016 18:33:05 +0200 Subject: [PATCH 170/293] DEVO PPM fixed id mode --- Multiprotocol/Devo_cyrf6936.ino | 15 ++++++++++++++- Multiprotocol/Multiprotocol.h | 30 ++++++++++++++++++++---------- Multiprotocol/Multiprotocol.ino | 21 ++++++++++++++++----- 3 files changed, 50 insertions(+), 16 deletions(-) diff --git a/Multiprotocol/Devo_cyrf6936.ino b/Multiprotocol/Devo_cyrf6936.ino index 924a779..cf56eed 100644 --- a/Multiprotocol/Devo_cyrf6936.ino +++ b/Multiprotocol/Devo_cyrf6936.ino @@ -78,7 +78,20 @@ static void __attribute__((unused)) DEVO_scramble_pkt() static void __attribute__((unused)) DEVO_add_pkt_suffix() { uint8_t bind_state; - if(prev_option!=option) + #ifdef ENABLE_PPM + if(mode_select && option==0 && IS_BIND_DONE_on) //PPM mode and option not already set and bind is finished + { + BIND_SET_INPUT; + BIND_SET_PULLUP; // set pullup + if(IS_BIND_BUTTON_on) + { + eeprom_write_byte((uint8_t*)(30+mode_select),0x01); // Set fixed id mode for the current model + option=1; + } + BIND_SET_OUTPUT; + } + #endif //ENABLE_PPM + if(prev_option!=option && IS_BIND_DONE_on) { MProtocol_id = RX_num + MProtocol_id_master; bind_counter=DEVO_BIND_COUNT; diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index bf25279..c4a55bd 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -248,17 +248,27 @@ struct PPM_Parameters // LED #ifdef XMEGA - #define LED_ON PORTD.OUTCLR = _BV(1) - #define LED_OFF PORTD.OUTSET = _BV(1) - #define LED_TOGGLE PORTD.OUTTGL = _BV(1) - #define LED_SET_OUTPUT PORTD.DIRSET = _BV(1) - #define IS_LED_on ( (PORTD.OUT & _BV(1)) != 0x00 ) + #define LED_ON PORTD.OUTCLR = _BV(1) + #define LED_OFF PORTD.OUTSET = _BV(1) + #define LED_TOGGLE PORTD.OUTTGL = _BV(1) + #define LED_SET_OUTPUT PORTD.DIRSET = _BV(1) + #define IS_LED_on ( (PORTD.OUT & _BV(1)) != 0x00 ) #else - #define LED_ON PORTB |= _BV(5) - #define LED_OFF PORTB &= ~_BV(5) - #define LED_TOGGLE PORTB ^= _BV(5) - #define LED_SET_OUTPUT DDRB |= _BV(5) - #define IS_LED_on ( (PORTB & _BV(5)) != 0x00 ) + #define LED_ON PORTB |= _BV(5) + #define LED_OFF PORTB &= ~_BV(5) + #define LED_TOGGLE PORTB ^= _BV(5) + #define LED_SET_OUTPUT DDRB |= _BV(5) + #define IS_LED_on ( (PORTB & _BV(5)) != 0x00 ) +#endif + +//BIND +#ifdef XMEGA + #define IS_BIND_BUTTON_on ( (PORTD.IN & _BV(2)) == 0x00 ) +#else + #define BIND_SET_INPUT DDRB &= ~_BV(5) + #define BIND_SET_PULLUP PORTB |= _BV(5) + #define IS_BIND_BUTTON_on ( (PINB & _BV(5)) == 0x00 ) + #define BIND_SET_OUTPUT DDRB |= _BV(5) #endif // TX diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 4124685..0ded1cb 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -196,11 +196,7 @@ void setup() delayMilliseconds(100); // Read status of bind button -#ifdef XMEGA - if( (PORTD.IN & _BV(2)) == 0x00 ) -#else - if( (PINB & _BV(5)) == 0x00 ) -#endif + if( IS_BIND_BUTTON_on ) BIND_BUTTON_FLAG_on; // If bind button pressed save the status for protocol id reset under hubsan // Read status of mode select binary switch @@ -483,6 +479,21 @@ static void protocol_init() #endif #if defined(DEVO_CYRF6936_INO) case MODE_DEVO: + #ifdef ENABLE_PPM + if(mode_select) //PPM mode + { + if(IS_BIND_BUTTON_FLAG_on) + { + eeprom_write_byte((uint8_t*)(30+mode_select),0x00); // reset to autobind mode for the current model + option=0; + } + else + { + option=eeprom_read_byte((uint8_t*)(30+mode_select)); // load previous mode: autobind or fixed id + if(option!=1) option=0; // if not fixed id mode then it should be autobind + } + } + #endif //ENABLE_PPM CTRL2_on; //antenna RF4 next_callback = DevoInit(); remote_callback = devo_callback; From 14e3419e4c57bfdbf5bba650f88dfd339e75f7ba Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sun, 28 Aug 2016 14:03:22 +0200 Subject: [PATCH 171/293] Added MJXQ / E010 --- Multiprotocol/MJXQ_nrf24l01.ino | 32 ++++++++++++++++++++++++-------- Multiprotocol/Multiprotocol.h | 4 +++- Multiprotocol/_Config.h | 1 + 3 files changed, 28 insertions(+), 9 deletions(-) diff --git a/Multiprotocol/MJXQ_nrf24l01.ino b/Multiprotocol/MJXQ_nrf24l01.ino index 9ca6f5e..556b178 100644 --- a/Multiprotocol/MJXQ_nrf24l01.ino +++ b/Multiprotocol/MJXQ_nrf24l01.ino @@ -12,7 +12,7 @@ You should have received a copy of the GNU General Public License along with Multiprotocol. If not, see . */ -// compatible with MJX WLH08, X600, X800, H26D +// compatible with MJX WLH08, X600, X800, H26D, Eachine E010 // Last sync with hexfet new_protocols/mjxq_nrf24l01.c dated 2016-01-17 #if defined(MJXQ_NRF24L01_INO) @@ -92,6 +92,12 @@ static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind) // Servo_AUX7 AUTOFLIP // X800, X600 switch(sub_protocol) { + case E010: + packet[10] = GET_FLAG(Servo_AUX5, 0x01) //HEADLESS + | GET_FLAG(Servo_AUX6, 0x02); //RTH + if (!bind) + packet[14] = GET_FLAG(Servo_AUX1, 0x04); //FLIP + break; case H26D: packet[10]=MJXQ_pan_tilt_value(); // fall through on purpose - no break @@ -169,7 +175,7 @@ static void __attribute__((unused)) MJXQ_init() if (sub_protocol == WLH08) memcpy(hopping_frequency, "\x12\x22\x32\x42", MJXQ_RF_NUM_CHANNELS); else - if (sub_protocol == H26D) + if (sub_protocol == H26D || sub_protocol == E010) memcpy(hopping_frequency, "\x36\x3e\x46\x2e", MJXQ_RF_NUM_CHANNELS); else { @@ -193,7 +199,10 @@ static void __attribute__((unused)) MJXQ_init() NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x01); // Enable data pipe 0 only NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // no retransmits NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, MJXQ_PACKET_SIZE); // rx pipe 0 (used only for blue board) - NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps + if (sub_protocol == E010) + NRF24L01_SetBitrate(NRF24L01_BR_250K); // 250K + else + NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps NRF24L01_SetPower(); } @@ -202,18 +211,25 @@ static void __attribute__((unused)) MJXQ_init2() if (sub_protocol == H26D) memcpy(hopping_frequency, "\x32\x3e\x42\x4e", MJXQ_RF_NUM_CHANNELS); else - if (sub_protocol == WLH08) + if (sub_protocol != WLH08 && sub_protocol != E010) for(uint8_t i=0;i Date: Sun, 28 Aug 2016 14:05:21 +0200 Subject: [PATCH 172/293] Added E010 --- Protocols_Details.md | 1 + 1 file changed, 1 insertion(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index f1f8d51..88ec485 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -325,6 +325,7 @@ A|E|T|R|FLIP|LED|PICTURE|VIDEO|HEADLESS|RTH|AUTOFLIP|PAN|TILT ###Sub_protocol X600 ###Sub_protocol X800 ###Sub_protocol H26D +###Sub_protocol E010 ##MT99XX Autobind protocol From 33b5694d35adabd077051198c5992a747d906a2e Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 29 Aug 2016 08:23:00 +0200 Subject: [PATCH 173/293] MJXQ/E010 mod --- Multiprotocol/MJXQ_nrf24l01.ino | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/Multiprotocol/MJXQ_nrf24l01.ino b/Multiprotocol/MJXQ_nrf24l01.ino index 556b178..cda417b 100644 --- a/Multiprotocol/MJXQ_nrf24l01.ino +++ b/Multiprotocol/MJXQ_nrf24l01.ino @@ -92,16 +92,11 @@ static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind) // Servo_AUX7 AUTOFLIP // X800, X600 switch(sub_protocol) { - case E010: - packet[10] = GET_FLAG(Servo_AUX5, 0x01) //HEADLESS - | GET_FLAG(Servo_AUX6, 0x02); //RTH - if (!bind) - packet[14] = GET_FLAG(Servo_AUX1, 0x04); //FLIP - break; case H26D: packet[10]=MJXQ_pan_tilt_value(); // fall through on purpose - no break case WLH08: + case E010: packet[10] += GET_FLAG(Servo_AUX6, 0x02) //RTH | GET_FLAG(Servo_AUX5, 0x01); //HEADLESS if (!bind) From e2021fdf5dd0d0750ef50fd9519bb7aaf2b12dc0 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 29 Aug 2016 08:24:52 +0200 Subject: [PATCH 174/293] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 20680e6..f6dcb69 100644 --- a/README.md +++ b/README.md @@ -221,6 +221,7 @@ MJXQ| |X600 |X800 |H26D + |E010 Shenqi| FY326| FQ777| From 0c16a6804a8674ea5c217242813da6e591584468 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 29 Aug 2016 08:29:57 +0200 Subject: [PATCH 175/293] E010 --- Protocols_Details.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index 88ec485..f2f71f6 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -323,9 +323,12 @@ A|E|T|R|FLIP|LED|PICTURE|VIDEO|HEADLESS|RTH|AUTOFLIP|PAN|TILT ###Sub_protocol WLH08 ###Sub_protocol X600 +Only 3 TX IDs available, change RX_Num value 0..2 to cycle through them ###Sub_protocol X800 +Only 3 TX IDs available, change RX_Num value 0..2 to cycle through them ###Sub_protocol H26D ###Sub_protocol E010 +Only 1 TX ID available ##MT99XX Autobind protocol From 2588011524209fcf877323fb6d9835beaec272d2 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 29 Aug 2016 09:51:27 +0200 Subject: [PATCH 176/293] Orange DSM module update --- Multiprotocol/MultiOrange.cpp.xmega | 3 ++- Multiprotocol/Multiprotocol.ino | 21 +++++++++++++++++---- Multiprotocol/Telemetry.ino | 18 +++++++++--------- 3 files changed, 28 insertions(+), 14 deletions(-) diff --git a/Multiprotocol/MultiOrange.cpp.xmega b/Multiprotocol/MultiOrange.cpp.xmega index 2a331fa..85a7ca0 100644 --- a/Multiprotocol/MultiOrange.cpp.xmega +++ b/Multiprotocol/MultiOrange.cpp.xmega @@ -17,7 +17,8 @@ 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) ; - +void initTXSerial( uint8_t speed); +void Serial_write(uint8_t data); extern void NRF24L01_Reset(void ) ; extern void A7105_Reset(void ) ; diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 0ded1cb..ec6bdc8 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -628,11 +628,19 @@ void update_serial_data() RX_FLAG_off; //data has been processed do { - cli(); + #ifdef XMEGA + cli(); + #else + UCSR0B &= ~(1< UBRR0H = UBRRH_VALUE; @@ -898,6 +909,7 @@ uint8_t SPI_Read(void) // replacement millis() and micros() // These work polled, no interrupts // micros() MUST be called at least once every 32 milliseconds +#ifndef XMEGA uint16_t MillisPrecount ; uint16_t lastTimerValue ; uint32_t TotalMicros ; @@ -997,6 +1009,7 @@ void init() // this needs to be called before setup() or some functions won't work there sei(); } +#endif //XMEGA /**************************/ /**************************/ @@ -1053,7 +1066,7 @@ ISR(USART_RX_vect) if((USARTC0.STATUS & 0x1C)==0) // Check frame error, data overrun and parity error #else - UCSR0B &= ~(1<=TXBUFFER_SIZE) - tx_head=0; - tx_buff[tx_head]=data; + uint8_t nextHead ; + nextHead = tx_head + 1 ; + if ( nextHead >= TXBUFFER_SIZE ) + nextHead = 0 ; + tx_buff[nextHead]=data; + tx_head = nextHead ; #ifdef XMEGA USARTC0.CTRLA = (USARTC0.CTRLA & 0xFC) | 0x01 ; #else UCSR0B |= (1< Date: Mon, 29 Aug 2016 17:32:21 +0200 Subject: [PATCH 177/293] Changed update_serial_data --- Multiprotocol/Multiprotocol.ino | 126 ++++++++++++++++---------------- 1 file changed, 61 insertions(+), 65 deletions(-) diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index ec6bdc8..2e4a37d 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -202,8 +202,7 @@ void setup() // Read status of mode select binary switch // after this mode_select will be one of {0000, 0001, ..., 1111} #ifdef XMEGA - mode_select=0x0F - ( PORTA.IN & 0x0F ) ; //encoder dip switches 1,2,4,8=>B2,B3,B4,C0 - mode_select = MODE_SERIAL ; + mode_select = MODE_SERIAL ; // only serial mode #else mode_select=0x0F - ( ( (PINB>>2)&0x07 ) | ( (PINC<<3)&0x08) );//encoder dip switches 1,2,4,8=>B2,B3,B4,C0 #endif @@ -328,7 +327,7 @@ static void update_led_status(void) { if(blink led on + LED_OFF; //bind completed -> led on else blink+=BLINK_BIND_TIME; //blink fastly during binding LED_TOGGLE; @@ -384,7 +383,7 @@ static void CheckTimer(uint16_t (*cb)(void)) while((TCC1.INTFLAGS & TC1_CCAIF_bm) == 0); // wait 2ms... #else cli(); // Disable global int due to RW of 16 bits registers - OCR1A = OCR1A + 2000*2 ; // set compare A for callback + OCR1A += 2000*2 ; // set compare A for callback TIFR1=(1<>4)& 0x07; //subprotocol no (0-7) bits 4-6 - RX_num=rx_ok_buff[1]& 0x0F; - MProtocol_id=MProtocol_id_master+RX_num;//personalized RX bind + rx num // rx_num bits 0---3 - } - else - if( ((rx_ok_buff[0]&0x80)!=0) && ((cur_protocol[0]&0x80)==0) ) // Bind flag has been set - CHANGE_PROTOCOL_FLAG_on; //restart protocol with bind - cur_protocol[0] = rx_ok_buff[0]; //store current protocol - - // decode channel values - volatile uint8_t *p=rx_ok_buff+2; - uint8_t dec=-3; - for(uint8_t i=0;i=8) - { - dec-=8; - p++; - } - p++; - Servo_data[i]=((((*((uint32_t *)p))>>dec)&0x7FF)*5)/8+860; //value range 860<->2140 -125%<->+125% - } - RX_DONOTUPDTAE_off; + if( ((rx_ok_buff[0]&0x5F) != (cur_protocol[0]&0x5F)) || ( (rx_ok_buff[1]&0x7F) != cur_protocol[1] ) ) + { // New model has been selected + prev_protocol=cur_protocol[0]&0x1F; //store previous protocol so we can reset the module + cur_protocol[1] = rx_ok_buff[1]&0x7F; //store current protocol + CHANGE_PROTOCOL_FLAG_on; //change protocol + sub_protocol=(rx_ok_buff[1]>>4)& 0x07; //subprotocol no (0-7) bits 4-6 + RX_num=rx_ok_buff[1]& 0x0F; + MProtocol_id=MProtocol_id_master+RX_num;//personalized RX bind + rx num // rx_num bits 0---3 } - while(IS_RX_MISSED_BUFF_on); // We've just processed an old frame... + else + if( ((rx_ok_buff[0]&0x80)!=0) && ((cur_protocol[0]&0x80)==0) ) // Bind flag has been set + CHANGE_PROTOCOL_FLAG_on; //restart protocol with bind + cur_protocol[0] = rx_ok_buff[0]; //store current protocol + + // decode channel values + volatile uint8_t *p=rx_ok_buff+2; + uint8_t dec=-3; + for(uint8_t i=0;i=8) + { + dec-=8; + p++; + } + p++; + Servo_data[i]=((((*((uint32_t *)p))>>dec)&0x7FF)*5)/8+860; //value range 860<->2140 -125%<->+125% + } + RX_DONOTUPDTAE_off; + #ifdef XMEGA + cli(); + #else + UCSR0B &= ~(1< Date: Tue, 30 Aug 2016 23:30:18 +0200 Subject: [PATCH 178/293] Update Protocols_Details.md --- Protocols_Details.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index f2f71f6..cd9cfea 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -55,7 +55,7 @@ Extended limits supported Telemetry enabled for A0, A1, RSSI, TSSI and Hub -Option=fine frequency tuning. This value is different for each board. To determine the option value, find the two limits where the RX loses connection then set the option value to half way between them. +Option=fine frequency tuning. This value is different for each board. To determine the option value, find the two limits where the RX loses connection then set the option value to half way between them. If you have a 4in1 V2 board the value is around 40. CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- @@ -68,7 +68,7 @@ Extended limits supported Telemetry enabled for A1 (RxBatt), A2, RSSI, TSSI and Hub -Option=fine frequency tuning. This value is different for each board. To determine the option value, find the two limits where the RX loses connection then set the option value to half way between them. +Option=fine frequency tuning. This value is different for each board. To determine the option value, find the two limits where the RX loses connection then set the option value to half way between them. If you have a 4in1 V2 board the value is around 40. ###Sub_protocol CH_16 CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16 @@ -83,7 +83,7 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ##SFHSS Models: Futaba RXs and XK models. -Option=fine frequency tuning. This value is different for each board. To determine the option value, find the two limits where the RX loses connection then set the option value to half way between them. +Option=fine frequency tuning. This value is different for each board. To determine the option value, find the two limits where the RX loses connection then set the option value to half way between them. If you have a 4in1 V2 board the value is around 40. CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- From 8b5bc181422dce1c17bc87c23ab4316901c5270a Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 31 Aug 2016 10:19:55 +0200 Subject: [PATCH 179/293] YD717 4-in-1 V2 compatibility --- Multiprotocol/YD717_nrf24l01.ino | 122 ++++++++----------------------- 1 file changed, 30 insertions(+), 92 deletions(-) diff --git a/Multiprotocol/YD717_nrf24l01.ino b/Multiprotocol/YD717_nrf24l01.ino index 1d9ffbe..3e1c4c5 100644 --- a/Multiprotocol/YD717_nrf24l01.ino +++ b/Multiprotocol/YD717_nrf24l01.ino @@ -34,13 +34,6 @@ #define YD717_PAYLOADSIZE 8 // receive data pipes set to this size, but unused -enum { - YD717_INIT1 = 0, - YD717_BIND2, - YD717_BIND3, - YD717_DATA -}; - static void __attribute__((unused)) yd717_send_packet(uint8_t bind) { uint8_t rudder_trim, elevator_trim, aileron_trim; @@ -132,119 +125,64 @@ static void __attribute__((unused)) yd717_init() // CRC, radio on NRF24L01_SetTxRxMode(TX_EN); NRF24L01_WriteReg(NRF24L01_00_CONFIG, BV(NRF24L01_00_EN_CRC) | BV(NRF24L01_00_PWR_UP)); - NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x3F); // Auto Acknoledgement on all data pipes - NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x3F); // Enable all data pipes - NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address - NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x1A); // 500uS retransmit t/o, 10 tries + NRF24L01_WriteReg(NRF24L01_01_EN_AA, 0x00); // Disable Acknoledgement on all data pipes + NRF24L01_WriteReg(NRF24L01_02_EN_RXADDR, 0x00); // Disable all data pipes + NRF24L01_WriteReg(NRF24L01_03_SETUP_AW, 0x03); // 5-byte RX/TX address + NRF24L01_WriteReg(NRF24L01_04_SETUP_RETR, 0x00); // No retransmit NRF24L01_WriteReg(NRF24L01_05_RF_CH, YD717_RF_CHANNEL); // Channel 3C - NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps + NRF24L01_SetBitrate(NRF24L01_BR_1M); // 1Mbps NRF24L01_SetPower(); - NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit - NRF24L01_WriteReg(NRF24L01_0C_RX_ADDR_P2, 0xC3); // LSB byte of pipe 2 receive address - NRF24L01_WriteReg(NRF24L01_0D_RX_ADDR_P3, 0xC4); - NRF24L01_WriteReg(NRF24L01_0E_RX_ADDR_P4, 0xC5); - NRF24L01_WriteReg(NRF24L01_0F_RX_ADDR_P5, 0xC6); - NRF24L01_WriteReg(NRF24L01_11_RX_PW_P0, YD717_PAYLOADSIZE); // bytes of data payload for pipe 1 - NRF24L01_WriteReg(NRF24L01_12_RX_PW_P1, YD717_PAYLOADSIZE); - NRF24L01_WriteReg(NRF24L01_13_RX_PW_P2, YD717_PAYLOADSIZE); - NRF24L01_WriteReg(NRF24L01_14_RX_PW_P3, YD717_PAYLOADSIZE); - NRF24L01_WriteReg(NRF24L01_15_RX_PW_P4, YD717_PAYLOADSIZE); - NRF24L01_WriteReg(NRF24L01_16_RX_PW_P5, YD717_PAYLOADSIZE); - NRF24L01_WriteReg(NRF24L01_17_FIFO_STATUS, 0x00); // Just in case, no real bits to write here + NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // Clear data ready, data sent, and retransmit - NRF24L01_Activate(0x73); // Activate feature register - NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3F); // Enable dynamic payload length on all pipes - NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07); // Set feature bits on + NRF24L01_Activate(0x73); // Activate feature register + NRF24L01_WriteReg(NRF24L01_1C_DYNPD, 0x3F); // Enable dynamic payload length on all pipes + NRF24L01_WriteReg(NRF24L01_1D_FEATURE, 0x07); // Set feature bits on NRF24L01_Activate(0x73); - // set tx id - NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5); - NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5); -} - -static void __attribute__((unused)) YD717_init1() -{ // for bind packets set address to prearranged value known to receiver uint8_t bind_rx_tx_addr[] = {0x65, 0x65, 0x65, 0x65, 0x65}; - uint8_t i; + if( sub_protocol==SYMAX4 ) - for(i=0; i < 5; i++) + for(uint8_t i=0; i < 5; i++) bind_rx_tx_addr[i] = 0x60; else if( sub_protocol==NIHUI ) - for(i=0; i < 5; i++) + for(uint8_t i=0; i < 5; i++) bind_rx_tx_addr[i] = 0x64; - NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, bind_rx_tx_addr, 5); NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, bind_rx_tx_addr, 5); } -static void __attribute__((unused)) YD717_init2() -{ - // set rx/tx address for data phase - NRF24L01_WriteRegisterMulti(NRF24L01_0A_RX_ADDR_P0, rx_tx_addr, 5); - NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5); -} - uint16_t yd717_callback() { - switch (phase) + if(IS_BIND_DONE_on) + yd717_send_packet(0); + else { - case YD717_INIT1: - yd717_send_packet(0); // receiver doesn't re-enter bind mode if connection lost...check if already bound - phase = YD717_BIND3; - break; - case YD717_BIND2: - if (counter == 0) - { - if (NRF24L01_packet_ack() == PKT_PENDING) - return YD717_PACKET_CHKTIME; // packet send not yet complete - YD717_init2(); // change to data phase rx/tx address - yd717_send_packet(0); - phase = YD717_BIND3; - } - else - { - if (NRF24L01_packet_ack() == PKT_PENDING) - return YD717_PACKET_CHKTIME; // packet send not yet complete; - yd717_send_packet(1); - counter--; - } - break; - case YD717_BIND3: - switch (NRF24L01_packet_ack()) - { - case PKT_PENDING: - return YD717_PACKET_CHKTIME; // packet send not yet complete - case PKT_ACKED: - phase = YD717_DATA; - BIND_DONE; // bind complete - break; - case PKT_TIMEOUT: - YD717_init1(); // change to bind rx/tx address - counter = YD717_BIND_COUNT; - phase = YD717_BIND2; - yd717_send_packet(1); - } - break; - case YD717_DATA: - if (NRF24L01_packet_ack() == PKT_PENDING) - return YD717_PACKET_CHKTIME; // packet send not yet complete + if (bind_counter == 0) + { + NRF24L01_WriteRegisterMulti(NRF24L01_10_TX_ADDR, rx_tx_addr, 5); // set address yd717_send_packet(0); - break; - } + BIND_DONE; // bind complete + } + else + { + yd717_send_packet(1); + bind_counter--; + } + } return YD717_PACKET_PERIOD; // Packet every 8ms } uint16_t initYD717() { - rx_tx_addr[4] = 0xC1; // always uses first data port + BIND_IN_PROGRESS; // autobind protocol + rx_tx_addr[4] = 0xC1; // always uses first data port yd717_init(); - phase = YD717_INIT1; - BIND_IN_PROGRESS; // autobind protocol + bind_counter = YD717_BIND_COUNT; // Call callback in 50ms return YD717_INITIAL_WAIT; } -#endif +#endif \ No newline at end of file From ece59ac3748d7d5079b3dcebbe128aef1758cf67 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 31 Aug 2016 10:20:56 +0200 Subject: [PATCH 180/293] FrSky ppm option value default 40 --- Multiprotocol/_Config.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 7e28880..3cb3996 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -147,7 +147,7 @@ const PPM_Parameters PPM_prot[15]= { // Dial Protocol Sub protocol RX_Num Power Auto Bind Option /* 1 */ {MODE_FLYSKY, Flysky , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 2 */ {MODE_HUBSAN, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, -/* 3 */ {MODE_FRSKY , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, // option=fine freq tuning +/* 3 */ {MODE_FRSKY , 0 , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning /* 4 */ {MODE_HISKY , Hisky , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 5 */ {MODE_V2X2 , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 6 */ {MODE_DSM2 , DSM2 , 0 , P_HIGH , NO_AUTOBIND , 2 }, // option=2=6 channels @ 22ms From b7b279961142dfeee728da4250ff48e20ffc34af Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 31 Aug 2016 10:22:36 +0200 Subject: [PATCH 181/293] FrSky option applied live --- Multiprotocol/FrSky_cc2500.ino | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Multiprotocol/FrSky_cc2500.ino b/Multiprotocol/FrSky_cc2500.ino index 6051524..6e00447 100644 --- a/Multiprotocol/FrSky_cc2500.ino +++ b/Multiprotocol/FrSky_cc2500.ino @@ -50,6 +50,7 @@ static void __attribute__((unused)) frsky2way_init(uint8_t bind) val=bind ? 0x43 : 0x03; CC2500_WriteReg(reg,val); } + prev_option = option ; CC2500_SetTxRxMode(TX_EN); CC2500_SetPower(); @@ -208,6 +209,11 @@ uint16_t ReadFrSky_2way() } CC2500_Strobe(CC2500_SIDLE); CC2500_WriteReg(CC2500_0A_CHANNR, get_chan_num(counter % 47)); + if ( prev_option != option ) + { + CC2500_WriteReg(CC2500_0C_FSCTRL0,option); // Frequency offset hack + prev_option = option ; + } CC2500_WriteReg(CC2500_23_FSCAL3, 0x89); CC2500_Strobe(CC2500_SFRX); frsky2way_data_frame(); From eabfd8b5c4544d2411e221689ab2385a4c317e6d Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 31 Aug 2016 10:26:27 +0200 Subject: [PATCH 182/293] Important changes of the scheduler and interrupts --- Multiprotocol/FrSkyX_cc2500.ino | 1 - Multiprotocol/Multiprotocol.h | 25 ++- Multiprotocol/Multiprotocol.ino | 367 ++++++++++++++++++-------------- Multiprotocol/Telemetry.ino | 9 +- 4 files changed, 233 insertions(+), 169 deletions(-) diff --git a/Multiprotocol/FrSkyX_cc2500.ino b/Multiprotocol/FrSkyX_cc2500.ino index ba5dfd5..3820432 100644 --- a/Multiprotocol/FrSkyX_cc2500.ino +++ b/Multiprotocol/FrSkyX_cc2500.ino @@ -252,7 +252,6 @@ uint16_t ReadFrSkyX() CC2500_WriteReg(CC2500_0C_FSCTRL0,option); // Frequency offset hack prev_option = option ; } - LED_ON; CC2500_SetTxRxMode(TX_EN); set_start(hopping_frequency_no); CC2500_SetPower(); diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 76840fd..220bbc6 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -273,10 +273,17 @@ struct PPM_Parameters #endif // TX -#define TX_ON PORTD |= _BV(1) -#define TX_OFF PORTD &= ~_BV(1) -#define TX_TOGGLE PORTD ^= _BV(1) -#define TX_SET_OUTPUT DDRD |= _BV(1) +#ifdef DEBUG_TX + #define TX_ON PORTD |= _BV(1) + #define TX_OFF PORTD &= ~_BV(1) + #define TX_TOGGLE PORTD ^= _BV(1) + #define TX_SET_OUTPUT DDRD |= _BV(1) +#else + #define TX_ON + #define TX_OFF + #define TX_TOGGLE + #define TX_SET_OUTPUT +#endif // Macros #define NOP() __asm__ __volatile__("nop") @@ -329,6 +336,16 @@ struct PPM_Parameters #define RX_MISSED_BUFF_on protocol_flags2 |= _BV(2) #define IS_RX_MISSED_BUFF_on ( ( protocol_flags2 & _BV(2) ) !=0 ) +#define TX_MAIN_PAUSE_off protocol_flags2 &= ~_BV(3) +#define TX_MAIN_PAUSE_on protocol_flags2 |= _BV(3) +#define IS_TX_MAIN_PAUSE_on ( ( protocol_flags2 & _BV(3) ) !=0 ) + +#define TX_RX_PAUSE_off protocol_flags2 &= ~_BV(4) +#define TX_RX_PAUSE_on protocol_flags2 |= _BV(4) +#define IS_TX_RX_PAUSE_on ( ( protocol_flags2 & _BV(4) ) !=0 ) + +#define IS_TX_PAUSE_on ( ( protocol_flags2 & (_BV(4)|_BV(3)) ) !=0 ) + #define BLINK_BIND_TIME 100 #define BLINK_SERIAL_TIME 500 #define BLINK_BAD_PROTO_TIME_LOW 1000 diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 2e4a37d..288af61 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -22,9 +22,8 @@ */ #include #include -#include "Multiprotocol.h" - //#define DEBUG_TX +#include "Multiprotocol.h" //Multiprotocol module configuration file #include "_Config.h" @@ -113,6 +112,7 @@ uint8_t prev_protocol=0; #define MAX_PKT 27 uint8_t pkt[MAX_PKT];//telemetry receiving packets #if defined(TELEMETRY) + uint8_t pass = 0; uint8_t pktt[MAX_PKT];//telemetry receiving packets #ifndef BASH_SERIAL volatile uint8_t tx_head=0; @@ -215,19 +215,8 @@ void setup() MProtocol_id_master=random_id(10,false); //Init RF modules - #ifdef CC2500_INSTALLED - CC2500_Reset(); - #endif - #ifdef A7105_INSTALLED - A7105_Reset(); - #endif - #ifdef CYRF6936_INSTALLED - CYRF_Reset(); - #endif - #ifdef NFR24L01_INSTALLED - NRF24L01_Reset(); - #endif - + modules_reset(); + #ifdef ENABLE_PPM //Protocol and interrupts initialization if(mode_select != MODE_SERIAL) @@ -271,8 +260,99 @@ void setup() } // Main +// Protocol scheduler void loop() +{ + uint16_t next_callback,diff=0xFFFF; + + while(1) + { + if(remote_callback==0 || diff>2*200) + { + do + { + Update_All(); + } + while(remote_callback==0); + } + #ifdef XMEGA + if( (TCC1.INTFLAGS & TC1_CCAIF_bm) != 0) + { + cli(); // Disable global int due to RW of 16 bits registers + TCC1.CCA = TCC1.CNT ; // Callback should already have been called... Use "now" as new sync point. + sei(); // Enable global int + } + else + while((TCC1.INTFLAGS & TC1_CCAIF_bm) == 0); // wait before callback + #else + if( (TIFR1 & (1<4000) + { // start to wait here as much as we can... + next_callback-=2000; // We will wait below for 2ms + #ifdef XMEGA + cli(); // Disable global int due to RW of 16 bits registers + TCC1.CCA +=2000*2; // set compare A for callback + TCC1.INTFLAGS = TC1_CCAIF_bm ; // clear compare A=callback flag + sei(); // enable global int + Update_All(); + if(IS_CHANGE_PROTOCOL_FLAG_on) + break; // Protocol has been changed + while((TCC1.INTFLAGS & TC1_CCAIF_bm) == 0); // wait 2ms... + #else + cli(); // Disable global int due to RW of 16 bits registers + OCR1A += 2000*2 ; // set compare A for callback + TIFR1=(1<4000) - { // start to wait here as much as we can... - next_callback-=2000; // We will wait below for 2ms -#ifdef XMEGA - cli(); // Disable global int due to RW of 16 bits registers - TCC1.CCA +=2000*2; // set compare A for callback - TCC1.INTFLAGS = TC1_CCAIF_bm ; // clear compare A=callback flag - sei(); // enable global int - while((TCC1.INTFLAGS & TC1_CCAIF_bm) == 0); // wait 2ms... -#else - cli(); // Disable global int due to RW of 16 bits registers - OCR1A += 2000*2 ; // set compare A for callback - TIFR1=(1<RXBUFFER_SIZE) { // A full frame has been received -#ifdef XMEGA - TCC1.INTCTRLB &=0xF3; // disable interrupt on compare B match -#else - TIMSK1 &=~(1< Date: Wed, 31 Aug 2016 15:43:45 +0200 Subject: [PATCH 183/293] FrSky 1way protocol + cosmetic --- Multiprotocol/A7105_SPI.ino | 24 ++--- Multiprotocol/FrSky1_cc2500.ino | 185 ++++++++++++++++++++++++++++++++ Multiprotocol/FrSky_cc2500.ino | 21 +--- Multiprotocol/Multiprotocol.h | 71 ++++++------ Multiprotocol/Multiprotocol.ino | 63 ++++++----- Multiprotocol/_Config.h | 3 + 6 files changed, 276 insertions(+), 91 deletions(-) create mode 100644 Multiprotocol/FrSky1_cc2500.ino diff --git a/Multiprotocol/A7105_SPI.ino b/Multiprotocol/A7105_SPI.ino index 30c022b..f5c83d2 100644 --- a/Multiprotocol/A7105_SPI.ino +++ b/Multiprotocol/A7105_SPI.ino @@ -23,12 +23,12 @@ void A7105_WriteData(uint8_t len, uint8_t channel) { uint8_t i; - CS_off; + A7105_CS_off; SPI_Write(A7105_RST_WRPTR); SPI_Write(0x05); for (i = 0; i < len; i++) SPI_Write(packet[i]); - CS_on; + A7105_CS_on; A7105_WriteReg(0x0F, channel); A7105_Strobe(A7105_TX); } @@ -36,27 +36,27 @@ void A7105_WriteData(uint8_t len, uint8_t channel) void A7105_ReadData() { uint8_t i; A7105_Strobe(0xF0); //A7105_RST_RDPTR - CS_off; + A7105_CS_off; SPI_Write(0x45); for (i=0;i<16;i++) packet[i]=A7105_Read(); - CS_on; + A7105_CS_on; } void A7105_WriteReg(uint8_t address, uint8_t data) { - CS_off; + A7105_CS_off; SPI_Write(address); NOP(); SPI_Write(data); - CS_on; + A7105_CS_on; } uint8_t A7105_ReadReg(uint8_t address) { uint8_t result; - CS_off; + A7105_CS_off; SPI_Write(address |=0x40); //bit 6 =1 for reading result = A7105_Read(); - CS_on; + A7105_CS_on; return(result); } @@ -110,13 +110,13 @@ uint8_t A7105_Reset() } void A7105_WriteID(uint32_t ida) { - CS_off; + A7105_CS_off; SPI_Write(0x06);//ex id=0x5475c52a ;txid3txid2txid1txid0 SPI_Write((ida>>24)&0xff);//53 SPI_Write((ida>>16)&0xff);//75 SPI_Write((ida>>8)&0xff);//c5 SPI_Write((ida>>0)&0xff);//2a - CS_on; + A7105_CS_on; } /* @@ -162,9 +162,9 @@ void A7105_SetPower() } void A7105_Strobe(uint8_t address) { - CS_off; + A7105_CS_off; SPI_Write(address); - CS_on; + A7105_CS_on; } const uint8_t PROGMEM HUBSAN_A7105_regs[] = { diff --git a/Multiprotocol/FrSky1_cc2500.ino b/Multiprotocol/FrSky1_cc2500.ino new file mode 100644 index 0000000..9df5988 --- /dev/null +++ b/Multiprotocol/FrSky1_cc2500.ino @@ -0,0 +1,185 @@ +/* + 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(FRSKY1_CC2500_INO) + +#include "iface_cc2500.h" + +static void __attribute__((unused)) FRSKY1_init() +{ + CC2500_WriteReg(CC2500_17_MCSM1, 0x0c); + CC2500_WriteReg(CC2500_18_MCSM0, 0x18); + CC2500_WriteReg(CC2500_06_PKTLEN, 0xff); + CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x04); + CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x05); + CC2500_WriteReg(CC2500_3E_PATABLE, 0xfe); + CC2500_WriteReg(CC2500_0B_FSCTRL1, 0x08); + CC2500_WriteReg(CC2500_0C_FSCTRL0, option); + CC2500_WriteReg(CC2500_0D_FREQ2, 0x5c); + CC2500_WriteReg(CC2500_0E_FREQ1, 0x58); + CC2500_WriteReg(CC2500_0F_FREQ0, 0x9d); + CC2500_WriteReg(CC2500_10_MDMCFG4, 0xaa); + CC2500_WriteReg(CC2500_11_MDMCFG3, 0x10); + CC2500_WriteReg(CC2500_12_MDMCFG2, 0x93); + CC2500_WriteReg(CC2500_13_MDMCFG1, 0x23); + CC2500_WriteReg(CC2500_14_MDMCFG0, 0x7a); + CC2500_WriteReg(CC2500_15_DEVIATN, 0x41); + for(uint8_t i=19;i<36;i++) + { + uint8_t reg=pgm_read_byte_near(&cc2500_conf[i][0]); + uint8_t val=pgm_read_byte_near(&cc2500_conf[i][1]); + CC2500_WriteReg(reg,val); + } + + CC2500_SetTxRxMode(TX_EN); + CC2500_SetPower(); + + CC2500_Strobe(CC2500_SIDLE); // Go to idle... + prev_option = option ; +} + +static uint8_t __attribute__((unused)) FRSKY1_crc8(uint8_t result, uint8_t *data, uint8_t len, uint8_t polynomial) +{ + for(uint8_t i = 0; i < len; i++) + { + result = result ^ data[i]; + for(uint8_t j = 0; j < 8; j++) + if(result & 0x80) + result = (result << 1) ^ polynomial; + else + result = result << 1; + } + return result; +} + +static uint8_t __attribute__((unused)) FRSKY1_crc8_le(uint8_t init, u8 *data, uint8_t len) +{ + uint8_t result = 0; + + for(uint8_t i = 0; i < 8; i++) + { + result = (result << 1) | (init & 0x01); + init >>= 1; + } + return FRSKY1_crc8(result,data,len,0x83); +} + +static void __attribute__((unused)) FRSKY1_build_bind_packet() +{ + //0e 03 01 57 12 00 06 0b 10 15 1a 00 00 00 61 + packet[0] = 0x0e; //Length + packet[1] = 0x03; //Packet type + packet[2] = 0x01; //Packet type + packet[3] = rx_tx_addr[3]; + packet[4] = rx_tx_addr[2]; + packet[5] = ((state - FRSKY_BIND) % 10) * 5; + packet[6] = packet[5] * 5 + 6; + packet[7] = packet[5] * 5 + 11; + packet[8] = packet[5] * 5 + 16; + packet[9] = packet[5] * 5 + 21; + packet[10] = packet[5] * 5 + 26; + packet[11] = 0x00; + packet[12] = 0x00; + packet[13] = 0x00; + packet[14] = FRSKY1_crc8(0x93, packet, 14, 0x07); +} + +static uint8_t __attribute__((unused)) FRSKY1_calc_channel() +{ + uint32_t temp=seed; + temp = (temp * 0xaa) % 0x7673; + seed = temp; + return (seed & 0xff) % 0x32; +} + +static void __attribute__((unused)) FRSKY1_build_data_packet() +{ + packet[0] = 0x0e; + packet[1] = rx_tx_addr[3]; + packet[2] = rx_tx_addr[2]; + packet[3] = seed & 0xff; + packet[4] = seed >> 8; + if (state == FRSKY_DATA1 || state == FRSKY_DATA3) + packet[5] = 0x0f; + else + if(state == FRSKY_DATA2 || state == FRSKY_DATA4) + packet[5] = 0xf0; + else + packet[5] = 0x00; + uint8_t idx = 0; //= (state == FRSKY_DATA1) ? 4 : 0; + for(uint8_t i = 0; i < 4; i++) + { + uint16_t value = convert_channel_frsky(i+idx); + packet[2*i + 6] = value & 0xff; + packet[2*i + 7] = value >> 8; + } + packet[14] = FRSKY1_crc8(crc8, packet, 14, 0x07); +} + +static uint16_t ReadFRSKY1() +{ + if (state < FRSKY_BIND_DONE) + { + FRSKY1_build_bind_packet(); + CC2500_Strobe(CC2500_SIDLE); + CC2500_WriteReg(CC2500_0A_CHANNR, 0x00); + CC2500_WriteData(packet, packet[0]+1); + state++; + return 53460; + } + if (state == FRSKY_BIND_DONE) + { + state++; + BIND_DONE; + } + if (state >= FRSKY_DATA1) + { + CC2500_Strobe(CC2500_SIDLE); + if (option != prev_option) + { + CC2500_WriteReg(CC2500_0C_FSCTRL0, option); + prev_option=option; + } + uint8_t chan = FRSKY1_calc_channel(); + CC2500_WriteReg(CC2500_0A_CHANNR, chan * 5 + 6); + FRSKY1_build_data_packet(); + + CC2500_WriteData(packet, packet[0]+1); + if (state == FRSKY_DATA5) + { + CC2500_SetPower(); + state = FRSKY_DATA1; + } + else + state++; + return 9006; + } + return 0; +} + +uint16_t initFRSKY1() +{ + //u8 data[2] = {(fixed_id >> 8) & 0xff, fixed_id & 0xff}; + crc8 = FRSKY1_crc8_le(0x6b, rx_tx_addr+2, 2); // Use rx_tx_addr[2] and rx_tx_addr[3] since we want to use RX_Num + FRSKY1_init(); + seed = 1; + if(IS_AUTOBIND_FLAG_on) + state = FRSKY_BIND; + else + state = FRSKY_DATA1; + return 10000; +} + +#endif diff --git a/Multiprotocol/FrSky_cc2500.ino b/Multiprotocol/FrSky_cc2500.ino index 6e00447..78bbc89 100644 --- a/Multiprotocol/FrSky_cc2500.ino +++ b/Multiprotocol/FrSky_cc2500.ino @@ -17,26 +17,9 @@ #include "iface_cc2500.h" -//##########Variables######## -//uint32_t state; -//uint8_t len; - -/* -enum { - FRSKY_BIND = 0, - FRSKY_BIND_DONE = 1000, - FRSKY_DATA1, - FRSKY_DATA2, - FRSKY_DATA3, - FRSKY_DATA4, - FRSKY_DATA5 -}; -*/ - static void __attribute__((unused)) frsky2way_init(uint8_t bind) { // Configure cc2500 for tx mode - CC2500_Reset(); // for(uint8_t i=0;i<36;i++) { @@ -142,9 +125,9 @@ static void __attribute__((unused)) frsky2way_data_frame() uint16_t initFrSky_2way() { if(IS_AUTOBIND_FLAG_on) - { + { frsky2way_init(1); - state = FRSKY_BIND;// + state = FRSKY_BIND; } else { diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 220bbc6..6e2d64c 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -52,7 +52,8 @@ enum PROTOCOLS MODE_SFHSS = 21, // =>CC2500 MODE_J6PRO = 22, // =>CYRF6936 MODE_FQ777 = 23, // =>NRF24L01 - MODE_ASSAN = 24 // =>NRF24L01 + MODE_ASSAN = 24, // =>NRF24L01 + MODE_FRSKY1 = 25 // =>CC2500 }; enum Flysky @@ -148,21 +149,22 @@ struct PPM_Parameters //******************* //*** Pinouts *** //******************* -#define LED_pin 13 //Promini original led on B5 -#define PPM_pin 3 //PPM-D3 +#define LED_pin 5 //D13 = PB5 +#define BIND_pin 5 //D13 = PB5 +#define PPM_pin 3 //D3 = PD3 #ifdef XMEGA - #define SDI_pin 6 //SDIO-D6 + #define SDI_pin 6 //SDIO-D6 #else - #define SDI_pin 5 //SDIO-D5 + #define SDI_pin 5 //D5 = PD5 #endif -#define SCLK_pin 4 //SCK-D4 -#define CS_pin 2 //CS-D2 -#define SDO_pin 6 //D6 -#define CC25_CSN_pin 7 -#define NRF_CSN_pin 8 -#define CYRF_CSN_pin 9 -#define CTRL1 1 //C1 (A1) -#define CTRL2 2 //C2 (A2) +#define SCLK_pin 4 //D4 = PD4 +#define A7105_CS_pin 2 //D2 = PD2 +#define SDO_pin 6 //D6 = PD6 +#define CC25_CSN_pin 7 //D7 = PD7 +#define NRF_CSN_pin 0 //D8 = PB0 +#define CYRF_CSN_pin 1 //D9 = PB1 +#define CTRL1_pin 1 //A1 = PC1 +#define CTRL2_pin 2 //A2 = PC2 // #ifdef XMEGA #define CTRL1_on @@ -177,39 +179,39 @@ struct PPM_Parameters #endif // #ifdef XMEGA - #define CS_on PORTD.OUTSET = _BV(4) //D4 - #define CS_off PORTD.OUTCLR = _BV(4) //D4 + #define A7105_CS_on PORTD.OUTSET = _BV(4) //D4 + #define A7105_CS_off PORTD.OUTCLR = _BV(4) //D4 #else - #define CS_on PORTD |= _BV(2) //D2 - #define CS_off PORTD &= ~_BV(2) //D2 + #define A7105_CS_on PORTD |= _BV(2) //D2 + #define A7105_CS_off PORTD &= ~_BV(2) //D2 #endif // #ifdef XMEGA - #define SCK_on PORTD.OUTSET = _BV(7) //D7 + #define SCK_on PORTD.OUTSET = _BV(7) //D7 #define SCK_off PORTD.OUTCLR = _BV(7) //D7 #else - #define SCK_on PORTD |= _BV(4) //D4 - #define SCK_off PORTD &= ~_BV(4) //D4 + #define SCK_on PORTD |= _BV(4) //D4 + #define SCK_off PORTD &= ~_BV(4) //D4 #endif // #ifdef XMEGA - #define SDI_on PORTD.OUTSET = _BV(5) //D5 + #define SDI_on PORTD.OUTSET = _BV(5) //D5 #define SDI_off PORTD.OUTCLR = _BV(5) //D5 #else - #define SDI_on PORTD |= _BV(5) //D5 - #define SDI_off PORTD &= ~_BV(5) //D5 + #define SDI_on PORTD |= _BV(5) //D5 + #define SDI_off PORTD &= ~_BV(5) //D5 #endif // #ifdef XMEGA - #define SDI_1 (PORTD.IN & (1< 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 288af61..4d43874 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -64,6 +64,8 @@ uint8_t rf_ch_num; uint8_t throttle, rudder, elevator, aileron; uint8_t flags; uint16_t crc; +uint8_t crc8; +uint16_t seed; // uint16_t state; uint8_t len; @@ -148,16 +150,15 @@ void setup() PORTE.OUTCLR = 0x01 ; #else // General pinout - DDRD = (1< Date: Wed, 31 Aug 2016 15:54:24 +0200 Subject: [PATCH 184/293] FrSky1 optim --- Multiprotocol/FrSky1_cc2500.ino | 46 ++++++++++++++++++++------------- Multiprotocol/Multiprotocol.h | 3 +-- Multiprotocol/Multiprotocol.ino | 2 +- 3 files changed, 30 insertions(+), 21 deletions(-) diff --git a/Multiprotocol/FrSky1_cc2500.ino b/Multiprotocol/FrSky1_cc2500.ino index 9df5988..d883ccd 100644 --- a/Multiprotocol/FrSky1_cc2500.ino +++ b/Multiprotocol/FrSky1_cc2500.ino @@ -16,26 +16,37 @@ #if defined(FRSKY1_CC2500_INO) #include "iface_cc2500.h" +const PROGMEM uint8_t FRSKY1_cc2500_conf[][2]={ + { CC2500_17_MCSM1, 0x0c }, + { CC2500_18_MCSM0, 0x18 }, + { CC2500_06_PKTLEN, 0xff }, + { CC2500_07_PKTCTRL1, 0x04 }, + { CC2500_08_PKTCTRL0, 0x05 }, + { CC2500_3E_PATABLE, 0xfe }, + { CC2500_0B_FSCTRL1, 0x08 }, + { CC2500_0C_FSCTRL0, 0x00 }, + { CC2500_0D_FREQ2, 0x5c }, + { CC2500_0E_FREQ1, 0x58 }, + { CC2500_0F_FREQ0, 0x9d }, + { CC2500_10_MDMCFG4, 0xaa }, + { CC2500_11_MDMCFG3, 0x10 }, + { CC2500_12_MDMCFG2, 0x93 }, + { CC2500_13_MDMCFG1, 0x23 }, + { CC2500_14_MDMCFG0, 0x7a }, + { CC2500_15_DEVIATN, 0x41 } +}; static void __attribute__((unused)) FRSKY1_init() { - CC2500_WriteReg(CC2500_17_MCSM1, 0x0c); - CC2500_WriteReg(CC2500_18_MCSM0, 0x18); - CC2500_WriteReg(CC2500_06_PKTLEN, 0xff); - CC2500_WriteReg(CC2500_07_PKTCTRL1, 0x04); - CC2500_WriteReg(CC2500_08_PKTCTRL0, 0x05); - CC2500_WriteReg(CC2500_3E_PATABLE, 0xfe); - CC2500_WriteReg(CC2500_0B_FSCTRL1, 0x08); - CC2500_WriteReg(CC2500_0C_FSCTRL0, option); - CC2500_WriteReg(CC2500_0D_FREQ2, 0x5c); - CC2500_WriteReg(CC2500_0E_FREQ1, 0x58); - CC2500_WriteReg(CC2500_0F_FREQ0, 0x9d); - CC2500_WriteReg(CC2500_10_MDMCFG4, 0xaa); - CC2500_WriteReg(CC2500_11_MDMCFG3, 0x10); - CC2500_WriteReg(CC2500_12_MDMCFG2, 0x93); - CC2500_WriteReg(CC2500_13_MDMCFG1, 0x23); - CC2500_WriteReg(CC2500_14_MDMCFG0, 0x7a); - CC2500_WriteReg(CC2500_15_DEVIATN, 0x41); + for(uint8_t i=0;i<17;i++) + { + uint8_t reg=pgm_read_byte_near(&FRSKY1_cc2500_conf[i][0]); + uint8_t val=pgm_read_byte_near(&FRSKY1_cc2500_conf[i][1]); + if(reg==CC2500_0C_FSCTRL0) + val=option; + CC2500_WriteReg(reg,val); + } + prev_option = option ; for(uint8_t i=19;i<36;i++) { uint8_t reg=pgm_read_byte_near(&cc2500_conf[i][0]); @@ -47,7 +58,6 @@ static void __attribute__((unused)) FRSKY1_init() CC2500_SetPower(); CC2500_Strobe(CC2500_SIDLE); // Go to idle... - prev_option = option ; } static uint8_t __attribute__((unused)) FRSKY1_crc8(uint8_t result, uint8_t *data, uint8_t len, uint8_t polynomial) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 6e2d64c..bbb24ac 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -232,13 +232,12 @@ struct PPM_Parameters #ifdef XMEGA #define CYRF_CSN_on PORTD.OUTSET = _BV(4) #define CYRF_CSN_off PORTD.OUTCLR = _BV(4) - #define CYRF_RST 0 #else #define CYRF_CSN_on PORTB |= _BV(1) //D9 #define CYRF_CSN_off PORTB &= ~_BV(1) //D9 #define CYRF_RST_HI PORTC |= _BV(5) //A5 #define CYRF_RST_LO PORTC &= ~_BV(5) //A5 - #define CYRF_RST 5 + #define CYRF_RST_pin 5 #endif // #ifdef XMEGA diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 4d43874..053e988 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -151,7 +151,7 @@ void setup() #else // General pinout DDRD = _BV(A7105_CS_pin)|_BV(SDI_pin)|_BV(SCLK_pin)|_BV( CC25_CSN_pin);//pin output - DDRC = _BV(CTRL1_pin)|_BV(CTRL2_pin)|_BV(CYRF_RST); //pin output + DDRC = _BV(CTRL1_pin)|_BV(CTRL2_pin)|_BV(CYRF_RST_pin); //pin output DDRB = _BV(NRF_CSN_pin)|_BV(CYRF_CSN_pin); //pin output PORTB = _BV(2)|_BV(3)|_BV(4)|_BV(BIND_pin); //pullup on dial (D10=PB2,D11=PB3,D12=PB4) and bind button PORTC = _BV(0); //pullup on dial (A0=PC0) From 942dec81c7b1c5c5c358ab5fe9d6fadb33fff61a Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 1 Sep 2016 08:08:00 +0200 Subject: [PATCH 185/293] Typo --- Multiprotocol/FrSky1_cc2500.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Multiprotocol/FrSky1_cc2500.ino b/Multiprotocol/FrSky1_cc2500.ino index d883ccd..df948a7 100644 --- a/Multiprotocol/FrSky1_cc2500.ino +++ b/Multiprotocol/FrSky1_cc2500.ino @@ -74,7 +74,7 @@ static uint8_t __attribute__((unused)) FRSKY1_crc8(uint8_t result, uint8_t *data return result; } -static uint8_t __attribute__((unused)) FRSKY1_crc8_le(uint8_t init, u8 *data, uint8_t len) +static uint8_t __attribute__((unused)) FRSKY1_crc8_le(uint8_t init, uint8_t *data, uint8_t len) { uint8_t result = 0; From 8150504ea0467a8fcc4af222670da6dfc70d98a0 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 1 Sep 2016 13:05:56 +0200 Subject: [PATCH 186/293] NRF CE --- Multiprotocol/Multiprotocol.h | 8 ++++++-- Multiprotocol/Multiprotocol.ino | 1 - Multiprotocol/NRF24l01_SPI.ino | 12 ++++++------ 3 files changed, 12 insertions(+), 9 deletions(-) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index bbb24ac..f4eccd3 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -224,9 +224,13 @@ struct PPM_Parameters #ifdef XMEGA #define NRF_CSN_on #define NRF_CSN_off + #define NRF_CE_on + #define NRF_CE_off #else - #define NRF_CSN_on PORTB |= _BV(0) //D8 - #define NRF_CSN_off PORTB &= ~_BV(0) //D8 + #define NRF_CSN_on PORTB |= _BV(0) //D8 + #define NRF_CSN_off PORTB &= ~_BV(0) //D8 + #define NRF_CE_on + #define NRF_CE_off #endif // #ifdef XMEGA diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 053e988..e8b72fa 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -130,7 +130,6 @@ uint8_t pkt[MAX_PKT];//telemetry receiving packets // Callback typedef uint16_t (*void_function_t) (void);//pointer to a function with no parameters which return an uint16_t integer void_function_t remote_callback = 0; -static void CheckTimer(uint16_t (*cb)(void)); // Init void setup() diff --git a/Multiprotocol/NRF24l01_SPI.ino b/Multiprotocol/NRF24l01_SPI.ino index 4b03ffb..579cffa 100644 --- a/Multiprotocol/NRF24l01_SPI.ino +++ b/Multiprotocol/NRF24l01_SPI.ino @@ -160,7 +160,7 @@ void NRF24L01_SetPower() void NRF24L01_SetTxRxMode(enum TXRX_State mode) { if(mode == TX_EN) { - NRF_CSN_off; + NRF_CE_off; NRF24L01_WriteReg(NRF24L01_07_STATUS, (1 << NRF24L01_07_RX_DR) //reset the flag(s) | (1 << NRF24L01_07_TX_DS) | (1 << NRF24L01_07_MAX_RT)); @@ -168,11 +168,11 @@ void NRF24L01_SetTxRxMode(enum TXRX_State mode) | (1 << NRF24L01_00_CRCO) | (1 << NRF24L01_00_PWR_UP)); delayMicroseconds(130); - NRF_CSN_on; + NRF_CE_on; } else if (mode == RX_EN) { - NRF_CSN_off; + NRF_CE_off; NRF24L01_WriteReg(NRF24L01_07_STATUS, 0x70); // reset the flag(s) NRF24L01_WriteReg(NRF24L01_00_CONFIG, 0x0F); // switch to RX mode NRF24L01_WriteReg(NRF24L01_07_STATUS, (1 << NRF24L01_07_RX_DR) //reset the flag(s) @@ -183,12 +183,12 @@ void NRF24L01_SetTxRxMode(enum TXRX_State mode) | (1 << NRF24L01_00_PWR_UP) | (1 << NRF24L01_00_PRIM_RX)); delayMicroseconds(130); - NRF_CSN_on; + NRF_CE_on; } else { NRF24L01_WriteReg(NRF24L01_00_CONFIG, (1 << NRF24L01_00_EN_CRC)); //PowerDown - NRF_CSN_off; + NRF_CE_off; } } @@ -204,7 +204,7 @@ void NRF24L01_Reset() NRF24L01_FlushTx(); NRF24L01_FlushRx(); NRF24L01_Strobe(0xff); // NOP - NRF24L01_ReadReg(0x07); + NRF24L01_ReadReg(NRF24L01_07_STATUS); NRF24L01_SetTxRxMode(TXRX_OFF); delayMicroseconds(100); } From 97956b6c5eafd4e05a4cea37a47eceaadedde8e7 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 1 Sep 2016 13:42:33 +0200 Subject: [PATCH 187/293] FrSky1 CRC messed up... --- Multiprotocol/FrSky1_cc2500.ino | 28 ++++++++++++++++++---------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/Multiprotocol/FrSky1_cc2500.ino b/Multiprotocol/FrSky1_cc2500.ino index df948a7..53d056c 100644 --- a/Multiprotocol/FrSky1_cc2500.ino +++ b/Multiprotocol/FrSky1_cc2500.ino @@ -60,14 +60,14 @@ static void __attribute__((unused)) FRSKY1_init() CC2500_Strobe(CC2500_SIDLE); // Go to idle... } -static uint8_t __attribute__((unused)) FRSKY1_crc8(uint8_t result, uint8_t *data, uint8_t len, uint8_t polynomial) +static uint8_t __attribute__((unused)) FRSKY1_crc8(uint8_t result, uint8_t *data, uint8_t len) { for(uint8_t i = 0; i < len; i++) { result = result ^ data[i]; for(uint8_t j = 0; j < 8; j++) if(result & 0x80) - result = (result << 1) ^ polynomial; + result = (result << 1) ^ 0x07; else result = result << 1; } @@ -83,7 +83,15 @@ static uint8_t __attribute__((unused)) FRSKY1_crc8_le(uint8_t init, uint8_t *dat result = (result << 1) | (init & 0x01); init >>= 1; } - return FRSKY1_crc8(result,data,len,0x83); + for(uint8_t i = 0; i < len; i++) + { + result = result ^ data[i]; + for(uint8_t j = 0; j < 8; j++) + if(result & 0x01) + result = (result >> 1) ^ 0x83; + else + result = result >> 1; + } } static void __attribute__((unused)) FRSKY1_build_bind_packet() @@ -103,7 +111,7 @@ static void __attribute__((unused)) FRSKY1_build_bind_packet() packet[11] = 0x00; packet[12] = 0x00; packet[13] = 0x00; - packet[14] = FRSKY1_crc8(0x93, packet, 14, 0x07); + packet[14] = FRSKY1_crc8(0x93, packet, 14); } static uint8_t __attribute__((unused)) FRSKY1_calc_channel() @@ -135,7 +143,7 @@ static void __attribute__((unused)) FRSKY1_build_data_packet() packet[2*i + 6] = value & 0xff; packet[2*i + 7] = value >> 8; } - packet[14] = FRSKY1_crc8(crc8, packet, 14, 0x07); + packet[14] = FRSKY1_crc8(crc8, packet, 14); } static uint16_t ReadFRSKY1() @@ -157,11 +165,6 @@ static uint16_t ReadFRSKY1() if (state >= FRSKY_DATA1) { CC2500_Strobe(CC2500_SIDLE); - if (option != prev_option) - { - CC2500_WriteReg(CC2500_0C_FSCTRL0, option); - prev_option=option; - } uint8_t chan = FRSKY1_calc_channel(); CC2500_WriteReg(CC2500_0A_CHANNR, chan * 5 + 6); FRSKY1_build_data_packet(); @@ -169,6 +172,11 @@ static uint16_t ReadFRSKY1() CC2500_WriteData(packet, packet[0]+1); if (state == FRSKY_DATA5) { + if (option != prev_option) + { + CC2500_WriteReg(CC2500_0C_FSCTRL0, option); + prev_option=option; + } CC2500_SetPower(); state = FRSKY_DATA1; } From d7825e1bf8adbb63ad94e8a0453c81f901eb63b1 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 1 Sep 2016 13:47:42 +0200 Subject: [PATCH 188/293] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index f6dcb69..24a06a6 100644 --- a/README.md +++ b/README.md @@ -162,6 +162,7 @@ Hubsan| Protocol|Sub_protocol --------|------------ FrSky| +FrSky1| FrSkyX| |CH_16 |CH_8 From bd0644a261f0600921f038df0ca67c4cd54f1728 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 1 Sep 2016 13:53:10 +0200 Subject: [PATCH 189/293] Update Protocols_Details.md --- Protocols_Details.md | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index cd9cfea..2d7c87d 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -51,6 +51,7 @@ A|E|T|R|FLIP|LIGHT|PICTURE|VIDEO|HEADLESS #CC2500 RF Module ##FRSKY +Models: FrSky receivers D4R and D8R. DIY RX-F801 and RX-F802. Extended limits supported Telemetry enabled for A0, A1, RSSI, TSSI and Hub @@ -61,6 +62,16 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +##FRSKY1 = FrSky 1 way +Models: FrSky receivers V8R4, V8R7 and V8FR. +Extended limits supported + +Option=fine frequency tuning. This value is different for each board. To determine the option value, find the two limits where the RX loses connection then set the option value to half way between them. If you have a 4in1 V2 board the value is around 40. + +CH1|CH2|CH3|CH4 +---|---|---|--- +CH1|CH2|CH3|CH4 + ##FRSKYX Models: FrSky receivers X4R, X6R and X8R. From 6e59897587c14c3f1e890b5bc16f1c8db8901c32 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 1 Sep 2016 13:53:48 +0200 Subject: [PATCH 190/293] Update Protocols_Details.md --- Protocols_Details.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 2d7c87d..e29b576 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -51,7 +51,8 @@ A|E|T|R|FLIP|LIGHT|PICTURE|VIDEO|HEADLESS #CC2500 RF Module ##FRSKY -Models: FrSky receivers D4R and D8R. DIY RX-F801 and RX-F802. +Models: FrSky receivers D4R and D8R. DIY RX-F801 and RX-F802 receivers. + Extended limits supported Telemetry enabled for A0, A1, RSSI, TSSI and Hub @@ -64,6 +65,7 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ##FRSKY1 = FrSky 1 way Models: FrSky receivers V8R4, V8R7 and V8FR. + Extended limits supported Option=fine frequency tuning. This value is different for each board. To determine the option value, find the two limits where the RX loses connection then set the option value to half way between them. If you have a 4in1 V2 board the value is around 40. From e51615f520b28dee5c286055b992bf20b9f56228 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 1 Sep 2016 14:00:42 +0200 Subject: [PATCH 191/293] DSM2 renamed to DSM --- Multiprotocol/{DSM2_cyrf6936.ino => DSM_cyrf6936.ino} | 6 +++--- Multiprotocol/FrSky1_cc2500.ino | 1 + Multiprotocol/Multiprotocol.h | 10 +++++----- Multiprotocol/Multiprotocol.ino | 10 +++++----- Multiprotocol/Telemetry.ino | 8 ++++---- Multiprotocol/_Config.h | 8 ++++---- 6 files changed, 22 insertions(+), 21 deletions(-) rename Multiprotocol/{DSM2_cyrf6936.ino => DSM_cyrf6936.ino} (99%) diff --git a/Multiprotocol/DSM2_cyrf6936.ino b/Multiprotocol/DSM_cyrf6936.ino similarity index 99% rename from Multiprotocol/DSM2_cyrf6936.ino rename to Multiprotocol/DSM_cyrf6936.ino index 85f8029..f1c213e 100644 --- a/Multiprotocol/DSM2_cyrf6936.ino +++ b/Multiprotocol/DSM_cyrf6936.ino @@ -13,7 +13,7 @@ along with Multiprotocol. If not, see . */ -#if defined(DSM2_CYRF6936_INO) +#if defined(DSM_CYRF6936_INO) #include "iface_cyrf6936.h" @@ -408,7 +408,7 @@ static void __attribute__((unused)) calc_dsmx_channel() } } -uint16_t ReadDsm2() +uint16_t ReadDsm() { #define DSM_CH1_CH2_DELAY 4010 // Time between write of channel 1 and channel 2 #define DSM_WRITE_DELAY 1550 // Time after write to verify write complete @@ -536,7 +536,7 @@ uint16_t ReadDsm2() return 0; } -uint16_t initDsm2() +uint16_t initDsm() { CYRF_Reset(); CYRF_GetMfgData(cyrfmfg_id);// diff --git a/Multiprotocol/FrSky1_cc2500.ino b/Multiprotocol/FrSky1_cc2500.ino index 53d056c..ac6558d 100644 --- a/Multiprotocol/FrSky1_cc2500.ino +++ b/Multiprotocol/FrSky1_cc2500.ino @@ -92,6 +92,7 @@ static uint8_t __attribute__((unused)) FRSKY1_crc8_le(uint8_t init, uint8_t *dat else result = result >> 1; } + return result; } static void __attribute__((unused)) FRSKY1_build_bind_packet() diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index f4eccd3..a4e0941 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -34,7 +34,7 @@ enum PROTOCOLS MODE_FRSKY = 3, // =>CC2500 MODE_HISKY = 4, // =>NRF24L01 MODE_V2X2 = 5, // =>NRF24L01 - MODE_DSM2 = 6, // =>CYRF6936 + MODE_DSM = 6, // =>CYRF6936 MODE_DEVO = 7, // =>CYRF6936 MODE_YD717 = 8, // =>NRF24L01 MODE_KN = 9, // =>NRF24L01 @@ -68,7 +68,7 @@ enum Hisky Hisky = 0, HK310 = 1 }; -enum DSM2 +enum DSM { DSM2 = 0, DSMX = 1 @@ -460,7 +460,7 @@ enum CYRF_POWER #define CYRF_HIGH_POWER CYRF_POWER_7 #define CYRF_LOW_POWER CYRF_POWER_3 #define CYRF_RANGE_POWER CYRF_POWER_1 // 1/30 of the full power distance -#define CYRF_BIND_POWER CYRF_POWER_1 +#define CYRF_BIND_POWER CYRF_POWER_0 enum TXRX_State { TXRX_OFF, @@ -498,7 +498,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- Frsky 3 Hisky 4 V2x2 5 - DSM2 6 + DSM 6 Devo 7 YD717 8 KN 9 @@ -532,7 +532,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- sub_protocol==Hisky Hisky 0 HK310 1 - sub_protocol==DSM2 + sub_protocol==DSM DSM2 0 DSMX 1 sub_protocol==YD717 diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index e8b72fa..5f15ad0 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -386,7 +386,7 @@ TX_OFF; update_led_status(); #if defined(TELEMETRY) uint8_t protocol=cur_protocol[0]&0x1F; - if( (protocol==MODE_FRSKY) || (protocol==MODE_HUBSAN) || (protocol==MODE_FRSKYX) || (protocol==MODE_DSM2) ) + if( (protocol==MODE_FRSKY) || (protocol==MODE_HUBSAN) || (protocol==MODE_FRSKYX) || (protocol==MODE_DSM) ) TelemetryUpdate(); #endif TX_ON; @@ -529,12 +529,12 @@ static void protocol_init() remote_callback = ReadSFHSS; break; #endif -#if defined(DSM2_CYRF6936_INO) - case MODE_DSM2: +#if defined(DSM_CYRF6936_INO) + case MODE_DSM: CTRL2_on; //antenna RF4 - next_callback = initDsm2(); + next_callback = initDsm(); //Servo_data[2]=1500;//before binding - remote_callback = ReadDsm2; + remote_callback = ReadDsm; break; #endif #if defined(DEVO_CYRF6936_INO) diff --git a/Multiprotocol/Telemetry.ino b/Multiprotocol/Telemetry.ino index 74a892c..f6ba047 100644 --- a/Multiprotocol/Telemetry.ino +++ b/Multiprotocol/Telemetry.ino @@ -42,7 +42,7 @@ struct t_serial_bash #endif #if defined DSM_TELEMETRY -void DSM2_frame() +void DSM_frame() { Serial_write(0xAA); // Start for (uint8_t i = 0; i < 17; i++) // RSSI value followed by 16 bytes of telemetry data @@ -452,9 +452,9 @@ void TelemetryUpdate() #endif #if defined DSM_TELEMETRY - if(telemetry_link && (cur_protocol[0]&0x1F) == MODE_DSM2 ) - { // DSM2 - DSM2_frame(); + if(telemetry_link && (cur_protocol[0]&0x1F) == MODE_DSM ) + { // DSM + DSM_frame(); telemetry_link=0; return; } diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index f54e086..878128a 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -45,7 +45,7 @@ #endif #ifdef CYRF6936_INSTALLED #define DEVO_CYRF6936_INO - #define DSM2_CYRF6936_INO + #define DSM_CYRF6936_INO #define J6PRO_CYRF6936_INO #endif #ifdef CC2500_INSTALLED @@ -88,7 +88,7 @@ //Comment a line to disable a protocol telemetry #if defined(TELEMETRY) - #if defined DSM2_CYRF6936_INO + #if defined DSM_CYRF6936_INO #define DSM_TELEMETRY #endif #if defined FRSKYX_CC2500_INO @@ -151,7 +151,7 @@ const PPM_Parameters PPM_prot[15]= { /* 3 */ {MODE_FRSKY , 0 , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning /* 4 */ {MODE_HISKY , Hisky , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 5 */ {MODE_V2X2 , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, -/* 6 */ {MODE_DSM2 , DSM2 , 0 , P_HIGH , NO_AUTOBIND , 2 }, // option=2=6 channels @ 22ms +/* 6 */ {MODE_DSM , DSM2 , 0 , P_HIGH , NO_AUTOBIND , 2 }, // option=2=6 channels @ 22ms /* 7 */ {MODE_DEVO , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 8 */ {MODE_YD717 , YD717 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 9 */ {MODE_KN , WLTOYS , 0 , P_HIGH , NO_AUTOBIND , 0 }, @@ -177,7 +177,7 @@ const PPM_Parameters PPM_prot[15]= { HK310 MODE_V2X2 NONE - MODE_DSM2 + MODE_DSM DSM2 DSMX MODE_DEVO From 89e6ae2475ce42e36b838d3999ad02efb395101a Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 1 Sep 2016 14:40:17 +0200 Subject: [PATCH 192/293] Update Protocols_Details.md --- Protocols_Details.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index e29b576..00036cf 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -135,7 +135,8 @@ Bind procedure using PPM: - To verify that the TX is in fixed mode: power cycle the TX, the module LED should be solid ON (no blink). - Note: Autobind/fixed ID mode is linked to the dial number. Which means that you can have multiple dial numbers set to the same protocol DEVO with different RX_Num and have different bind modes at the same time. It enables PPM users to get model match under DEVO. -##DSM2 +##DSM +###Sub_protocol DSM2 Extended limits supported Telemetry enabled for TSSI and plugins From ee27535b82f4a503f881f243ce442025870ad82d Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 1 Sep 2016 14:42:56 +0200 Subject: [PATCH 193/293] Update README.md --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 24a06a6..8b4dfdc 100644 --- a/README.md +++ b/README.md @@ -131,7 +131,7 @@ Dial|Protocol|Sub_protocol|RX Num|Power|Auto Bind|Option|RF Module 3|FRSKY|-|0|High|No|-41|CC2500 4|HISKY|Hisky|0|High|No|0|NRF24L01 5|V2X2|-|0|High|No|0|NRF24L01 -6|DSM2|DSM2|0|High|No|6|CYRF6936 +6|DSM|DSM2|0|High|No|6|CYRF6936 7|DEVO|-|0|High|No|0|CYRF6936 8|YD717|YD717|0|High|No|0|NRF24L01 9|KN|WLTOYS|0|High|No|0|NRF24L01 @@ -171,7 +171,7 @@ SFHSS| #####CYRF6936 RF module Protocol|Sub_protocol --------|------------ -DSM2| +DSM| |DSM2 |DSMX Devo| @@ -239,8 +239,8 @@ Note: ###RF modules Up to 4 RF modules can be installed: - [A7105](http://www.banggood.com/XL7105-D03-A7105-Modification-Module-Support-Deviation-Galee-Flysky-p-922603.html) for Flysky, Hubsan -- [CC2500](http://www.banggood.com/CC2500-PA-LNA-Romote-Wireless-Module-CC2500-SI4432-NRF24L01-p-922595.html) for FrSky, FrSkyX and SFHSS -- [CYRF6936](http://www.ehirobo.com/walkera-wk-devo-s-mod-devo-8-or-12-to-devo-8s-or-12s-upgrade-module.html) for DSM2, DSMX, DEVO, Walkera +- [CC2500](http://www.banggood.com/CC2500-PA-LNA-Romote-Wireless-Module-CC2500-SI4432-NRF24L01-p-922595.html) for FrSky, FrSky1, FrSkyX and SFHSS +- [CYRF6936](http://www.ehirobo.com/walkera-wk-devo-s-mod-devo-8-or-12-to-devo-8s-or-12s-upgrade-module.html) for DSM, DEVO, J6Pro - [NRF24L01](http://www.banggood.com/2_4G-NRF24L01-PA-LNA-Wireless-Module-1632mm-Without-Antenna-p-922601.html) for Hisky, V2x2, CX-10, SYMAX and plenty other protocols RF modules can be installed for protocols need only. Example: if you only need the Hubsan protocol then install only a A7105 on your board. From 043a8336e5fdd9e17e51b45973d22f9a839b3df4 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 1 Sep 2016 17:41:24 +0200 Subject: [PATCH 194/293] Code cleaning (XMEGA) --- Multiprotocol/Multiprotocol.h | 21 + Multiprotocol/Multiprotocol.ino | 793 +++++++++++++++----------------- Multiprotocol/Telemetry.ino | 45 +- 3 files changed, 398 insertions(+), 461 deletions(-) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index a4e0941..9fb49cc 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -146,6 +146,27 @@ struct PPM_Parameters uint8_t option; }; +//******************* +//*** Timer *** +//******************* +#ifdef XMEGA + #define TIFR1 TCC1.INTFLAGS + #define OCF1A_bm TC1_CCAIF_bm + #define OCR1A TCC1.CCA + #define TCNT1 TCC1.CNT + #define USARTC0.DATA UDR0 + #define OCF1B_bm TC1_CCBIF_bm + #define OCR1B TCC1.CCB + #define TCC1.INTCTRLB TIMSK1 + #define SET_TIMSK1_OCIE1B TIMSK1 = (TIMSK1 & 0xF3) | 0x04 + #define CLR_TIMSK1_OCIE1B TIMSK1 &= 0xF3 +#else + #define OCF1A_bm _BV(OCF1A) + #define OCF1B_bm _BV(OCF1B) + #define SET_TIMSK1_OCIE1B TIMSK1 |= _BV(OCIE1B) + #define CLR_TIMSK1_OCIE1B TIMSK1 &=~_BV(OCIE1B) +#endif + //******************* //*** Pinouts *** //******************* diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 5f15ad0..392e51e 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -29,6 +29,10 @@ #include "_Config.h" #include "TX_Def.h" +#ifdef XMEGA + #undef ENABLE_PPM // Disable PPM for orange module +#endif + //Global constants/variables uint32_t MProtocol_id;//tx id, uint32_t MProtocol_id_master; @@ -72,7 +76,7 @@ uint8_t len; uint8_t RX_num; #if defined(FRSKYX_CC2500_INO) || defined(SFHSS_CC2500_INO) -uint8_t calData[48]; + uint8_t calData[48]; #endif //Channel mapping for protocols @@ -100,7 +104,7 @@ volatile uint16_t PPM_data[NUM_CHN]; volatile uint8_t rx_buff[RXBUFFER_SIZE]; volatile uint8_t rx_ok_buff[RXBUFFER_SIZE]; #ifndef BASH_SERIAL -volatile uint8_t tx_buff[TXBUFFER_SIZE]; + volatile uint8_t tx_buff[TXBUFFER_SIZE]; #endif volatile uint8_t discard_frame = 0; @@ -134,27 +138,44 @@ void_function_t remote_callback = 0; // Init void setup() { -#ifdef XMEGA - PORTD.OUTSET = 0x17 ; - PORTD.DIRSET = 0xB2 ; - PORTD.DIRCLR = 0x4D ; - PORTD.PIN0CTRL = 0x18 ; - PORTD.PIN2CTRL = 0x18 ; - PORTE.DIRSET = 0x01 ; - PORTE.DIRCLR = 0x02 ; - PORTE.OUTSET = 0x01 ; + #ifdef XMEGA + // General pinout + PORTD.OUTSET = 0x17 ; + PORTD.DIRSET = 0xB2 ; + PORTD.DIRCLR = 0x4D ; + PORTD.PIN0CTRL = 0x18 ; + PORTD.PIN2CTRL = 0x18 ; + PORTE.DIRSET = 0x01 ; + PORTE.DIRCLR = 0x02 ; + PORTE.OUTSET = 0x01 ; - for ( uint8_t count = 0 ; count < 20 ; count += 1 ) - asm("nop") ; - PORTE.OUTCLR = 0x01 ; -#else - // General pinout - DDRD = _BV(A7105_CS_pin)|_BV(SDI_pin)|_BV(SCLK_pin)|_BV( CC25_CSN_pin);//pin output - DDRC = _BV(CTRL1_pin)|_BV(CTRL2_pin)|_BV(CYRF_RST_pin); //pin output - DDRB = _BV(NRF_CSN_pin)|_BV(CYRF_CSN_pin); //pin output - PORTB = _BV(2)|_BV(3)|_BV(4)|_BV(BIND_pin); //pullup on dial (D10=PB2,D11=PB3,D12=PB4) and bind button - PORTC = _BV(0); //pullup on dial (A0=PC0) -#endif + for ( uint8_t count = 0 ; count < 20 ; count += 1 ) + asm("nop") ; + PORTE.OUTCLR = 0x01 ; + + // Timer1 config + // TCC1 16-bit timer, clocked at 0.5uS + EVSYS.CH3MUX = 0x80 + 0x04 ; // Prescaler of 16 + TCC1.CTRLB = 0; TCC1.CTRLC = 0; TCC1.CTRLD = 0; TCC1.CTRLE = 0; + TCC1.INTCTRLA = 0; TIMSK1 = 0; + TCC1.PER = 0xFFFF ; + TCNT1 = 0 ; + TCC1.CTRLA = 0x0B ; // Event3 (prescale of 16) + #else + // General pinout + DDRD = _BV(A7105_CS_pin)|_BV(SDI_pin)|_BV(SCLK_pin)|_BV( CC25_CSN_pin);//pin output + DDRC = _BV(CTRL1_pin)|_BV(CTRL2_pin)|_BV(CYRF_RST_pin); //pin output + DDRB = _BV(NRF_CSN_pin)|_BV(CYRF_CSN_pin); //pin output + PORTB = _BV(2)|_BV(3)|_BV(4)|_BV(BIND_pin); //pullup on dial (D10=PB2,D11=PB3,D12=PB4) and bind button + PORTC = _BV(0); //pullup on dial (A0=PC0) + #ifdef DEBUG_TX + TX_SET_OUTPUT; + #endif + + // Timer1 config + TCCR1A = 0; + TCCR1B = (1 << CS11); //prescaler8, set timer1 to increment every 0.5us(16Mhz) and start timer + #endif // Set Chip selects A7105_CS_on; @@ -165,32 +186,13 @@ void setup() SDI_on; SCK_off; -//#ifdef XMEGA -// // SPI enable, master, prescale of 16 -// SPID.CTRL = SPI_ENABLE_bm | SPI_MASTER_bm | SPI_PRESCALER0_bm ; -//#endif - - // Timer1 config -#ifdef XMEGA -// TCC1 16-bit timer, clocked at 0.5uS - EVSYS.CH3MUX = 0x80 + 0x04 ; // Prescaler of 16 - TCC1.CTRLB = 0; TCC1.CTRLC = 0; TCC1.CTRLD = 0; TCC1.CTRLE = 0; - TCC1.INTCTRLA = 0; TCC1.INTCTRLB = 0; - TCC1.PER = 0xFFFF ; - TCC1.CNT = 0 ; - TCC1.CTRLA = 0x0B ; // Event3 (prescale of 16) -#else - TCCR1A = 0; - TCCR1B = (1 << CS11); //prescaler8, set timer1 to increment every 0.5us(16Mhz) and start timer -#endif - // Set servos positions for(uint8_t i=0;i>2)&0x07 ) | ( (PINC<<3)&0x08) );//encoder dip switches 1,2,4,8=>B2,B3,B4,C0 -#endif + #ifndef ENABLE_PPM + mode_select = MODE_SERIAL ; // force serial mode + #else + mode_select=0x0F - ( ( (PINB>>2)&0x07 ) | ( (PINC<<3)&0x08) );//encoder dip switches 1,2,4,8=>B2,B3,B4,C0 + #endif // Update LED LED_OFF; @@ -235,27 +237,25 @@ void setup() protocol_init(); -#ifndef XMEGA //Configure PPM interrupt EICRA |=_BV(ISC11); // The rising edge of INT1 pin D3 generates an interrupt request EIMSK |= _BV(INT1); // INT1 interrupt enable -#endif -#if defined(TELEMETRY) - PPM_Telemetry_serial_init(); // Configure serial for telemetry -#endif + #if defined(TELEMETRY) + PPM_Telemetry_serial_init(); // Configure serial for telemetry + #endif } else #endif //ENABLE_PPM { // Serial -#ifdef ENABLE_SERIAL - cur_protocol[0]=0; - cur_protocol[1]=0; - prev_protocol=0; - servo_max_100=SERIAL_MAX_100; servo_min_100=SERIAL_MIN_100; - servo_max_125=SERIAL_MAX_125; servo_min_125=SERIAL_MIN_125; - Mprotocol_serial_init(); // Configure serial and enable RX interrupt -#endif //ENABLE_SERIAL + #ifdef ENABLE_SERIAL + cur_protocol[0]=0; + cur_protocol[1]=0; + prev_protocol=0; + servo_max_100=SERIAL_MAX_100; servo_min_100=SERIAL_MIN_100; + servo_max_125=SERIAL_MAX_125; servo_min_125=SERIAL_MIN_125; + Mprotocol_serial_init(); // Configure serial and enable RX interrupt + #endif //ENABLE_SERIAL } } @@ -275,25 +275,14 @@ void loop() } while(remote_callback==0); } - #ifdef XMEGA - if( (TCC1.INTFLAGS & TC1_CCAIF_bm) != 0) - { - cli(); // Disable global int due to RW of 16 bits registers - TCC1.CCA = TCC1.CNT ; // Callback should already have been called... Use "now" as new sync point. - sei(); // Enable global int - } - else - while((TCC1.INTFLAGS & TC1_CCAIF_bm) == 0); // wait before callback - #else - if( (TIFR1 & _BV(OCF1A)) != 0) - { - cli(); // Disable global int due to RW of 16 bits registers - OCR1A=TCNT1; // Callback should already have been called... Use "now" as new sync point. - sei(); // Enable global int - } - else - while((TIFR1 & _BV(OCF1A)) == 0); // Wait before callback - #endif + if( (TIFR1 & OCF1A_bm) != 0) + { + cli(); // Disable global int due to RW of 16 bits registers + OCR1A=TCNT1; // Callback should already have been called... Use "now" as new sync point. + sei(); // Enable global int + } + else + while((TIFR1 & OCF1A_bm) == 0); // Wait before callback do { TX_ON; @@ -306,41 +295,22 @@ void loop() while(next_callback>4000) { // start to wait here as much as we can... next_callback-=2000; // We will wait below for 2ms - #ifdef XMEGA - cli(); // Disable global int due to RW of 16 bits registers - TCC1.CCA +=2000*2; // set compare A for callback - TCC1.INTFLAGS = TC1_CCAIF_bm ; // clear compare A=callback flag - sei(); // enable global int - Update_All(); - if(IS_CHANGE_PROTOCOL_FLAG_on) - break; // Protocol has been changed - while((TCC1.INTFLAGS & TC1_CCAIF_bm) == 0); // wait 2ms... - #else - cli(); // Disable global int due to RW of 16 bits registers - OCR1A += 2000*2 ; // set compare A for callback - TIFR1=_BV(OCF1A); // clear compare A=callback flag - sei(); // enable global int - Update_All(); - if(IS_CHANGE_PROTOCOL_FLAG_on) - break; // Protocol has been changed - while((TIFR1 & _BV(OCF1A)) == 0); // wait 2ms... - #endif + 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 + sei(); // enable global int + Update_All(); + if(IS_CHANGE_PROTOCOL_FLAG_on) + break; // Protocol has been changed + while((TIFR1 & OCF1A_bm) == 0); // wait 2ms... } // at this point we have a maximum of 4ms in next_callback next_callback *= 2 ; - #ifdef XMEGA - cli(); // Disable global int due to RW of 16 bits registers - TCC1.CCA +=next_callback; // set compare A for callback - TCC1.INTFLAGS = TC1_CCAIF_bm ; // clear compare A=callback flag - diff=TCC1.CCA-TCC1.CNT; // compare timer and comparator - sei(); // enable global int - #else - cli(); // Disable global int due to RW of 16 bits registers - OCR1A+= next_callback ; // set compare A for callback - TIFR1=_BV(OCF1A); // clear compare A=callback flag - diff=OCR1A-TCNT1; // compare timer and comparator - sei(); // enable global int - #endif + 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 + diff=OCR1A-TCNT1; // compare timer and comparator + sei(); // enable global int } while(diff&0x8000); // Callback did not took more than requested time for next callback // so we can launch Update_All before next callback @@ -349,49 +319,42 @@ void loop() void Update_All() { -TX_ON; -NOP(); -TX_OFF; - -#ifdef ENABLE_SERIAL - if(mode_select==MODE_SERIAL && IS_RX_FLAG_on) // Serial mode and something has been received - { - update_serial_data(); // Update protocol and data - update_aux_flags(); - if(IS_CHANGE_PROTOCOL_FLAG_on) - { // Protocol needs to be changed - LED_OFF; //led off during protocol init - modules_reset(); //reset all modules - protocol_init(); //init new protocol + #ifdef ENABLE_SERIAL + if(mode_select==MODE_SERIAL && IS_RX_FLAG_on) // Serial mode and something has been received + { + update_serial_data(); // Update protocol and data + update_aux_flags(); + if(IS_CHANGE_PROTOCOL_FLAG_on) + { // Protocol needs to be changed + LED_OFF; //led off during protocol init + modules_reset(); //reset all modules + protocol_init(); //init new protocol + } } - } -#endif //ENABLE_SERIAL -#ifdef ENABLE_PPM - if(mode_select!=MODE_SERIAL && IS_PPM_FLAG_on) // PPM mode and a full frame has been received - { - for(uint8_t i=0;iPPM_MAX_125) temp_ppm=PPM_MAX_125; - Servo_data[i]= temp_ppm ; + #endif //ENABLE_SERIAL + #ifdef ENABLE_PPM + if(mode_select!=MODE_SERIAL && IS_PPM_FLAG_on) // PPM mode and a full frame has been received + { + for(uint8_t i=0;iPPM_MAX_125) temp_ppm=PPM_MAX_125; + Servo_data[i]= temp_ppm ; + } + update_aux_flags(); + PPM_FLAG_off; // wait for next frame before update } - update_aux_flags(); - PPM_FLAG_off; // wait for next frame before update - } -#endif //ENABLE_PPM + #endif //ENABLE_PPM update_led_status(); #if defined(TELEMETRY) - uint8_t protocol=cur_protocol[0]&0x1F; - if( (protocol==MODE_FRSKY) || (protocol==MODE_HUBSAN) || (protocol==MODE_FRSKYX) || (protocol==MODE_DSM) ) - TelemetryUpdate(); + uint8_t protocol=cur_protocol[0]&0x1F; + if( (protocol==MODE_FRSKY) || (protocol==MODE_HUBSAN) || (protocol==MODE_FRSKYX) || (protocol==MODE_DSM) ) + TelemetryUpdate(); #endif -TX_ON; -NOP(); -TX_OFF; } // Update Servo_AUX flags based on servo AUX positions @@ -429,27 +392,29 @@ static void update_led_status(void) inline void tx_pause() { -#ifdef TELEMETRY - #ifdef XMEGA - USARTC0.CTRLA &= ~0x03 ; // Pause telemetry by disabling transmitter interrupt - #else - #ifndef BASH_SERIAL - UCSR0B &= ~_BV(UDRIE0); // Pause telemetry by disabling transmitter interrupt + #ifdef TELEMETRY + #ifdef XMEGA + USARTC0.CTRLA &= ~0x03 ; // Pause telemetry by disabling transmitter interrupt + #else + #ifndef BASH_SERIAL + UCSR0B &= ~_BV(UDRIE0); // Pause telemetry by disabling transmitter interrupt + #endif #endif #endif -#endif } inline void tx_resume() { -#ifdef TELEMETRY - if(!IS_TX_PAUSE_on) - #ifdef XMEGA - USARTC0.CTRLA = (USARTC0.CTRLA & 0xFC) | 0x01 ; // Resume telemetry by enabling transmitter interrupt - #else - UCSR0B |= _BV(UDRIE0); // Resume telemetry by enabling transmitter interrupt - #endif -#endif + #ifdef TELEMETRY + if(!IS_TX_PAUSE_on) + #ifdef XMEGA + USARTC0.CTRLA = (USARTC0.CTRLA & 0xFC) | 0x01 ; // Resume telemetry by enabling transmitter interrupt + #else + #ifndef BASH_SERIAL + UCSR0B |= _BV(UDRIE0); // Resume telemetry by enabling transmitter interrupt + #endif + #endif + #endif } // Protocol start @@ -482,186 +447,186 @@ static void protocol_init() switch(cur_protocol[0]&0x1F) // Init the requested protocol { -#if defined(FLYSKY_A7105_INO) - case MODE_FLYSKY: - CTRL1_off; //antenna RF1 - next_callback = initFlySky(); - remote_callback = ReadFlySky; - break; -#endif -#if defined(HUBSAN_A7105_INO) - case MODE_HUBSAN: - CTRL1_off; //antenna RF1 - if(IS_BIND_BUTTON_FLAG_on) random_id(10,true); // Generate new ID if bind button is pressed. - next_callback = initHubsan(); - remote_callback = ReadHubsan; - break; -#endif -#if defined(FRSKY_CC2500_INO) - case MODE_FRSKY: - CTRL1_off; //antenna RF2 - CTRL2_on; - next_callback = initFrSky_2way(); - remote_callback = ReadFrSky_2way; - break; -#endif -#if defined(FRSKY1_CC2500_INO) - case MODE_FRSKY1: - CTRL1_off; //antenna RF2 - CTRL2_on; - next_callback = initFRSKY1(); - remote_callback = ReadFRSKY1; - break; -#endif -#if defined(FRSKYX_CC2500_INO) - case MODE_FRSKYX: - CTRL1_off; //antenna RF2 - CTRL2_on; - next_callback = initFrSkyX(); - remote_callback = ReadFrSkyX; - break; -#endif -#if defined(SFHSS_CC2500_INO) - case MODE_SFHSS: - CTRL1_off; //antenna RF2 - CTRL2_on; - next_callback = initSFHSS(); - remote_callback = ReadSFHSS; - break; -#endif -#if defined(DSM_CYRF6936_INO) - case MODE_DSM: - CTRL2_on; //antenna RF4 - next_callback = initDsm(); - //Servo_data[2]=1500;//before binding - remote_callback = ReadDsm; - break; -#endif -#if defined(DEVO_CYRF6936_INO) - case MODE_DEVO: - #ifdef ENABLE_PPM - if(mode_select) //PPM mode - { - if(IS_BIND_BUTTON_FLAG_on) - { - eeprom_write_byte((uint8_t*)(30+mode_select),0x00); // reset to autobind mode for the current model - option=0; - } - else - { - option=eeprom_read_byte((uint8_t*)(30+mode_select)); // load previous mode: autobind or fixed id - if(option!=1) option=0; // if not fixed id mode then it should be autobind - } - } - #endif //ENABLE_PPM - CTRL2_on; //antenna RF4 - next_callback = DevoInit(); - remote_callback = devo_callback; - break; -#endif -#if defined(J6PRO_CYRF6936_INO) - case MODE_J6PRO: - CTRL2_on; //antenna RF4 - next_callback = initJ6Pro(); - remote_callback = ReadJ6Pro; - break; -#endif -#if defined(HISKY_NRF24L01_INO) - case MODE_HISKY: - next_callback=initHiSky(); - remote_callback = hisky_cb; - break; -#endif -#if defined(V2X2_NRF24L01_INO) - case MODE_V2X2: - next_callback = initV2x2(); - remote_callback = ReadV2x2; - break; -#endif -#if defined(YD717_NRF24L01_INO) - case MODE_YD717: - next_callback=initYD717(); - remote_callback = yd717_callback; - break; -#endif -#if defined(KN_NRF24L01_INO) - case MODE_KN: - next_callback = initKN(); - remote_callback = kn_callback; - break; -#endif -#if defined(SYMAX_NRF24L01_INO) - case MODE_SYMAX: - next_callback = initSymax(); - remote_callback = symax_callback; - break; -#endif -#if defined(SLT_NRF24L01_INO) - case MODE_SLT: - next_callback=initSLT(); - remote_callback = SLT_callback; - break; -#endif -#if defined(CX10_NRF24L01_INO) - case MODE_CX10: - next_callback=initCX10(); - remote_callback = CX10_callback; - break; -#endif -#if defined(CG023_NRF24L01_INO) - case MODE_CG023: - next_callback=initCG023(); - remote_callback = CG023_callback; - break; -#endif -#if defined(BAYANG_NRF24L01_INO) - case MODE_BAYANG: - next_callback=initBAYANG(); - remote_callback = BAYANG_callback; - break; -#endif -#if defined(ESKY_NRF24L01_INO) - case MODE_ESKY: - next_callback=initESKY(); - remote_callback = ESKY_callback; - break; -#endif -#if defined(MT99XX_NRF24L01_INO) - case MODE_MT99XX: - next_callback=initMT99XX(); - remote_callback = MT99XX_callback; - break; -#endif -#if defined(MJXQ_NRF24L01_INO) - case MODE_MJXQ: - next_callback=initMJXQ(); - remote_callback = MJXQ_callback; - break; -#endif -#if defined(SHENQI_NRF24L01_INO) - case MODE_SHENQI: - next_callback=initSHENQI(); - remote_callback = SHENQI_callback; - break; -#endif -#if defined(FY326_NRF24L01_INO) - case MODE_FY326: - next_callback=initFY326(); - remote_callback = FY326_callback; - break; -#endif -#if defined(FQ777_NRF24L01_INO) - case MODE_FQ777: - next_callback=initFQ777(); - remote_callback = FQ777_callback; - break; -#endif -#if defined(ASSAN_NRF24L01_INO) - case MODE_ASSAN: - next_callback=initASSAN(); - remote_callback = ASSAN_callback; - break; -#endif + #if defined(FLYSKY_A7105_INO) + case MODE_FLYSKY: + CTRL1_off; //antenna RF1 + next_callback = initFlySky(); + remote_callback = ReadFlySky; + break; + #endif + #if defined(HUBSAN_A7105_INO) + case MODE_HUBSAN: + CTRL1_off; //antenna RF1 + if(IS_BIND_BUTTON_FLAG_on) random_id(10,true); // Generate new ID if bind button is pressed. + next_callback = initHubsan(); + remote_callback = ReadHubsan; + break; + #endif + #if defined(FRSKY_CC2500_INO) + case MODE_FRSKY: + CTRL1_off; //antenna RF2 + CTRL2_on; + next_callback = initFrSky_2way(); + remote_callback = ReadFrSky_2way; + break; + #endif + #if defined(FRSKY1_CC2500_INO) + case MODE_FRSKY1: + CTRL1_off; //antenna RF2 + CTRL2_on; + next_callback = initFRSKY1(); + remote_callback = ReadFRSKY1; + break; + #endif + #if defined(FRSKYX_CC2500_INO) + case MODE_FRSKYX: + CTRL1_off; //antenna RF2 + CTRL2_on; + next_callback = initFrSkyX(); + remote_callback = ReadFrSkyX; + break; + #endif + #if defined(SFHSS_CC2500_INO) + case MODE_SFHSS: + CTRL1_off; //antenna RF2 + CTRL2_on; + next_callback = initSFHSS(); + remote_callback = ReadSFHSS; + break; + #endif + #if defined(DSM_CYRF6936_INO) + case MODE_DSM: + CTRL2_on; //antenna RF4 + next_callback = initDsm(); + //Servo_data[2]=1500;//before binding + remote_callback = ReadDsm; + break; + #endif + #if defined(DEVO_CYRF6936_INO) + case MODE_DEVO: + #ifdef ENABLE_PPM + if(mode_select) //PPM mode + { + if(IS_BIND_BUTTON_FLAG_on) + { + eeprom_write_byte((uint8_t*)(30+mode_select),0x00); // reset to autobind mode for the current model + option=0; + } + else + { + option=eeprom_read_byte((uint8_t*)(30+mode_select)); // load previous mode: autobind or fixed id + if(option!=1) option=0; // if not fixed id mode then it should be autobind + } + } + #endif //ENABLE_PPM + CTRL2_on; //antenna RF4 + next_callback = DevoInit(); + remote_callback = devo_callback; + break; + #endif + #if defined(J6PRO_CYRF6936_INO) + case MODE_J6PRO: + CTRL2_on; //antenna RF4 + next_callback = initJ6Pro(); + remote_callback = ReadJ6Pro; + break; + #endif + #if defined(HISKY_NRF24L01_INO) + case MODE_HISKY: + next_callback=initHiSky(); + remote_callback = hisky_cb; + break; + #endif + #if defined(V2X2_NRF24L01_INO) + case MODE_V2X2: + next_callback = initV2x2(); + remote_callback = ReadV2x2; + break; + #endif + #if defined(YD717_NRF24L01_INO) + case MODE_YD717: + next_callback=initYD717(); + remote_callback = yd717_callback; + break; + #endif + #if defined(KN_NRF24L01_INO) + case MODE_KN: + next_callback = initKN(); + remote_callback = kn_callback; + break; + #endif + #if defined(SYMAX_NRF24L01_INO) + case MODE_SYMAX: + next_callback = initSymax(); + remote_callback = symax_callback; + break; + #endif + #if defined(SLT_NRF24L01_INO) + case MODE_SLT: + next_callback=initSLT(); + remote_callback = SLT_callback; + break; + #endif + #if defined(CX10_NRF24L01_INO) + case MODE_CX10: + next_callback=initCX10(); + remote_callback = CX10_callback; + break; + #endif + #if defined(CG023_NRF24L01_INO) + case MODE_CG023: + next_callback=initCG023(); + remote_callback = CG023_callback; + break; + #endif + #if defined(BAYANG_NRF24L01_INO) + case MODE_BAYANG: + next_callback=initBAYANG(); + remote_callback = BAYANG_callback; + break; + #endif + #if defined(ESKY_NRF24L01_INO) + case MODE_ESKY: + next_callback=initESKY(); + remote_callback = ESKY_callback; + break; + #endif + #if defined(MT99XX_NRF24L01_INO) + case MODE_MT99XX: + next_callback=initMT99XX(); + remote_callback = MT99XX_callback; + break; + #endif + #if defined(MJXQ_NRF24L01_INO) + case MODE_MJXQ: + next_callback=initMJXQ(); + remote_callback = MJXQ_callback; + break; + #endif + #if defined(SHENQI_NRF24L01_INO) + case MODE_SHENQI: + next_callback=initSHENQI(); + remote_callback = SHENQI_callback; + break; + #endif + #if defined(FY326_NRF24L01_INO) + case MODE_FY326: + next_callback=initFY326(); + remote_callback = FY326_callback; + break; + #endif + #if defined(FQ777_NRF24L01_INO) + case MODE_FQ777: + next_callback=initFQ777(); + remote_callback = FQ777_callback; + break; + #endif + #if defined(ASSAN_NRF24L01_INO) + case MODE_ASSAN: + next_callback=initASSAN(); + remote_callback = ASSAN_callback; + break; + #endif } if(next_callback>32000) @@ -671,15 +636,9 @@ static void protocol_init() next_callback-=temp<<10; // between 2-3ms left at this stage } cli(); // disable global int -#ifdef XMEGA - TCC1.CCA = TCC1.CNT + next_callback*2; // set compare A for callback + OCR1A = TCNT1 + next_callback*2;// set compare A for callback sei(); // enable global int - TCC1.INTFLAGS = TC1_CCAIF_bm ; // clear compare A flag -#else - OCR1A=TCNT1+next_callback*2; // set compare A for callback - sei(); // enable global int - TIFR1=_BV(OCF1A); // clear compare A flag -#endif + TIFR1 = OCF1A_bm ; // clear compare A flag BIND_BUTTON_FLAG_off; // do not bind/reset id anymore even if protocol change } @@ -834,40 +793,37 @@ uint16_t limit_channel_100(uint8_t ch) void Mprotocol_serial_init() { -#ifdef XMEGA - - PORTC.OUTSET = 0x08 ; - PORTC.DIRSET = 0x08 ; + #ifdef XMEGA + PORTC.OUTSET = 0x08 ; + PORTC.DIRSET = 0x08 ; - USARTC0.BAUDCTRLA = 19 ; - USARTC0.BAUDCTRLB = 0 ; - - USARTC0.CTRLB = 0x18 ; - USARTC0.CTRLA = (USARTC0.CTRLA & 0xCF) | 0x10 ; - USARTC0.CTRLC = 0x2B ; - USARTC0.DATA ; - #ifdef INVERT_TELEMETRY - PORTC.PIN3CTRL |= 0x40 ; - #endif -#else - #include - UBRR0H = UBRRH_VALUE; - UBRR0L = UBRRL_VALUE; - UCSR0A = 0 ; // Clear X2 bit - //Set frame format to 8 data bits, even parity, 2 stop bits - UCSR0C = _BV(UPM01)|_BV(USBS0)|_BV(UCSZ01)|_BV(UCSZ00); - while ( UCSR0A & (1 << RXC0) )//flush receive buffer - UDR0; - //enable reception and RC complete interrupt - UCSR0B = _BV(RXEN0)|_BV(RXCIE0);//rx enable and interrupt -#ifdef DEBUG_TX - TX_SET_OUTPUT; -#else - #if defined(TELEMETRY) - initTXSerial( SPEED_100K ) ; - #endif //TELEMETRY -#endif //DEBUG_TX -#endif //XMEGA + USARTC0.BAUDCTRLA = 19 ; + USARTC0.BAUDCTRLB = 0 ; + + USARTC0.CTRLB = 0x18 ; + USARTC0.CTRLA = (USARTC0.CTRLA & 0xCF) | 0x10 ; + USARTC0.CTRLC = 0x2B ; + UDR0 ; + #ifdef INVERT_TELEMETRY + PORTC.PIN3CTRL |= 0x40 ; + #endif + #else + #include + UBRR0H = UBRRH_VALUE; + UBRR0L = UBRRL_VALUE; + UCSR0A = 0 ; // Clear X2 bit + //Set frame format to 8 data bits, even parity, 2 stop bits + UCSR0C = _BV(UPM01)|_BV(USBS0)|_BV(UCSZ01)|_BV(UCSZ00); + while ( UCSR0A & (1 << RXC0) )//flush receive buffer + UDR0; + //enable reception and RC complete interrupt + UCSR0B = _BV(RXEN0)|_BV(RXCIE0);//rx enable and interrupt + #ifndef DEBUG_TX + #if defined(TELEMETRY) + initTXSerial( SPEED_100K ) ; + #endif //TELEMETRY + #endif //DEBUG_TX + #endif //XMEGA } #if defined(TELEMETRY) @@ -1076,11 +1032,7 @@ ISR(INT1_vect, ISR_NOBLOCK) static uint16_t Prev_TCNT1=0; uint16_t Cur_TCNT1; -#ifdef XMEGA - Cur_TCNT1 = TCC1.CNT - Prev_TCNT1 ; // Capture current Timer1 value -#else - Cur_TCNT1=TCNT1-Prev_TCNT1; // Capture current Timer1 value -#endif + Cur_TCNT1 = TCNT1 - Prev_TCNT1 ; // Capture current Timer1 value if(Cur_TCNT1<1000) chan=-1; // bad frame else @@ -1110,44 +1062,30 @@ ISR(USART_RX_vect) { // RX interrupt static uint8_t idx=0; #ifdef XMEGA - if((USARTC0.STATUS & 0x1C)==0) // Check frame error, data overrun and parity error + if((USARTC0.STATUS & 0x1C)==0) // Check frame error, data overrun and parity error #else - UCSR0B &= ~_BV(RXCIE0) ; // RX interrupt disable + UCSR0B &= ~_BV(RXCIE0) ; // RX interrupt disable sei() ; - if((UCSR0A&0x1C)==0) // Check frame error, data overrun and parity error + if((UCSR0A&0x1C)==0) // Check frame error, data overrun and parity error #endif { // received byte is ok to process if(idx==0||discard_frame==1) { // Let's try to sync at this point idx=0;discard_frame=0; - #ifdef XMEGA - if(USARTC0.DATA==0x55) // If 1st byte is 0x55 it looks ok - #else - if(UDR0==0x55) // If 1st byte is 0x55 it looks ok - #endif + if(UDR0==0x55) // If 1st byte is 0x55 it looks ok { TX_RX_PAUSE_on; tx_pause(); - #ifdef XMEGA - TCC1.CCB = TCC1.CNT+(6500L) ; // Full message should be received within timer of 3250us - TCC1.INTFLAGS = TC1_CCBIF_bm ; // clear OCR1B match flag - TCC1.INTCTRLB = (TCC1.INTCTRLB & 0xF3) | 0x04 ; // enable interrupt on compare B match - #else - OCR1B=TCNT1+6500L; // Full message should be received within timer of 3250us - TIFR1=_BV(OCF1B); // clear OCR1B match flag - TIMSK1 |=_BV(OCIE1B); // enable interrupt on compare B match - #endif + OCR1B = TCNT1+(6500L) ; // Full message should be received within timer of 3250us + TIFR1 = OCF1B_bm ; // clear OCR1B match flag + SET_TIMSK1_OCIE1B ; // enable interrupt on compare B match idx++; } } else { - RX_MISSED_BUFF_off; // if rx_buff was good it's not anymore... - #ifdef XMEGA - rx_buff[(idx++)-1]=USARTC0.DATA; // Store received byte - #else - rx_buff[(idx++)-1]=UDR0; // Store received byte - #endif + RX_MISSED_BUFF_off; // if rx_buff was good it's not anymore... + rx_buff[(idx++)-1]=UDR0; // Store received byte if(idx>RXBUFFER_SIZE) { // A full frame has been received if(!IS_RX_DONOTUPDTAE_on) @@ -1156,27 +1094,19 @@ ISR(USART_RX_vect) RX_FLAG_on; // flag for main to process servo data } else - RX_MISSED_BUFF_on; // notify that rx_buff is good - discard_frame=1; // start again + RX_MISSED_BUFF_on; // notify that rx_buff is good + discard_frame=1; // start again } } } else { - #ifdef XMEGA - idx = USARTC0.DATA; // Dummy read - #else - idx=UDR0; // Dummy read - #endif - discard_frame=1; // Error encountered discard full frame... + idx=UDR0; // Dummy read + discard_frame=1; // Error encountered discard full frame... } if(discard_frame==1) { - #ifdef XMEGA - TCC1.INTCTRLB &=0xF3; // Disable interrupt on compare B match - #else - TIMSK1 &=~_BV(OCIE1B); // Disable interrupt on compare B match - #endif + CLR_TIMSK1_OCIE1B; // Disable interrupt on compare B match TX_RX_PAUSE_off; tx_resume(); } @@ -1190,16 +1120,11 @@ ISR(USART_RX_vect) #ifdef XMEGA ISR(TCC1_CCB_vect) #else -//ISR(TIMER1_COMPB_vect) ISR(TIMER1_COMPB_vect, ISR_NOBLOCK ) #endif { // Timer1 compare B interrupt discard_frame=1; - #ifdef XMEGA - TCC1.INTCTRLB &=0xF3; // Disable interrupt on compare B match - #else - TIMSK1 &=~_BV(OCIE1B); // Disable interrupt on compare B match - #endif + CLR_TIMSK1_OCIE1B; // Disable interrupt on compare B match tx_resume(); } #endif //ENABLE_SERIAL \ No newline at end of file diff --git a/Multiprotocol/Telemetry.ino b/Multiprotocol/Telemetry.ino index f6ba047..22d04d1 100644 --- a/Multiprotocol/Telemetry.ino +++ b/Multiprotocol/Telemetry.ino @@ -1,7 +1,7 @@ -//************************************* -// FrSky Telemetry serial code * -// By Midelic on RCGroups * -//************************************* +//************************** +// Telemetry serial code * +// By Midelic on RCGroups * +//************************** #if defined TELEMETRY @@ -30,15 +30,14 @@ uint8_t frame[18]; #ifdef BASH_SERIAL // For bit-bashed serial output - -struct t_serial_bash -{ - uint8_t head ; - uint8_t tail ; - uint8_t data[64] ; - uint8_t busy ; - uint8_t speed ; -} SerialControl ; + struct t_serial_bash + { + uint8_t head ; + uint8_t tail ; + uint8_t data[64] ; + uint8_t busy ; + uint8_t speed ; + } SerialControl ; #endif #if defined DSM_TELEMETRY @@ -540,18 +539,10 @@ ISR(USART_UDRE_vect) { if(++tx_tail>=TXBUFFER_SIZE)//head tx_tail=0; -#ifdef XMEGA - USARTC0.DATA = tx_buff[tx_tail] ; -#else UDR0=tx_buff[tx_tail]; -#endif } if (tx_tail == tx_head) -#ifdef XMEGA - USARTC0.CTRLA &= ~0x03 ; -#else - UCSR0B &= ~(1< Date: Thu, 1 Sep 2016 18:09:35 +0200 Subject: [PATCH 195/293] FRSKY1 --- Multiprotocol/FrSky1_cc2500.ino | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Multiprotocol/FrSky1_cc2500.ino b/Multiprotocol/FrSky1_cc2500.ino index ac6558d..7afb4bd 100644 --- a/Multiprotocol/FrSky1_cc2500.ino +++ b/Multiprotocol/FrSky1_cc2500.ino @@ -165,24 +165,25 @@ static uint16_t ReadFRSKY1() } if (state >= FRSKY_DATA1) { - CC2500_Strobe(CC2500_SIDLE); uint8_t chan = FRSKY1_calc_channel(); + CC2500_Strobe(CC2500_SIDLE); + if (option != prev_option) + { + CC2500_WriteReg(CC2500_0C_FSCTRL0, option); + prev_option=option; + } CC2500_WriteReg(CC2500_0A_CHANNR, chan * 5 + 6); FRSKY1_build_data_packet(); - CC2500_WriteData(packet, packet[0]+1); if (state == FRSKY_DATA5) { - if (option != prev_option) - { - CC2500_WriteReg(CC2500_0C_FSCTRL0, option); - prev_option=option; - } CC2500_SetPower(); state = FRSKY_DATA1; } else state++; + + CC2500_WriteData(packet, packet[0]+1); return 9006; } return 0; @@ -190,7 +191,6 @@ static uint16_t ReadFRSKY1() uint16_t initFRSKY1() { - //u8 data[2] = {(fixed_id >> 8) & 0xff, fixed_id & 0xff}; crc8 = FRSKY1_crc8_le(0x6b, rx_tx_addr+2, 2); // Use rx_tx_addr[2] and rx_tx_addr[3] since we want to use RX_Num FRSKY1_init(); seed = 1; From 2ac704178c60f2f4d6cc77cd9265fd5932bd5288 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 1 Sep 2016 18:12:35 +0200 Subject: [PATCH 196/293] FRSKY1 --- Multiprotocol/FrSky1_cc2500.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Multiprotocol/FrSky1_cc2500.ino b/Multiprotocol/FrSky1_cc2500.ino index 7afb4bd..21069b6 100644 --- a/Multiprotocol/FrSky1_cc2500.ino +++ b/Multiprotocol/FrSky1_cc2500.ino @@ -147,7 +147,7 @@ static void __attribute__((unused)) FRSKY1_build_data_packet() packet[14] = FRSKY1_crc8(crc8, packet, 14); } -static uint16_t ReadFRSKY1() +uint16_t ReadFRSKY1() { if (state < FRSKY_BIND_DONE) { From ec2086e0f74e1517d6eb4036769502c898064e9e Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 1 Sep 2016 20:12:17 +0200 Subject: [PATCH 197/293] Fixed invert serial compilation --- Multiprotocol/Multiprotocol.ino | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 392e51e..dfff25d 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -407,6 +407,7 @@ inline void tx_resume() { #ifdef TELEMETRY if(!IS_TX_PAUSE_on) + { #ifdef XMEGA USARTC0.CTRLA = (USARTC0.CTRLA & 0xFC) | 0x01 ; // Resume telemetry by enabling transmitter interrupt #else @@ -414,6 +415,7 @@ inline void tx_resume() UCSR0B |= _BV(UDRIE0); // Resume telemetry by enabling transmitter interrupt #endif #endif + } #endif } @@ -430,8 +432,10 @@ static void protocol_init() tx_pause(); pass=0; telemetry_link=0; - tx_tail=0; - tx_head=0; + #ifndef BASH_SERIAL + tx_tail=0; + tx_head=0; + #endif #endif blink=millis(); From f0646dde32e0ea2bd664eb08e101e3bbf7d4776d Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sat, 3 Sep 2016 10:12:30 +0200 Subject: [PATCH 198/293] FrSky1 Fix --- Multiprotocol/FrSky1_cc2500.ino | 68 +++++++++++++++++++-------------- 1 file changed, 39 insertions(+), 29 deletions(-) diff --git a/Multiprotocol/FrSky1_cc2500.ino b/Multiprotocol/FrSky1_cc2500.ino index 21069b6..d7d723e 100644 --- a/Multiprotocol/FrSky1_cc2500.ino +++ b/Multiprotocol/FrSky1_cc2500.ino @@ -15,6 +15,17 @@ #if defined(FRSKY1_CC2500_INO) +#define FRSKY1_BIND_COUNT 200 + +enum { + FRSKY1_DATA1=0, + FRSKY1_DATA2, + FRSKY1_DATA3, + FRSKY1_DATA4, + FRSKY1_DATA5 +}; + + #include "iface_cc2500.h" const PROGMEM uint8_t FRSKY1_cc2500_conf[][2]={ { CC2500_17_MCSM1, 0x0c }, @@ -103,7 +114,7 @@ static void __attribute__((unused)) FRSKY1_build_bind_packet() packet[2] = 0x01; //Packet type packet[3] = rx_tx_addr[3]; packet[4] = rx_tx_addr[2]; - packet[5] = ((state - FRSKY_BIND) % 10) * 5; + packet[5] = (binding_idx % 10) * 5; packet[6] = packet[5] * 5 + 6; packet[7] = packet[5] * 5 + 11; packet[8] = packet[5] * 5 + 16; @@ -125,19 +136,23 @@ static uint8_t __attribute__((unused)) FRSKY1_calc_channel() static void __attribute__((unused)) FRSKY1_build_data_packet() { + uint8_t idx = 0; // transmit lower channels + packet[0] = 0x0e; packet[1] = rx_tx_addr[3]; packet[2] = rx_tx_addr[2]; packet[3] = seed & 0xff; packet[4] = seed >> 8; - if (state == FRSKY_DATA1 || state == FRSKY_DATA3) + if (phase == FRSKY1_DATA1 || phase == FRSKY1_DATA3) packet[5] = 0x0f; else - if(state == FRSKY_DATA2 || state == FRSKY_DATA4) + if(phase == FRSKY1_DATA2 || phase == FRSKY1_DATA4) + { packet[5] = 0xf0; + idx=4; // transmit upper channels + } else packet[5] = 0x00; - uint8_t idx = 0; //= (state == FRSKY_DATA1) ? 4 : 0; for(uint8_t i = 0; i < 4; i++) { uint16_t value = convert_channel_frsky(i+idx); @@ -149,22 +164,8 @@ static void __attribute__((unused)) FRSKY1_build_data_packet() uint16_t ReadFRSKY1() { - if (state < FRSKY_BIND_DONE) - { - FRSKY1_build_bind_packet(); - CC2500_Strobe(CC2500_SIDLE); - CC2500_WriteReg(CC2500_0A_CHANNR, 0x00); - CC2500_WriteData(packet, packet[0]+1); - state++; - return 53460; - } - if (state == FRSKY_BIND_DONE) - { - state++; - BIND_DONE; - } - if (state >= FRSKY_DATA1) - { + if(IS_BIND_DONE_on) + { // Normal operation uint8_t chan = FRSKY1_calc_channel(); CC2500_Strobe(CC2500_SIDLE); if (option != prev_option) @@ -175,29 +176,38 @@ uint16_t ReadFRSKY1() CC2500_WriteReg(CC2500_0A_CHANNR, chan * 5 + 6); FRSKY1_build_data_packet(); - if (state == FRSKY_DATA5) + if (phase == FRSKY1_DATA5) { CC2500_SetPower(); - state = FRSKY_DATA1; + phase = FRSKY1_DATA1; } else - state++; + phase++; CC2500_WriteData(packet, packet[0]+1); return 9006; } - return 0; + // Bind mode + FRSKY1_build_bind_packet(); + CC2500_Strobe(CC2500_SIDLE); + CC2500_WriteReg(CC2500_0A_CHANNR, 0x00); + CC2500_WriteData(packet, packet[0]+1); + binding_idx++; + if(binding_idx>=FRSKY1_BIND_COUNT) + BIND_DONE; + return 53460; } uint16_t initFRSKY1() { - crc8 = FRSKY1_crc8_le(0x6b, rx_tx_addr+2, 2); // Use rx_tx_addr[2] and rx_tx_addr[3] since we want to use RX_Num + //ID is 15 bits. Using rx_tx_addr[2] and rx_tx_addr[3] since we want to use RX_Num for model match + rx_tx_addr[2]&=0x7F; + crc8 = FRSKY1_crc8_le(0x6b, rx_tx_addr+2, 2); + FRSKY1_init(); seed = 1; - if(IS_AUTOBIND_FLAG_on) - state = FRSKY_BIND; - else - state = FRSKY_DATA1; + binding_idx=0; + phase = FRSKY1_DATA1; return 10000; } From 4daec3794ed680fc0844052ea5a52fe6eaaca0a7 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sat, 3 Sep 2016 11:49:25 +0200 Subject: [PATCH 199/293] Renamed FrSky protocols to match with receivers --- .../{FrSky_cc2500.ino => FrSkyD_cc2500.ino} | 2 +- .../{FrSky1_cc2500.ino => FrSkyV_cc2500.ino} | 69 +++++++++---------- Multiprotocol/Multiprotocol.h | 8 +-- Multiprotocol/Multiprotocol.ino | 14 ++-- Multiprotocol/Telemetry.ino | 4 +- Multiprotocol/_Config.h | 12 ++-- 6 files changed, 52 insertions(+), 57 deletions(-) rename Multiprotocol/{FrSky_cc2500.ino => FrSkyD_cc2500.ino} (99%) rename Multiprotocol/{FrSky1_cc2500.ino => FrSkyV_cc2500.ino} (74%) diff --git a/Multiprotocol/FrSky_cc2500.ino b/Multiprotocol/FrSkyD_cc2500.ino similarity index 99% rename from Multiprotocol/FrSky_cc2500.ino rename to Multiprotocol/FrSkyD_cc2500.ino index 78bbc89..9bc2ff5 100644 --- a/Multiprotocol/FrSky_cc2500.ino +++ b/Multiprotocol/FrSkyD_cc2500.ino @@ -13,7 +13,7 @@ along with Multiprotocol. If not, see . */ -#if defined(FRSKY_CC2500_INO) +#if defined(FRSKYD_CC2500_INO) #include "iface_cc2500.h" diff --git a/Multiprotocol/FrSky1_cc2500.ino b/Multiprotocol/FrSkyV_cc2500.ino similarity index 74% rename from Multiprotocol/FrSky1_cc2500.ino rename to Multiprotocol/FrSkyV_cc2500.ino index d7d723e..aaf88a9 100644 --- a/Multiprotocol/FrSky1_cc2500.ino +++ b/Multiprotocol/FrSkyV_cc2500.ino @@ -13,21 +13,21 @@ along with Multiprotocol. If not, see . */ -#if defined(FRSKY1_CC2500_INO) +#if defined(FRSKYV_CC2500_INO) -#define FRSKY1_BIND_COUNT 200 +#define FRSKYV_BIND_COUNT 200 enum { - FRSKY1_DATA1=0, - FRSKY1_DATA2, - FRSKY1_DATA3, - FRSKY1_DATA4, - FRSKY1_DATA5 + FRSKYV_DATA1=0, + FRSKYV_DATA2, + FRSKYV_DATA3, + FRSKYV_DATA4, + FRSKYV_DATA5 }; #include "iface_cc2500.h" -const PROGMEM uint8_t FRSKY1_cc2500_conf[][2]={ +const PROGMEM uint8_t FRSKYV_cc2500_conf[][2]={ { CC2500_17_MCSM1, 0x0c }, { CC2500_18_MCSM0, 0x18 }, { CC2500_06_PKTLEN, 0xff }, @@ -47,12 +47,12 @@ const PROGMEM uint8_t FRSKY1_cc2500_conf[][2]={ { CC2500_15_DEVIATN, 0x41 } }; -static void __attribute__((unused)) FRSKY1_init() +static void __attribute__((unused)) FRSKYV_init() { for(uint8_t i=0;i<17;i++) { - uint8_t reg=pgm_read_byte_near(&FRSKY1_cc2500_conf[i][0]); - uint8_t val=pgm_read_byte_near(&FRSKY1_cc2500_conf[i][1]); + uint8_t reg=pgm_read_byte_near(&FRSKYV_cc2500_conf[i][0]); + uint8_t val=pgm_read_byte_near(&FRSKYV_cc2500_conf[i][1]); if(reg==CC2500_0C_FSCTRL0) val=option; CC2500_WriteReg(reg,val); @@ -71,7 +71,7 @@ static void __attribute__((unused)) FRSKY1_init() CC2500_Strobe(CC2500_SIDLE); // Go to idle... } -static uint8_t __attribute__((unused)) FRSKY1_crc8(uint8_t result, uint8_t *data, uint8_t len) +static uint8_t __attribute__((unused)) FRSKYV_crc8(uint8_t result, uint8_t *data, uint8_t len) { for(uint8_t i = 0; i < len; i++) { @@ -85,15 +85,10 @@ static uint8_t __attribute__((unused)) FRSKY1_crc8(uint8_t result, uint8_t *data return result; } -static uint8_t __attribute__((unused)) FRSKY1_crc8_le(uint8_t init, uint8_t *data, uint8_t len) +static uint8_t __attribute__((unused)) FRSKYV_crc8_le(uint8_t *data, uint8_t len) { - uint8_t result = 0; + uint8_t result = 0xD6; - for(uint8_t i = 0; i < 8; i++) - { - result = (result << 1) | (init & 0x01); - init >>= 1; - } for(uint8_t i = 0; i < len; i++) { result = result ^ data[i]; @@ -106,7 +101,7 @@ static uint8_t __attribute__((unused)) FRSKY1_crc8_le(uint8_t init, uint8_t *dat return result; } -static void __attribute__((unused)) FRSKY1_build_bind_packet() +static void __attribute__((unused)) FRSKYV_build_bind_packet() { //0e 03 01 57 12 00 06 0b 10 15 1a 00 00 00 61 packet[0] = 0x0e; //Length @@ -123,10 +118,10 @@ static void __attribute__((unused)) FRSKY1_build_bind_packet() packet[11] = 0x00; packet[12] = 0x00; packet[13] = 0x00; - packet[14] = FRSKY1_crc8(0x93, packet, 14); + packet[14] = FRSKYV_crc8(0x93, packet, 14); } -static uint8_t __attribute__((unused)) FRSKY1_calc_channel() +static uint8_t __attribute__((unused)) FRSKYV_calc_channel() { uint32_t temp=seed; temp = (temp * 0xaa) % 0x7673; @@ -134,7 +129,7 @@ static uint8_t __attribute__((unused)) FRSKY1_calc_channel() return (seed & 0xff) % 0x32; } -static void __attribute__((unused)) FRSKY1_build_data_packet() +static void __attribute__((unused)) FRSKYV_build_data_packet() { uint8_t idx = 0; // transmit lower channels @@ -143,10 +138,10 @@ static void __attribute__((unused)) FRSKY1_build_data_packet() packet[2] = rx_tx_addr[2]; packet[3] = seed & 0xff; packet[4] = seed >> 8; - if (phase == FRSKY1_DATA1 || phase == FRSKY1_DATA3) + if (phase == FRSKYV_DATA1 || phase == FRSKYV_DATA3) packet[5] = 0x0f; else - if(phase == FRSKY1_DATA2 || phase == FRSKY1_DATA4) + if(phase == FRSKYV_DATA2 || phase == FRSKYV_DATA4) { packet[5] = 0xf0; idx=4; // transmit upper channels @@ -159,14 +154,14 @@ static void __attribute__((unused)) FRSKY1_build_data_packet() packet[2*i + 6] = value & 0xff; packet[2*i + 7] = value >> 8; } - packet[14] = FRSKY1_crc8(crc8, packet, 14); + packet[14] = FRSKYV_crc8(crc8, packet, 14); } -uint16_t ReadFRSKY1() +uint16_t ReadFRSKYV() { if(IS_BIND_DONE_on) { // Normal operation - uint8_t chan = FRSKY1_calc_channel(); + uint8_t chan = FRSKYV_calc_channel(); CC2500_Strobe(CC2500_SIDLE); if (option != prev_option) { @@ -174,12 +169,12 @@ uint16_t ReadFRSKY1() prev_option=option; } CC2500_WriteReg(CC2500_0A_CHANNR, chan * 5 + 6); - FRSKY1_build_data_packet(); + FRSKYV_build_data_packet(); - if (phase == FRSKY1_DATA5) + if (phase == FRSKYV_DATA5) { CC2500_SetPower(); - phase = FRSKY1_DATA1; + phase = FRSKYV_DATA1; } else phase++; @@ -188,26 +183,26 @@ uint16_t ReadFRSKY1() return 9006; } // Bind mode - FRSKY1_build_bind_packet(); + FRSKYV_build_bind_packet(); CC2500_Strobe(CC2500_SIDLE); CC2500_WriteReg(CC2500_0A_CHANNR, 0x00); CC2500_WriteData(packet, packet[0]+1); binding_idx++; - if(binding_idx>=FRSKY1_BIND_COUNT) + if(binding_idx>=FRSKYV_BIND_COUNT) BIND_DONE; return 53460; } -uint16_t initFRSKY1() +uint16_t initFRSKYV() { //ID is 15 bits. Using rx_tx_addr[2] and rx_tx_addr[3] since we want to use RX_Num for model match rx_tx_addr[2]&=0x7F; - crc8 = FRSKY1_crc8_le(0x6b, rx_tx_addr+2, 2); + crc8 = FRSKYV_crc8_le(rx_tx_addr+2, 2); - FRSKY1_init(); + FRSKYV_init(); seed = 1; binding_idx=0; - phase = FRSKY1_DATA1; + phase = FRSKYV_DATA1; return 10000; } diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 9fb49cc..2ac6e25 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -31,7 +31,7 @@ enum PROTOCOLS MODE_SERIAL = 0, // Serial commands MODE_FLYSKY = 1, // =>A7105 MODE_HUBSAN = 2, // =>A7105 - MODE_FRSKY = 3, // =>CC2500 + MODE_FRSKYD = 3, // =>CC2500 MODE_HISKY = 4, // =>NRF24L01 MODE_V2X2 = 5, // =>NRF24L01 MODE_DSM = 6, // =>CYRF6936 @@ -53,7 +53,7 @@ enum PROTOCOLS MODE_J6PRO = 22, // =>CYRF6936 MODE_FQ777 = 23, // =>NRF24L01 MODE_ASSAN = 24, // =>NRF24L01 - MODE_FRSKY1 = 25 // =>CC2500 + MODE_FRSKYV = 25 // =>CC2500 }; enum Flysky @@ -516,7 +516,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- => Reserved 0 Flysky 1 Hubsan 2 - Frsky 3 + FrskyD 3 Hisky 4 V2x2 5 DSM 6 @@ -538,7 +538,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- J6PRO 22 FQ777 23 ASSAN 24 - FRSKY1 25 + FrskyV 25 BindBit=> 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index dfff25d..e15a811 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -352,7 +352,7 @@ void Update_All() update_led_status(); #if defined(TELEMETRY) uint8_t protocol=cur_protocol[0]&0x1F; - if( (protocol==MODE_FRSKY) || (protocol==MODE_HUBSAN) || (protocol==MODE_FRSKYX) || (protocol==MODE_DSM) ) + if( (protocol==MODE_FRSKYD) || (protocol==MODE_HUBSAN) || (protocol==MODE_FRSKYX) || (protocol==MODE_DSM) ) TelemetryUpdate(); #endif } @@ -466,20 +466,20 @@ static void protocol_init() remote_callback = ReadHubsan; break; #endif - #if defined(FRSKY_CC2500_INO) - case MODE_FRSKY: + #if defined(FRSKYD_CC2500_INO) + case MODE_FRSKYD: CTRL1_off; //antenna RF2 CTRL2_on; next_callback = initFrSky_2way(); remote_callback = ReadFrSky_2way; break; #endif - #if defined(FRSKY1_CC2500_INO) - case MODE_FRSKY1: + #if defined(FRSKYV_CC2500_INO) + case MODE_FRSKYV: CTRL1_off; //antenna RF2 CTRL2_on; - next_callback = initFRSKY1(); - remote_callback = ReadFRSKY1; + next_callback = initFRSKYV(); + remote_callback = ReadFRSKYV; break; #endif #if defined(FRSKYX_CC2500_INO) diff --git a/Multiprotocol/Telemetry.ino b/Multiprotocol/Telemetry.ino index 22d04d1..54a44cc 100644 --- a/Multiprotocol/Telemetry.ino +++ b/Multiprotocol/Telemetry.ino @@ -108,7 +108,7 @@ void frsky_check_telemetry(uint8_t *pkt,uint8_t len) void frsky_link_frame() { frame[0] = 0xFE; - if ((cur_protocol[0]&0x1F)==MODE_FRSKY) + if ((cur_protocol[0]&0x1F)==MODE_FRSKYD) { compute_RSSIdbm(); frame[1] = pktt[3]; @@ -465,7 +465,7 @@ void TelemetryUpdate() return; } #if defined HUB_TELEMETRY - if(!telemetry_link && (cur_protocol[0]&0x1F) == MODE_FRSKY) + if(!telemetry_link && (cur_protocol[0]&0x1F) == MODE_FRSKYD) { // FrSky frsky_user_frame(); return; diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 878128a..cb5a61b 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -49,8 +49,8 @@ #define J6PRO_CYRF6936_INO #endif #ifdef CC2500_INSTALLED - #define FRSKY_CC2500_INO - #define FRSKY1_CC2500_INO + #define FRSKYD_CC2500_INO + #define FRSKYV_CC2500_INO #define FRSKYX_CC2500_INO #define SFHSS_CC2500_INO #endif @@ -94,7 +94,7 @@ #if defined FRSKYX_CC2500_INO #define SPORT_TELEMETRY #endif - #if defined FRSKY_CC2500_INO + #if defined FRSKYD_CC2500_INO #define HUB_TELEMETRY #endif #endif @@ -148,7 +148,7 @@ const PPM_Parameters PPM_prot[15]= { // Dial Protocol Sub protocol RX_Num Power Auto Bind Option /* 1 */ {MODE_FLYSKY, Flysky , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 2 */ {MODE_HUBSAN, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, -/* 3 */ {MODE_FRSKY , 0 , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning +/* 3 */ {MODE_FRSKYD , 0 , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning /* 4 */ {MODE_HISKY , Hisky , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 5 */ {MODE_V2X2 , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 6 */ {MODE_DSM , DSM2 , 0 , P_HIGH , NO_AUTOBIND , 2 }, // option=2=6 channels @ 22ms @@ -170,7 +170,7 @@ const PPM_Parameters PPM_prot[15]= { V912 MODE_HUBSAN NONE - MODE_FRSKY + MODE_FRSKYD NONE MODE_HISKY Hisky @@ -239,7 +239,7 @@ const PPM_Parameters PPM_prot[15]= { NONE MODE_ASSAN NONE - MODE_FRSKY1 + MODE_FRSKYV NONE */ From e04c573726833116f6194dac4a1536515d8d03ce Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sat, 3 Sep 2016 11:56:39 +0200 Subject: [PATCH 200/293] Renamed FrSky protocols --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 8b4dfdc..61c6610 100644 --- a/README.md +++ b/README.md @@ -67,19 +67,19 @@ Notes: ###Telemetry -There are 4 protocols supporting telemetry: Hubsan, DSM, FrSky and FrSkyX. +There are 4 protocols supporting telemetry: Hubsan, DSM, FrSkyD and FrSkyX. Hubsan displays the battery voltage and TX RSSI. DSM displays TX RSSI and full telemetry. -FrSky displays full telemetry (A0, A1, RX RSSI, TX RSSI and Hub). +FrSkyD displays full telemetry (A0, A1, RX RSSI, TX RSSI and Hub). FrSkyX displays full telemetry (A1, A2, RX RSSI, TX RSSI and Hub). ### If used in PPM mode -Telemetry is available as a serial 9600 8 n 1 output on the TX pin of the Atmega328p using the FRSky hub format for Hubsan, FrSky, FrSkyX and DSM format for DSM2/X. +Telemetry is available as a serial 9600 8 n 1 output on the TX pin of the Atmega328p using the FrSky hub format for Hubsan, FrSkyD, FrSkyX and DSM format for DSM2/X. You can connect it to your TX if it is telemetry enabled or use a bluetooth adapter (HC05/HC06) along with an app on your phone/tablet ([app example](https://play.google.com/store/apps/details?id=biz.onomato.frskydash&hl=fr)) to display telemetry information and setup alerts. @@ -128,7 +128,7 @@ Dial|Protocol|Sub_protocol|RX Num|Power|Auto Bind|Option|RF Module 0|Select serial|||||| 1|FLYSKY|Flysky|0|High|No|0|A7105 2|HUBSAN|-|0|High|No|0|A7105 -3|FRSKY|-|0|High|No|-41|CC2500 +3|FRSKYD|-|0|High|No|-41|CC2500 4|HISKY|Hisky|0|High|No|0|NRF24L01 5|V2X2|-|0|High|No|0|NRF24L01 6|DSM|DSM2|0|High|No|6|CYRF6936 @@ -161,8 +161,8 @@ Hubsan| #####CC2500 RF module Protocol|Sub_protocol --------|------------ -FrSky| -FrSky1| +FrSkyV| +FrSkyD| FrSkyX| |CH_16 |CH_8 @@ -239,7 +239,7 @@ Note: ###RF modules Up to 4 RF modules can be installed: - [A7105](http://www.banggood.com/XL7105-D03-A7105-Modification-Module-Support-Deviation-Galee-Flysky-p-922603.html) for Flysky, Hubsan -- [CC2500](http://www.banggood.com/CC2500-PA-LNA-Romote-Wireless-Module-CC2500-SI4432-NRF24L01-p-922595.html) for FrSky, FrSky1, FrSkyX and SFHSS +- [CC2500](http://www.banggood.com/CC2500-PA-LNA-Romote-Wireless-Module-CC2500-SI4432-NRF24L01-p-922595.html) for FrSkyV, FrSkyD, FrSkyX and SFHSS - [CYRF6936](http://www.ehirobo.com/walkera-wk-devo-s-mod-devo-8-or-12-to-devo-8s-or-12s-upgrade-module.html) for DSM, DEVO, J6Pro - [NRF24L01](http://www.banggood.com/2_4G-NRF24L01-PA-LNA-Wireless-Module-1632mm-Without-Antenna-p-922601.html) for Hisky, V2x2, CX-10, SYMAX and plenty other protocols From 48258dd9dde0eae8cf60a8f59a6bf4523dd8e90a Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sat, 3 Sep 2016 11:57:40 +0200 Subject: [PATCH 201/293] Renamed FrSky protocols --- Protocols_Details.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 00036cf..c378215 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -50,7 +50,18 @@ A|E|T|R|FLIP|LIGHT|PICTURE|VIDEO|HEADLESS *** #CC2500 RF Module -##FRSKY +##FRSKYV = FrSky 1 way +Models: FrSky receivers V8R4, V8R7 and V8FR. + +Extended limits supported + +Option=fine frequency tuning. This value is different for each board. To determine the option value, find the two limits where the RX loses connection then set the option value to half way between them. If you have a 4in1 V2 board the value is around 40. + +CH1|CH2|CH3|CH4 +---|---|---|--- +CH1|CH2|CH3|CH4 + +##FRSKYD Models: FrSky receivers D4R and D8R. DIY RX-F801 and RX-F802 receivers. Extended limits supported @@ -63,17 +74,6 @@ CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 ---|---|---|---|---|---|---|--- CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 -##FRSKY1 = FrSky 1 way -Models: FrSky receivers V8R4, V8R7 and V8FR. - -Extended limits supported - -Option=fine frequency tuning. This value is different for each board. To determine the option value, find the two limits where the RX loses connection then set the option value to half way between them. If you have a 4in1 V2 board the value is around 40. - -CH1|CH2|CH3|CH4 ----|---|---|--- -CH1|CH2|CH3|CH4 - ##FRSKYX Models: FrSky receivers X4R, X6R and X8R. From 8b670498639290af47be460d4135503563249c6d Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sun, 4 Sep 2016 16:46:21 +0200 Subject: [PATCH 202/293] Added NRF24L01_ReadPayloadLength --- Multiprotocol/NRF24l01_SPI.ino | 11 +++++++++++ Multiprotocol/_Config.h | 2 +- 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/Multiprotocol/NRF24l01_SPI.ino b/Multiprotocol/NRF24l01_SPI.ino index 579cffa..717d4d4 100644 --- a/Multiprotocol/NRF24l01_SPI.ino +++ b/Multiprotocol/NRF24l01_SPI.ino @@ -76,6 +76,16 @@ uint8_t NRF24L01_ReadReg(uint8_t reg) NRF_CSN_on; } */ + +static uint8_t __attribute__((unused)) NRF24L01_ReadPayloadLength() +{ + NRF_CSN_off; + SPI_Write(R_RX_PL_WID); + uint8_t len = SPI_Read(); + NRF_CSN_on; + return len; +} + static void NRF24L01_ReadPayload(uint8_t * data, uint8_t length) { NRF_CSN_off; @@ -221,6 +231,7 @@ uint8_t NRF24L01_packet_ack() return PKT_PENDING; } + /////////////// // XN297 emulation layer uint8_t xn297_scramble_enabled=XN297_SCRAMBLED; //enabled by default diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index cb5a61b..66ebe92 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -148,7 +148,7 @@ const PPM_Parameters PPM_prot[15]= { // Dial Protocol Sub protocol RX_Num Power Auto Bind Option /* 1 */ {MODE_FLYSKY, Flysky , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 2 */ {MODE_HUBSAN, 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, -/* 3 */ {MODE_FRSKYD , 0 , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning +/* 3 */ {MODE_FRSKYD, 0 , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning /* 4 */ {MODE_HISKY , Hisky , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 5 */ {MODE_V2X2 , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 6 */ {MODE_DSM , DSM2 , 0 , P_HIGH , NO_AUTOBIND , 2 }, // option=2=6 channels @ 22ms From 2261d655eaf51a0764259c4cc1cc7b46cb128c6f Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sun, 4 Sep 2016 16:47:34 +0200 Subject: [PATCH 203/293] DEVO/J6pro Flash space optimization --- Multiprotocol/CYRF6936_SPI.ino | 34 ++++++++++++++++++++++++++++++++ Multiprotocol/Devo_cyrf6936.ino | 26 ++---------------------- Multiprotocol/J6Pro_cyrf6936.ino | 32 +++++------------------------- 3 files changed, 41 insertions(+), 51 deletions(-) diff --git a/Multiprotocol/CYRF6936_SPI.ino b/Multiprotocol/CYRF6936_SPI.ino index dcf06e1..d37e484 100644 --- a/Multiprotocol/CYRF6936_SPI.ino +++ b/Multiprotocol/CYRF6936_SPI.ino @@ -258,3 +258,37 @@ void CYRF_FindBestChannels(uint8_t *channels, uint8_t len, uint8_t minspace, uin } CYRF_SetTxRxMode(TX_EN); } + +#if defined(DEVO_CYRF6936_INO) || defined(J6PRO_CYRF6936_INO) +const uint8_t PROGMEM DEVO_j6pro_sopcodes[][8] = { + /* Note these are in order transmitted (LSB 1st) */ + {0x3C, 0x37, 0xCC, 0x91, 0xE2, 0xF8, 0xCC, 0x91}, + {0x9B, 0xC5, 0xA1, 0x0F, 0xAD, 0x39, 0xA2, 0x0F}, + {0xEF, 0x64, 0xB0, 0x2A, 0xD2, 0x8F, 0xB1, 0x2A}, + {0x66, 0xCD, 0x7C, 0x50, 0xDD, 0x26, 0x7C, 0x50}, + {0x5C, 0xE1, 0xF6, 0x44, 0xAD, 0x16, 0xF6, 0x44}, + {0x5A, 0xCC, 0xAE, 0x46, 0xB6, 0x31, 0xAE, 0x46}, + {0xA1, 0x78, 0xDC, 0x3C, 0x9E, 0x82, 0xDC, 0x3C}, + {0xB9, 0x8E, 0x19, 0x74, 0x6F, 0x65, 0x18, 0x74}, + {0xDF, 0xB1, 0xC0, 0x49, 0x62, 0xDF, 0xC1, 0x49}, + {0x97, 0xE5, 0x14, 0x72, 0x7F, 0x1A, 0x14, 0x72}, +#if defined(J6PRO_CYRF6936_INO) + {0x82, 0xC7, 0x90, 0x36, 0x21, 0x03, 0xFF, 0x17}, + {0xE2, 0xF8, 0xCC, 0x91, 0x3C, 0x37, 0xCC, 0x91}, //Note: the '03' was '9E' in the Cypress recommended table + {0xAD, 0x39, 0xA2, 0x0F, 0x9B, 0xC5, 0xA1, 0x0F}, //The following are the same as the 1st 8 above, + {0xD2, 0x8F, 0xB1, 0x2A, 0xEF, 0x64, 0xB0, 0x2A}, //but with the upper and lower word swapped + {0xDD, 0x26, 0x7C, 0x50, 0x66, 0xCD, 0x7C, 0x50}, + {0xAD, 0x16, 0xF6, 0x44, 0x5C, 0xE1, 0xF6, 0x44}, + {0xB6, 0x31, 0xAE, 0x46, 0x5A, 0xCC, 0xAE, 0x46}, + {0x9E, 0x82, 0xDC, 0x3C, 0xA1, 0x78, 0xDC, 0x3C}, + {0x6F, 0x65, 0x18, 0x74, 0xB9, 0x8E, 0x19, 0x74}, +#endif +}; +#endif +static void __attribute__((unused)) CYRF_PROGMEM_ConfigSOPCode(const uint8_t *data) +{ + uint8_t code[8]; + for(uint8_t i=0;i<8;i++) + code[i]=pgm_read_byte_near(&data[i]); + CYRF_ConfigSOPCode(code); +} \ No newline at end of file diff --git a/Multiprotocol/Devo_cyrf6936.ino b/Multiprotocol/Devo_cyrf6936.ino index cf56eed..a677de9 100644 --- a/Multiprotocol/Devo_cyrf6936.ino +++ b/Multiprotocol/Devo_cyrf6936.ino @@ -43,28 +43,6 @@ enum { DEVO_BOUND_10, }; -const uint8_t PROGMEM DEVO_sopcodes[][8] = { - /* Note these are in order transmitted (LSB 1st) */ - /* 0 */ {0x3C,0x37,0xCC,0x91,0xE2,0xF8,0xCC,0x91}, //0x91CCF8E291CC373C - /* 1 */ {0x9B,0xC5,0xA1,0x0F,0xAD,0x39,0xA2,0x0F}, //0x0FA239AD0FA1C59B - /* 2 */ {0xEF,0x64,0xB0,0x2A,0xD2,0x8F,0xB1,0x2A}, //0x2AB18FD22AB064EF - /* 3 */ {0x66,0xCD,0x7C,0x50,0xDD,0x26,0x7C,0x50}, //0x507C26DD507CCD66 - /* 4 */ {0x5C,0xE1,0xF6,0x44,0xAD,0x16,0xF6,0x44}, //0x44F616AD44F6E15C - /* 5 */ {0x5A,0xCC,0xAE,0x46,0xB6,0x31,0xAE,0x46}, //0x46AE31B646AECC5A - /* 6 */ {0xA1,0x78,0xDC,0x3C,0x9E,0x82,0xDC,0x3C}, //0x3CDC829E3CDC78A1 - /* 7 */ {0xB9,0x8E,0x19,0x74,0x6F,0x65,0x18,0x74}, //0x7418656F74198EB9 - /* 8 */ {0xDF,0xB1,0xC0,0x49,0x62,0xDF,0xC1,0x49}, //0x49C1DF6249C0B1DF - /* 9 */ {0x97,0xE5,0x14,0x72,0x7F,0x1A,0x14,0x72}, //0x72141A7F7214E597 -}; - -static void __attribute__((unused)) DEVO_ConfigSOPCode(uint8_t val) -{ - uint8_t code[8]; - for(uint8_t i=0;i<8;i++) - code[i]=pgm_read_byte_near(&DEVO_sopcodes[val][i]); - CYRF_ConfigSOPCode(code); -} - static void __attribute__((unused)) DEVO_scramble_pkt() { #ifdef NO_SCRAMBLE @@ -181,7 +159,7 @@ static void __attribute__((unused)) DEVO_cyrf_set_bound_sop_code() uint8_t sopidx = (0xff &((cyrfmfg_id[0] << 2) + cyrfmfg_id[1] + cyrfmfg_id[2])) % 10; CYRF_SetTxRxMode(TX_EN); CYRF_ConfigCRCSeed((crc << 8) + crc); - DEVO_ConfigSOPCode(sopidx); + CYRF_PROGMEM_ConfigSOPCode(DEVO_j6pro_sopcodes[sopidx]); CYRF_SetPower(0x08); } @@ -313,7 +291,7 @@ uint16_t DevoInit() CYRF_GetMfgData(cyrfmfg_id); CYRF_SetTxRxMode(TX_EN); CYRF_ConfigCRCSeed(0x0000); - DEVO_ConfigSOPCode(0); + CYRF_PROGMEM_ConfigSOPCode(DEVO_j6pro_sopcodes[0]); DEVO_set_radio_channels(); hopping_frequency_ptr = hopping_frequency; diff --git a/Multiprotocol/J6Pro_cyrf6936.ino b/Multiprotocol/J6Pro_cyrf6936.ino index f82bb70..02f1743 100644 --- a/Multiprotocol/J6Pro_cyrf6936.ino +++ b/Multiprotocol/J6Pro_cyrf6936.ino @@ -35,30 +35,8 @@ enum PktState { J6PRO_CHAN_4, }; -const uint8_t j6pro_sopcodes[][8] = { - /* Note these are in order transmitted (LSB 1st) */ - {0x3C, 0x37, 0xCC, 0x91, 0xE2, 0xF8, 0xCC, 0x91}, - {0x9B, 0xC5, 0xA1, 0x0F, 0xAD, 0x39, 0xA2, 0x0F}, - {0xEF, 0x64, 0xB0, 0x2A, 0xD2, 0x8F, 0xB1, 0x2A}, - {0x66, 0xCD, 0x7C, 0x50, 0xDD, 0x26, 0x7C, 0x50}, - {0x5C, 0xE1, 0xF6, 0x44, 0xAD, 0x16, 0xF6, 0x44}, - {0x5A, 0xCC, 0xAE, 0x46, 0xB6, 0x31, 0xAE, 0x46}, - {0xA1, 0x78, 0xDC, 0x3C, 0x9E, 0x82, 0xDC, 0x3C}, - {0xB9, 0x8E, 0x19, 0x74, 0x6F, 0x65, 0x18, 0x74}, - {0xDF, 0xB1, 0xC0, 0x49, 0x62, 0xDF, 0xC1, 0x49}, - {0x97, 0xE5, 0x14, 0x72, 0x7F, 0x1A, 0x14, 0x72}, - {0x82, 0xC7, 0x90, 0x36, 0x21, 0x03, 0xFF, 0x17}, - {0xE2, 0xF8, 0xCC, 0x91, 0x3C, 0x37, 0xCC, 0x91}, //Note: the '03' was '9E' in the Cypress recommended table - {0xAD, 0x39, 0xA2, 0x0F, 0x9B, 0xC5, 0xA1, 0x0F}, //The following are the same as the 1st 8 above, - {0xD2, 0x8F, 0xB1, 0x2A, 0xEF, 0x64, 0xB0, 0x2A}, //but with the upper and lower word swapped - {0xDD, 0x26, 0x7C, 0x50, 0x66, 0xCD, 0x7C, 0x50}, - {0xAD, 0x16, 0xF6, 0x44, 0x5C, 0xE1, 0xF6, 0x44}, - {0xB6, 0x31, 0xAE, 0x46, 0x5A, 0xCC, 0xAE, 0x46}, - {0x9E, 0x82, 0xDC, 0x3C, 0xA1, 0x78, 0xDC, 0x3C}, - {0x6F, 0x65, 0x18, 0x74, 0xB9, 0x8E, 0x19, 0x74}, -}; -const uint8_t bind_sop_code[] = {0x62, 0xdf, 0xc1, 0x49, 0xdf, 0xb1, 0xc0, 0x49}; -const uint8_t data_code[] = {0x02, 0xf9, 0x93, 0x97, 0x02, 0xfa, 0x5c, 0xe3, 0x01, 0x2b, 0xf1, 0xdb, 0x01, 0x32, 0xbe, 0x6f}; +const uint8_t PROGMEM j6pro_bind_sop_code[] = {0x62, 0xdf, 0xc1, 0x49, 0xdf, 0xb1, 0xc0, 0x49}; +const uint8_t j6pro_data_code[] = {0x02, 0xf9, 0x93, 0x97, 0x02, 0xfa, 0x5c, 0xe3, 0x01, 0x2b, 0xf1, 0xdb, 0x01, 0x32, 0xbe, 0x6f}; static void __attribute__((unused)) j6pro_build_bind_packet() { @@ -106,7 +84,7 @@ static void __attribute__((unused)) j6pro_cyrf_init() CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0xee); CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x00); CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x00); - CYRF_ConfigDataCode(data_code, 16); + CYRF_ConfigDataCode(j6pro_data_code, 16); CYRF_WritePreamble(0x023333); CYRF_GetMfgData(cyrfmfg_id); @@ -121,7 +99,7 @@ static void __attribute__((unused)) cyrf_bindinit() CYRF_SetPower(0x28); //Deviation using max power, replaced by bind power... CYRF_ConfigRFChannel(0x52); - CYRF_ConfigSOPCode(bind_sop_code); + CYRF_PROGMEM_ConfigSOPCode(j6pro_bind_sop_code); CYRF_ConfigCRCSeed(0x0000); CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4a); CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); @@ -144,7 +122,7 @@ static void __attribute__((unused)) cyrf_datainit() uint16_t crc = (0xff & (cyrfmfg_id[1] - cyrfmfg_id[4] + cyrfmfg_id[5])) | ((0xff & (cyrfmfg_id[2] + cyrfmfg_id[3] - cyrfmfg_id[4] + cyrfmfg_id[5])) << 8); CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x25); - CYRF_ConfigSOPCode(j6pro_sopcodes[sop_idx]); + CYRF_PROGMEM_ConfigSOPCode(DEVO_j6pro_sopcodes[sop_idx]); CYRF_ConfigCRCSeed(crc); } From d96ba9fa463a5bc7bf0259cc909adb98c3e3feec Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sun, 4 Sep 2016 16:48:52 +0200 Subject: [PATCH 204/293] Flysky Flash space optimization --- Multiprotocol/FlySky_a7105.ino | 65 ++++++++++++++++++---------------- 1 file changed, 35 insertions(+), 30 deletions(-) diff --git a/Multiprotocol/FlySky_a7105.ino b/Multiprotocol/FlySky_a7105.ino index a7f4033..43ccffd 100644 --- a/Multiprotocol/FlySky_a7105.ino +++ b/Multiprotocol/FlySky_a7105.ino @@ -50,10 +50,6 @@ enum { FLAG_V912_BTMBTN= 0x80, }; -uint8_t chanrow; -uint8_t chancol; -uint8_t chanoffset; - const uint8_t PROGMEM V912_X17_SEQ[10] = { 0x14, 0x31, 0x40, 0x49, 0x49, // sometime first byte is 0x15 ? 0x49, 0x49, 0x49, 0x49, 0x49, }; @@ -151,25 +147,6 @@ static void __attribute__((unused)) flysky_build_packet(uint8_t init) flysky_apply_extension_flags(); } -const uint8_t PROGMEM tx_channels[16][16] = { - {0x0a, 0x5a, 0x14, 0x64, 0x1e, 0x6e, 0x28, 0x78, 0x32, 0x82, 0x3c, 0x8c, 0x46, 0x96, 0x50, 0xa0}, - {0xa0, 0x50, 0x96, 0x46, 0x8c, 0x3c, 0x82, 0x32, 0x78, 0x28, 0x6e, 0x1e, 0x64, 0x14, 0x5a, 0x0a}, - {0x0a, 0x5a, 0x50, 0xa0, 0x14, 0x64, 0x46, 0x96, 0x1e, 0x6e, 0x3c, 0x8c, 0x28, 0x78, 0x32, 0x82}, - {0x82, 0x32, 0x78, 0x28, 0x8c, 0x3c, 0x6e, 0x1e, 0x96, 0x46, 0x64, 0x14, 0xa0, 0x50, 0x5a, 0x0a}, - {0x28, 0x78, 0x0a, 0x5a, 0x50, 0xa0, 0x14, 0x64, 0x1e, 0x6e, 0x3c, 0x8c, 0x32, 0x82, 0x46, 0x96}, - {0x96, 0x46, 0x82, 0x32, 0x8c, 0x3c, 0x6e, 0x1e, 0x64, 0x14, 0xa0, 0x50, 0x5a, 0x0a, 0x78, 0x28}, - {0x50, 0xa0, 0x28, 0x78, 0x0a, 0x5a, 0x1e, 0x6e, 0x3c, 0x8c, 0x32, 0x82, 0x46, 0x96, 0x14, 0x64}, - {0x64, 0x14, 0x96, 0x46, 0x82, 0x32, 0x8c, 0x3c, 0x6e, 0x1e, 0x5a, 0x0a, 0x78, 0x28, 0xa0, 0x50}, - {0x50, 0xa0, 0x46, 0x96, 0x3c, 0x8c, 0x28, 0x78, 0x0a, 0x5a, 0x32, 0x82, 0x1e, 0x6e, 0x14, 0x64}, - {0x64, 0x14, 0x6e, 0x1e, 0x82, 0x32, 0x5a, 0x0a, 0x78, 0x28, 0x8c, 0x3c, 0x96, 0x46, 0xa0, 0x50}, - {0x46, 0x96, 0x3c, 0x8c, 0x50, 0xa0, 0x28, 0x78, 0x0a, 0x5a, 0x1e, 0x6e, 0x32, 0x82, 0x14, 0x64}, - {0x64, 0x14, 0x82, 0x32, 0x6e, 0x1e, 0x5a, 0x0a, 0x78, 0x28, 0xa0, 0x50, 0x8c, 0x3c, 0x96, 0x46}, - {0x46, 0x96, 0x0a, 0x5a, 0x3c, 0x8c, 0x14, 0x64, 0x50, 0xa0, 0x28, 0x78, 0x1e, 0x6e, 0x32, 0x82}, - {0x82, 0x32, 0x6e, 0x1e, 0x78, 0x28, 0xa0, 0x50, 0x64, 0x14, 0x8c, 0x3c, 0x5a, 0x0a, 0x96, 0x46}, - {0x46, 0x96, 0x0a, 0x5a, 0x50, 0xa0, 0x3c, 0x8c, 0x28, 0x78, 0x1e, 0x6e, 0x32, 0x82, 0x14, 0x64}, - {0x64, 0x14, 0x82, 0x32, 0x6e, 0x1e, 0x78, 0x28, 0x8c, 0x3c, 0xa0, 0x50, 0x5a, 0x0a, 0x96, 0x46}, -}; - uint16_t ReadFlySky() { if (bind_counter) @@ -183,28 +160,56 @@ uint16_t ReadFlySky() else { flysky_build_packet(0); - A7105_WriteData(21, pgm_read_byte_near(&tx_channels[chanrow][chancol])-chanoffset); - chancol = (chancol + 1) % 16; - if (! chancol) //Keep transmit power updated - A7105_SetPower(); + A7105_WriteData(21, hopping_frequency[hopping_frequency_no]); + hopping_frequency_no = (hopping_frequency_no + 1) & 0x0F; + A7105_SetPower(); } return 1510; //1460 on deviation but not working with the latest V911 bricks... Turnigy 9X v2 is 1533, Flysky TX for 9XR/9XR Pro is 1510, V911 TX is 1490. } -uint16_t initFlySky() { +const uint8_t PROGMEM tx_channels[8][4] = { + { 0x12, 0x34, 0x56, 0x78}, + { 0x18, 0x27, 0x36, 0x45}, + { 0x41, 0x82, 0x36, 0x57}, + { 0x84, 0x13, 0x65, 0x72}, + { 0x87, 0x64, 0x15, 0x32}, + { 0x76, 0x84, 0x13, 0x52}, + { 0x71, 0x62, 0x84, 0x35}, + { 0x71, 0x86, 0x43, 0x52} +}; + +uint16_t initFlySky() +{ + uint8_t chanrow; + uint8_t chanoffset; + uint8_t temp; + A7105_Init(INIT_FLYSKY); //flysky_init(); if ((rx_tx_addr[3]&0xF0) > 0x90) // limit offset to 9 as higher values don't work with some RX (ie V912) rx_tx_addr[3]=rx_tx_addr[3]-0x70; chanrow=rx_tx_addr[3] & 0x0F; - chancol=0; chanoffset=rx_tx_addr[3]/16; + // Build frequency hop table + for(uint8_t i=0;i<16;i++) + { + temp=pgm_read_byte_near(&tx_channels[chanrow>>1][i>>2]); + if(i&0x01) + temp&=0x0F; + else + temp>>=4; + temp*=0x0A; + if(i&0x02) + temp+=0x50; + hopping_frequency[((chanrow&1)?15-i:i)]=temp-chanoffset; + } + hopping_frequency_no=0; + if(IS_AUTOBIND_FLAG_on) bind_counter = FLYSKY_BIND_COUNT; else bind_counter = 0; return 2400; } - #endif From a989c3b7d02cde76f4e23dfbfb17774c760331e8 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 9 Sep 2016 12:15:16 +0200 Subject: [PATCH 205/293] HONTAI protocol addition --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 61c6610..fa2b3f5 100644 --- a/README.md +++ b/README.md @@ -227,6 +227,10 @@ Shenqi| FY326| FQ777| ASSAN| +HONTAI| + |HONTAI + |JJRCX1 + |X5C1 Note: - The dial should be set to 0 for serial. Which means all protocol selection pins should be left unconnected. From d4b85e3b1c4caddb437c49cb58a7692174a8613a Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 9 Sep 2016 18:34:20 +0200 Subject: [PATCH 206/293] 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< Date: Sat, 10 Sep 2016 11:28:53 +0800 Subject: [PATCH 207/293] Fix hontai code for X5C1 --- Multiprotocol/Hontai_nrf24l01.ino | 23 +++++++++++++++++------ 1 file changed, 17 insertions(+), 6 deletions(-) diff --git a/Multiprotocol/Hontai_nrf24l01.ino b/Multiprotocol/Hontai_nrf24l01.ino index e25b019..464ca3f 100644 --- a/Multiprotocol/Hontai_nrf24l01.ino +++ b/Multiprotocol/Hontai_nrf24l01.ino @@ -102,9 +102,13 @@ static void __attribute__((unused)) HONTAI_send_packet(uint8_t bind) 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] = convert_channel_8b_scale(AILERON, 63, 0); // Aileron + if(sub_protocol == FORMAT_JJRCX1 || sub_protocol == FORMAT_X5C1) + { packet[4] |= 0x80; // not sure what this bit does + if (sub_protocol == FORMAT_X5C1) + packet[4] |= GET_FLAG(Servo_AUX1, 0x40); ///Lights (X5C1) + } else { packet[4] |= GET_FLAG(Servo_AUX6, 0x80) // RTH @@ -112,11 +116,14 @@ static void __attribute__((unused)) HONTAI_send_packet(uint8_t bind) } packet[5] = convert_channel_8b_scale(ELEVATOR, 0, 63) // Elevator | GET_FLAG(Servo_AUX7, 0x80) // Calibrate - | GET_FLAG(Servo_AUX1, 0x40); // Flip + | GET_FLAG(Servo_AUX2, 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) + if(sub_protocol == FORMAT_X5C1) + packet[7] = 0; // Aileron trim + else + packet[7] = convert_channel_8b_scale(AILERON, 0, 32)-16; // Aileron trim + if(sub_protocol == FORMAT_JJRCX1 || sub_protocol == FORMAT_X5C1) { packet[8] = 0xc0 // Always in expert mode | GET_FLAG(Servo_AUX6, 0x02) // RTH @@ -124,7 +131,11 @@ static void __attribute__((unused)) HONTAI_send_packet(uint8_t bind) } 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 + if (sub_protocol == FORMAT_X5C1) + packet[9] = 0; // Elevator trim + else + packet[9] = convert_channel_8b_scale(ELEVATOR, 0, 32)-16; // Elevator trim + packet_size=HONTAI_PACKET_SIZE; } crc16(packet, packet_size); From eb3905447fb65a5231f299d6d66e6f0ae72dc799 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sat, 10 Sep 2016 09:25:36 +0200 Subject: [PATCH 208/293] Hontai channels fix --- Multiprotocol/Hontai_nrf24l01.ino | 49 ++++++++----------------------- 1 file changed, 13 insertions(+), 36 deletions(-) diff --git a/Multiprotocol/Hontai_nrf24l01.ino b/Multiprotocol/Hontai_nrf24l01.ino index 464ca3f..508ae50 100644 --- a/Multiprotocol/Hontai_nrf24l01.ino +++ b/Multiprotocol/Hontai_nrf24l01.ino @@ -25,29 +25,6 @@ #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, @@ -94,7 +71,7 @@ static void __attribute__((unused)) HONTAI_send_packet(uint8_t bind) else { if(sub_protocol == FORMAT_JJRCX1) - packet[0] = GET_FLAG(CHANNEL_ARM, 0x02); + packet[0] = GET_FLAG(Servo_AUX2, 0x02); // Arm else packet[0] = 0x0b; @@ -103,34 +80,34 @@ static void __attribute__((unused)) HONTAI_send_packet(uint8_t bind) packet[3] = (convert_channel_8b_scale(THROTTLE, 0, 127) << 1) // Throttle | GET_FLAG(Servo_AUX3, 0x01); // Picture packet[4] = convert_channel_8b_scale(AILERON, 63, 0); // Aileron - if(sub_protocol == FORMAT_JJRCX1 || sub_protocol == FORMAT_X5C1) - { - packet[4] |= 0x80; // not sure what this bit does - if (sub_protocol == FORMAT_X5C1) - packet[4] |= GET_FLAG(Servo_AUX1, 0x40); ///Lights (X5C1) - } - else + if(sub_protocol == FORMAT_HONTAI) { packet[4] |= GET_FLAG(Servo_AUX6, 0x80) // RTH | GET_FLAG(Servo_AUX5, 0x40); // Headless } + else + { + packet[4] |= 0x80; // not sure what this bit does + if (sub_protocol == FORMAT_X5C1) + packet[4] |= GET_FLAG(Servo_AUX2, 0x40); // Lights (X5C1) + } packet[5] = convert_channel_8b_scale(ELEVATOR, 0, 63) // Elevator | GET_FLAG(Servo_AUX7, 0x80) // Calibrate - | GET_FLAG(Servo_AUX2, 0x40); // Flip + | GET_FLAG(Servo_AUX1, 0x40); // Flip packet[6] = convert_channel_8b_scale(RUDDER, 0, 63) // Rudder | GET_FLAG(Servo_AUX4, 0x80); // Video if(sub_protocol == FORMAT_X5C1) packet[7] = 0; // Aileron trim else - packet[7] = convert_channel_8b_scale(AILERON, 0, 32)-16; // Aileron trim - if(sub_protocol == FORMAT_JJRCX1 || sub_protocol == FORMAT_X5C1) + packet[7] = convert_channel_8b_scale(AILERON, 0, 32)-16; // Aileron trim + if(sub_protocol == FORMAT_HONTAI) + packet[8] = convert_channel_8b_scale(RUDDER, 0, 32)-16; // Rudder trim + else { 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 if (sub_protocol == FORMAT_X5C1) packet[9] = 0; // Elevator trim else From c0204cb7259c6732a71c597937ddadc19da983e2 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sat, 10 Sep 2016 09:27:53 +0200 Subject: [PATCH 209/293] Update Protocols_Details.md --- Protocols_Details.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index c378215..cb7d48e 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -328,6 +328,19 @@ Dual Rate: +100%=full range, Throttle Hold: +100%=hold, Idle Up: +100%=3D, GYRO: ###Sub_protocol FEILUN Same channels assignement as above. +##HONTAI +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11 +---|---|---|---|---|---|---|---|---|----|---- +A|E|T|R|FLIP|LED|PICTURE|VIDEO|HEADLESS|RTH|CAL + +###Sub_protocol HONTAI +###Sub_protocol JJRCX1 +CH6| +---| +ARM| + +###Sub_protocol X5C1 + ##MJXQ Autobind protocol From f0ced15e6a2d6f7552bd35d9cfb15ca44c5d0cf8 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sat, 10 Sep 2016 09:39:33 +0200 Subject: [PATCH 210/293] Update Protocols_Details.md --- Protocols_Details.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Protocols_Details.md b/Protocols_Details.md index cb7d48e..b504fa9 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -329,6 +329,8 @@ Dual Rate: +100%=full range, Throttle Hold: +100%=hold, Idle Up: +100%=3D, GYRO: Same channels assignement as above. ##HONTAI +Autobind protocol + CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11 ---|---|---|---|---|---|---|---|---|----|---- A|E|T|R|FLIP|LED|PICTURE|VIDEO|HEADLESS|RTH|CAL From 7918b392e8704f29d08c1cde60ebec8623e95773 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sat, 10 Sep 2016 09:42:39 +0200 Subject: [PATCH 211/293] Hontai fix --- Multiprotocol/Hontai_nrf24l01.ino | 1 + 1 file changed, 1 insertion(+) diff --git a/Multiprotocol/Hontai_nrf24l01.ino b/Multiprotocol/Hontai_nrf24l01.ino index 508ae50..a172bd9 100644 --- a/Multiprotocol/Hontai_nrf24l01.ino +++ b/Multiprotocol/Hontai_nrf24l01.ino @@ -238,6 +238,7 @@ uint16_t HONTAI_callback() uint16_t initHONTAI() { + BIND_IN_PROGRESS; // autobind protocol bind_counter = HONTAI_BIND_COUNT; HONTAI_initialize_txid(); HONTAI_init(); From c34ab489721b2839ecf3ae9c1fe156c50d46787b Mon Sep 17 00:00:00 2001 From: pascallanger Date: Sat, 10 Sep 2016 10:06:50 +0200 Subject: [PATCH 212/293] Update Protocols_Details.md --- Protocols_Details.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index b504fa9..bd898da 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -341,7 +341,7 @@ CH6| ---| ARM| -###Sub_protocol X5C1 +###Sub_protocol X5C1 clone ##MJXQ Autobind protocol From 3d26e6e34054dee5cff6e9d909209034b2b352b8 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 12 Sep 2016 16:40:45 +0200 Subject: [PATCH 213/293] Hontai/X5C1 fix --- Multiprotocol/Hontai_nrf24l01.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Multiprotocol/Hontai_nrf24l01.ino b/Multiprotocol/Hontai_nrf24l01.ino index a172bd9..08ce83a 100644 --- a/Multiprotocol/Hontai_nrf24l01.ino +++ b/Multiprotocol/Hontai_nrf24l01.ino @@ -97,7 +97,7 @@ static void __attribute__((unused)) HONTAI_send_packet(uint8_t bind) packet[6] = convert_channel_8b_scale(RUDDER, 0, 63) // Rudder | GET_FLAG(Servo_AUX4, 0x80); // Video if(sub_protocol == FORMAT_X5C1) - packet[7] = 0; // Aileron trim + packet[7] = convert_channel_8b_scale(AILERON, 0, 63)-31; // Aileron trim else packet[7] = convert_channel_8b_scale(AILERON, 0, 32)-16; // Aileron trim if(sub_protocol == FORMAT_HONTAI) @@ -109,9 +109,9 @@ static void __attribute__((unused)) HONTAI_send_packet(uint8_t bind) | GET_FLAG(Servo_AUX5, 0x01); // Headless } if (sub_protocol == FORMAT_X5C1) - packet[9] = 0; // Elevator trim + packet[9] = convert_channel_8b_scale(ELEVATOR, 0, 63)-31; // Elevator trim else - packet[9] = convert_channel_8b_scale(ELEVATOR, 0, 32)-16; // Elevator trim + packet[9] = convert_channel_8b_scale(ELEVATOR, 0, 32)-16; // Elevator trim packet_size=HONTAI_PACKET_SIZE; } From 236ac52925b4ecd9b15f86f0e5e33192591462f2 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 12 Sep 2016 16:41:40 +0200 Subject: [PATCH 214/293] Fix global ID random --- Multiprotocol/ASSAN_nrf24l01.ino | 1 - Multiprotocol/FrSkyX_cc2500.ino | 3 -- Multiprotocol/Hubsan_a7105.ino | 1 - Multiprotocol/Multiprotocol.ino | 83 +++++++++++++++++++++++++------- 4 files changed, 65 insertions(+), 23 deletions(-) diff --git a/Multiprotocol/ASSAN_nrf24l01.ino b/Multiprotocol/ASSAN_nrf24l01.ino index 3add45a..5295a07 100644 --- a/Multiprotocol/ASSAN_nrf24l01.ino +++ b/Multiprotocol/ASSAN_nrf24l01.ino @@ -156,7 +156,6 @@ static void __attribute__((unused)) ASSAN_initialize_txid() // Alternate frequency has some random do { - randomSeed((uint32_t)analogRead(A6) << 10 | analogRead(A7)); freq2=random(0xfefefefe)%9; freq2+=freq*2-5; } diff --git a/Multiprotocol/FrSkyX_cc2500.ino b/Multiprotocol/FrSkyX_cc2500.ino index 3820432..be159b3 100644 --- a/Multiprotocol/FrSkyX_cc2500.ino +++ b/Multiprotocol/FrSkyX_cc2500.ino @@ -303,10 +303,7 @@ uint16_t ReadFrSkyX() uint16_t initFrSkyX() { while(!chanskip) - { - randomSeed((uint32_t)analogRead(A6) << 10 | analogRead(A7)); chanskip=random(0xfefefefe)%47; - } while((chanskip-ctr)%4) ctr=(ctr+1)%4; diff --git a/Multiprotocol/Hubsan_a7105.ino b/Multiprotocol/Hubsan_a7105.ino index ff54c5a..de0c2bf 100644 --- a/Multiprotocol/Hubsan_a7105.ino +++ b/Multiprotocol/Hubsan_a7105.ino @@ -345,7 +345,6 @@ uint16_t initHubsan() { const uint8_t allowed_ch[] = {0x14, 0x1e, 0x28, 0x32, 0x3c, 0x46, 0x50, 0x5a, 0x64, 0x6e, 0x78, 0x82}; A7105_Init(INIT_HUBSAN); //hubsan_init(); - randomSeed((uint32_t)analogRead(A6) << 10 | analogRead(A7)); sessionid = random(0xfefefefe) + ((uint32_t)random(0xfefefefe) << 16); channel = allowed_ch[random(0xfefefefe) % sizeof(allowed_ch)]; diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index c46a5c9..7c00573 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -95,10 +95,15 @@ uint8_t protocol_flags=0,protocol_flags2=0; // PPM variable volatile uint16_t PPM_data[NUM_CHN]; +//Random variable +volatile uint32_t gWDT_entropy=0; + // Serial variables #ifdef INVERT_TELEMETRY // enable bit bash for serial - #define BASH_SERIAL 1 + #ifndef XMEGA + #define BASH_SERIAL 1 + #endif #define INVERT_SERIAL 1 #endif #define BAUD 100000 @@ -179,6 +184,7 @@ void setup() TCCR1A = 0; TCCR1B = (1 << CS11); //prescaler8, set timer1 to increment every 0.5us(16Mhz) and start timer #endif + random_init(); // Set Chip selects A7105_CS_on; @@ -216,11 +222,14 @@ void setup() LED_OFF; LED_SET_OUTPUT; - // Read or create protocol id - MProtocol_id_master=random_id(10,false); - //Init RF modules modules_reset(); + + //Init the seed with a random value created from watchdog timer for all protocols requiring random values + randomSeed(random_value()); + + // Read or create protocol id + MProtocol_id_master=random_id(10,false); #ifdef ENABLE_PPM //Protocol and interrupts initialization @@ -856,28 +865,41 @@ static void set_rx_tx_addr(uint32_t id) rx_tx_addr[4] = 0xC1; // for YD717: always uses first data port } +static void random_init(void) +{ + cli(); // Temporarily turn off interrupts, until WDT configured + MCUSR = 0; // Use the MCU status register to reset flags for WDR, BOR, EXTR, and POWR + WDTCSR |= _BV(WDCE); // WDT control register, This sets the Watchdog Change Enable (WDCE) flag, which is needed to set the prescaler + WDTCSR = _BV(WDIE); // Watchdog interrupt enable (WDIE) + sei(); // Turn interupts on +} + +static uint32_t random_value(void) +{ + while (!gWDT_entropy); + return gWDT_entropy; +} + static uint32_t random_id(uint16_t adress, uint8_t create_new) { uint32_t id; uint8_t txid[4]; - if (eeprom_read_byte((uint8_t*)(adress+10))==0xf0 && !create_new) + if(eeprom_read_byte((uint8_t*)(adress+10))==0xf0 && !create_new) { // TXID exists in EEPROM eeprom_read_block((void*)txid,(const void*)adress,4); id=(txid[0] | ((uint32_t)txid[1]<<8) | ((uint32_t)txid[2]<<16) | ((uint32_t)txid[3]<<24)); + if(id!=0x2AD141A7) //ID with seed=0 + return id; } - else - { // if not generate a random ID - randomSeed((uint32_t)analogRead(A6)<<10|analogRead(A7));//seed - // - id = random(0xfefefefe) + ((uint32_t)random(0xfefefefe) << 16); - txid[0]= (id &0xFF); - txid[1] = ((id >> 8) & 0xFF); - txid[2] = ((id >> 16) & 0xFF); - txid[3] = ((id >> 24) & 0xFF); - eeprom_write_block((const void*)txid,(void*)adress,4); - eeprom_write_byte((uint8_t*)(adress+10),0xf0);//write bind flag in eeprom. - } + // Generate a random ID + id = random(0xfefefefe) + ((uint32_t)random(0xfefefefe) << 16); + txid[0]= (id &0xFF); + txid[1] = ((id >> 8) & 0xFF); + txid[2] = ((id >> 16) & 0xFF); + txid[3] = ((id >> 24) & 0xFF); + eeprom_write_block((const void*)txid,(void*)adress,4); + eeprom_write_byte((uint8_t*)(adress+10),0xf0);//write bind flag in eeprom. return id; } @@ -1156,4 +1178,29 @@ ISR(TIMER1_COMPB_vect, ISR_NOBLOCK ) CLR_TIMSK1_OCIE1B; // Disable interrupt on compare B match tx_resume(); } -#endif //ENABLE_SERIAL \ No newline at end of file +#endif //ENABLE_SERIAL + +// Random interrupt service routine called every time the WDT interrupt is triggered. +// It is only enabled at startup to generate a seed. +ISR(WDT_vect) +{ + static uint8_t gWDT_buffer_position=0; + #define gWDT_buffer_SIZE 32 + static uint8_t gWDT_buffer[gWDT_buffer_SIZE]; + gWDT_buffer[gWDT_buffer_position] = TCNT1L; // Record the Timer 1 low byte (only one needed) + gWDT_buffer_position++; // every time the WDT interrupt is triggered + if (gWDT_buffer_position >= gWDT_buffer_SIZE) + { + // The following code is an implementation of Jenkin's one at a time hash + for(uint8_t gWDT_loop_counter = 0; gWDT_loop_counter < gWDT_buffer_SIZE; ++gWDT_loop_counter) + { + gWDT_entropy += gWDT_buffer[gWDT_loop_counter]; + gWDT_entropy += (gWDT_entropy << 10); + gWDT_entropy ^= (gWDT_entropy >> 6); + } + gWDT_entropy += (gWDT_entropy << 3); + gWDT_entropy ^= (gWDT_entropy >> 11); + gWDT_entropy += (gWDT_entropy << 15); + WDTCSR = 0; // Disable Watchdog interrupt + } +} From 242f9d55ed02808be8da649cbffeb1404b838a1c Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 12 Sep 2016 16:42:13 +0200 Subject: [PATCH 215/293] DSM: loads of changes... --- Multiprotocol/DSM_cyrf6936.ino | 397 ++++++++++++++++----------------- 1 file changed, 190 insertions(+), 207 deletions(-) diff --git a/Multiprotocol/DSM_cyrf6936.ino b/Multiprotocol/DSM_cyrf6936.ino index f1c213e..8034462 100644 --- a/Multiprotocol/DSM_cyrf6936.ino +++ b/Multiprotocol/DSM_cyrf6936.ino @@ -17,29 +17,45 @@ #include "iface_cyrf6936.h" -#define RANDOM_CHANNELS 0 // disabled -//#define RANDOM_CHANNELS 1 // enabled -#define BIND_CHANNEL 0x0d //13 This can be any odd channel +#define DSM2_RANDOM_CHANNELS 0 // disabled +//#define DSM2_RANDOM_CHANNELS 1 // enabled +#define DSM_BIND_CHANNEL 0x0d //13 This can be any odd channel //During binding we will send BIND_COUNT/2 packets //One packet each 10msec -#define BIND_COUNT1 600 +#define DSM_BIND_COUNT 300 enum { - DSM2_BIND = 0, - DSM2_CHANSEL = BIND_COUNT1 + 0, - DSM2_CH1_WRITE_A = BIND_COUNT1 + 1, - DSM2_CH1_CHECK_A = BIND_COUNT1 + 2, - DSM2_CH2_WRITE_A = BIND_COUNT1 + 3, - DSM2_CH2_CHECK_A = BIND_COUNT1 + 4, - DSM2_CH2_READ_A = BIND_COUNT1 + 5, - DSM2_CH1_WRITE_B = BIND_COUNT1 + 6, - DSM2_CH1_CHECK_B = BIND_COUNT1 + 7, - DSM2_CH2_WRITE_B = BIND_COUNT1 + 8, - DSM2_CH2_CHECK_B = BIND_COUNT1 + 9, - DSM2_CH2_READ_B = BIND_COUNT1 + 10, + DSM_BIND_WRITE=0, + DSM_BIND_CHECK, + DSM_BIND_READ, + DSM_CHANSEL, + DSM_CH1_WRITE_A, + DSM_CH1_CHECK_A, + DSM_CH2_WRITE_A, + DSM_CH2_CHECK_A, + DSM_CH2_READ_A, + DSM_CH1_WRITE_B, + DSM_CH1_CHECK_B, + DSM_CH2_WRITE_B, + DSM_CH2_CHECK_B, + DSM_CH2_READ_B, }; +// +uint8_t sop_col; +uint8_t ch_map[14]; +const uint8_t PROGMEM ch_map_progmem[][12] = { + {0, 1, 2, 3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, //Guess + {0, 1, 2, 3, 4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, //Guess + {1, 5, 2, 3, 0, 4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, //HP6DSM + {1, 5, 2, 4, 3, 6, 0, 0xff, 0xff, 0xff, 0xff, 0xff}, //DX6i + {1, 5, 2, 3, 6, 0xff, 0xff, 4, 0, 7, 0xff, 0xff}, //DX8 + {3, 2, 1, 5, 0, 4, 6, 7, 8, 0xff, 0xff, 0xff}, //DM9 + {3, 2, 1, 5, 0, 4, 6, 7, 8, 9, 0xff, 0xff}, //Guess + {3, 2, 1, 5, 0, 4, 6, 7, 8, 9, 10, 0xff}, //Guess + {3, 2, 1, 5, 0, 4, 6, 7, 8, 9, 10, 11} }; //Guess + const uint8_t PROGMEM pncodes[5][9][8] = { /* Note these are in order transmitted (LSB 1st) */ { /* Row 0 */ @@ -105,11 +121,6 @@ static void __attribute__((unused)) read_code(uint8_t *buf, uint8_t row, uint8_t buf[i]=pgm_read_byte_near( &pncodes[row][col][i] ); } -// -uint8_t sop_col; -uint8_t data_col; -uint8_t binding; - static void __attribute__((unused)) build_bind_packet() { uint8_t i; @@ -128,14 +139,16 @@ static void __attribute__((unused)) build_bind_packet() packet[9] = sum & 0xff; packet[10] = 0x01; //??? packet[11] = option>3?option:option+4; - if(sub_protocol==DSMX) //DSMX type + if(sub_protocol==DSMX) //DSMX type #if defined DSM_TELEMETRY - packet[12] = 0xb2; // Telemetry on + packet[12] = 0xb2; // Telemetry on #else packet[12] = option<8? 0xa2 : 0xb2; // Telemetry off #endif else packet[12] = option<8?0x01:0x02; + //TODO: packet[12]=0x12 for DSM/2048@11ms + packet[13] = 0x00; //??? for(i = 8; i < 14; i++) sum += packet[i]; @@ -143,128 +156,44 @@ static void __attribute__((unused)) build_bind_packet() packet[15] = sum & 0xff; } -static uint8_t __attribute__((unused)) PROTOCOL_SticksMoved(uint8_t init) -{ -#define STICK_MOVEMENT 15*(servo_max_125-servo_min_125)/100 // defines when the bind dialog should be interrupted (stick movement STICK_MOVEMENT %) - static uint16_t ele_start, ail_start; - uint16_t ele = Servo_data[ELEVATOR];//CHAN_ReadInput(MIXER_MapChannel(INP_ELEVATOR)); - uint16_t ail = Servo_data[AILERON];//CHAN_ReadInput(MIXER_MapChannel(INP_AILERON)); - if(init) { - ele_start = ele; - ail_start = ail; - return 0; - } - uint16_t ele_diff = ele_start - ele;//abs(ele_start - ele); - uint16_t ail_diff = ail_start - ail;//abs(ail_start - ail); - return ((ele_diff + ail_diff) > STICK_MOVEMENT);// -} - -static void __attribute__((unused)) build_data_packet(uint8_t upper)// +static void __attribute__((unused)) build_data_packet(uint8_t upper) { uint8_t i; - uint8_t bits; + uint8_t bits=11; //2048 - uint8_t ch_map[] = {3, 2, 1, 5, 0, 4, 6, 7, 8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //9 Channels - DM9 TX - switch(option>3?option:option+4) // Create channel map based on number of channels - { - case 12: - ch_map[11]=11; // 12 channels - case 11: - ch_map[10]=10; // 11 channels - case 10: - ch_map[9]=9; // 10 channels - break; - case 8: - memcpy(ch_map,"\x01\x05\x02\x03\x06\xFF\xFF\x04\x00\x07",10); // 8 channels - DX8 TX - break; - case 7: - memcpy(ch_map,"\x01\x05\x02\x04\x03\x06\x00",7); // 7 channels - DX6i TX - break; - case 6: - memcpy(ch_map,"\x01\x05\x02\x03\x00\x04\xFF",7); // 6 channels - HP6DSM TX - break; - case 4: - case 5: - memcpy(ch_map,"\x00\x01\x02\x03\xFF\xFF\xFF",7); // 4 channels - Guess - if(option&0x01) - ch_map[4]=4; // 5 channels - Guess - break; - } // - if( binding && PROTOCOL_SticksMoved(0) ) - binding = 0; if (sub_protocol==DSMX) { packet[0] = cyrfmfg_id[2]; packet[1] = cyrfmfg_id[3]; - bits=11; } else { packet[0] = (0xff ^ cyrfmfg_id[2]); packet[1] = (0xff ^ cyrfmfg_id[3]); - bits=10; + if(option<8) //1024 for 7 channels or less -> Note this is not true for DSM2 @11ms... TODO + bits=10; } // - uint16_t max = 1 << bits;//max=2048 for DSMX & 1024 for DSM2 less than 8 ch and 2048 otherwise - //uint16_t pct_100 = (uint32_t)max * 100 / 150;//682 1024*100/150 - // + uint16_t max = (1 << bits) - 1; + uint8_t chans=0; + if(upper && option>7) + chans=7; for (i = 0; i < 7; i++) { - uint8_t idx = ch_map[upper * 7 + i];//1,5,2,3,0,4 + uint8_t idx = ch_map[chans + i];//1,5,2,3,0,4 uint16_t value = 0xffff;; if (idx != 0xff) { - if (binding) + if (!IS_BIND_DONE_on) { // Failsafe position during binding value=max/2; //all channels to middle if(idx==0) value=1; //except throttle } else - { - switch(idx) - { - case 0: - value=Servo_data[THROTTLE];//85.75-938.25=125%//171-853=100% - break; - case 1: - value=Servo_data[AILERON]; - break; - case 2: - value=Servo_data[ELEVATOR]; - break; - case 3: - value=Servo_data[RUDDER]; - break; - case 4: - value=Servo_data[AUX1]; - break; - case 5: - value=Servo_data[AUX2]; - break; - case 6: - value=Servo_data[AUX3]; - break; - case 7: - value=Servo_data[AUX4]; - break; - case 8: - value=Servo_data[AUX5]; - break; - case 9: - value=Servo_data[AUX6]; - break; - case 10: - value=Servo_data[AUX7]; - break; - case 11: - value=Servo_data[AUX8]; - break; - } - value=map(value,servo_min_125,servo_max_125,0,max-1); - } - value |= (upper && i == 0 ? 0x8000 : 0) | (idx << bits); + value=map(Servo_data[CH_TAER[idx]],servo_min_125,servo_max_125,0,max); + value |= (upper ? 0x8000 : 0) | (idx << bits); } packet[i*2+2] = (value >> 8) & 0xff; packet[i*2+3] = (value >> 0) & 0xff; @@ -276,7 +205,7 @@ static uint8_t __attribute__((unused)) get_pn_row(uint8_t channel) return (sub_protocol == DSMX ? (channel - 2) % 5 : channel % 5); } -const uint8_t init_vals[][2] = { +const uint8_t PROGMEM init_vals[][2] = { {CYRF_02_TX_CTRL, 0x02}, //0x00 in deviation but needed to know when transmit is over {CYRF_05_RX_CTRL, 0x00}, {CYRF_28_CLK_EN, 0x02}, @@ -296,7 +225,7 @@ const uint8_t init_vals[][2] = { {CYRF_10_FRAMING_CFG, 0x4a}, //set sop len and threshold {CYRF_29_RX_ABORT, 0x0f}, //Clear RX abort? {CYRF_03_TX_CFG, 0x38 | CYRF_BIND_POWER}, //Set 64chip, SDR mode - {CYRF_10_FRAMING_CFG, 0x4a}, //set sop len and threshold + {CYRF_10_FRAMING_CFG, 0x4E}, //0x4a}, //set sop len and threshold {CYRF_1F_TX_OVERRIDE, 0x04}, //disable tx CRC {CYRF_1E_RX_OVERRIDE, 0x14}, //disable rx crc {CYRF_14_EOP_CTRL, 0x02}, //set EOP sync == 2 @@ -306,23 +235,23 @@ const uint8_t init_vals[][2] = { static void __attribute__((unused)) cyrf_config() { for(uint8_t i = 0; i < sizeof(init_vals) / 2; i++) - CYRF_WriteRegister(init_vals[i][0], init_vals[i][1]); + CYRF_WriteRegister(pgm_read_byte_near(&init_vals[i][0]), pgm_read_byte_near(&init_vals[i][1])); CYRF_WritePreamble(0x333304); CYRF_ConfigRFChannel(0x61); } -static void __attribute__((unused)) initialize_bind_state() +static void __attribute__((unused)) initialize_bind_phase() { uint8_t code[32]; - CYRF_ConfigRFChannel(BIND_CHANNEL); //This seems to be random? - uint8_t pn_row = get_pn_row(BIND_CHANNEL); - //printf("Ch: %d Row: %d SOP: %d Data: %d\n", BIND_CHANNEL, pn_row, sop_col, data_col); + CYRF_ConfigRFChannel(DSM_BIND_CHANNEL); //This seems to be random? + uint8_t pn_row = get_pn_row(DSM_BIND_CHANNEL); + //printf("Ch: %d Row: %d SOP: %d Data: %d\n", DSM_BIND_CHANNEL, pn_row, sop_col, 7 - sop_col); CYRF_ConfigCRCSeed(crc); read_code(code,pn_row,sop_col,8); CYRF_ConfigSOPCode(code); - read_code(code,pn_row,data_col,16); + read_code(code,pn_row,7 - sop_col,16); read_code(code+16,0,8,8); memcpy(code + 24, (void *)"\xc6\x94\x22\xfe\x48\xe6\x57\x4e", 8); CYRF_ConfigDataCode(code, 32); @@ -330,7 +259,7 @@ static void __attribute__((unused)) initialize_bind_state() build_bind_packet(); } -const uint8_t data_vals[][2] = { +const uint8_t PROGMEM data_vals[][2] = { {CYRF_05_RX_CTRL, 0x83}, //Initialize for reading RSSI {CYRF_29_RX_ABORT, 0x20}, {CYRF_0F_XACT_CFG, 0x24}, @@ -351,21 +280,21 @@ const uint8_t data_vals[][2] = { static void __attribute__((unused)) cyrf_configdata() { for(uint8_t i = 0; i < sizeof(data_vals) / 2; i++) - CYRF_WriteRegister(data_vals[i][0], data_vals[i][1]); + CYRF_WriteRegister(pgm_read_byte_near(&data_vals[i][0]), pgm_read_byte_near(&data_vals[i][1])); } static void __attribute__((unused)) set_sop_data_crc() { uint8_t code[16]; uint8_t pn_row = get_pn_row(hopping_frequency[hopping_frequency_no]); - //printf("Ch: %d Row: %d SOP: %d Data: %d\n", ch[hopping_frequency_no], pn_row, sop_col, data_col); + //printf("Ch: %d Row: %d SOP: %d Data: %d\n", ch[hopping_frequency_no], pn_row, sop_col, 7 - sop_col); CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]); CYRF_ConfigCRCSeed(crc); crc=~crc; read_code(code,pn_row,sop_col,8); CYRF_ConfigSOPCode(code); - read_code(code,pn_row,data_col,16); + read_code(code,pn_row,7 - sop_col,16); CYRF_ConfigDataCode(code, 16); if(sub_protocol == DSMX) @@ -408,128 +337,179 @@ static void __attribute__((unused)) calc_dsmx_channel() } } +static uint8_t __attribute__((unused)) DSM_Check_RX_packet() +{ + uint8_t result=1; // assume good packet + + uint16_t sum = 384 - 0x10; + for(uint8_t i = 1; i < 9; i++) + { + sum += pkt[i]; + if(i<5) + if(pkt[i] != (0xff ^ cyrfmfg_id[i])) + result=0; // bad packet + } + if( pkt[9] != (sum>>8) && pkt[10] != (uint8_t)sum ) + result=0; + return result; +} + uint16_t ReadDsm() { #define DSM_CH1_CH2_DELAY 4010 // Time between write of channel 1 and channel 2 #define DSM_WRITE_DELAY 1550 // Time after write to verify write complete -#define DSM_READ_DELAY 600 // Time before write to check read state, and switch channels. Was 400 but 500 seems what the 328p needs to read a packet +#define DSM_READ_DELAY 600 // Time before write to check read phase, and switch channels. Was 400 but 600 seems what the 328p needs to read a packet uint16_t start; - - switch(state) + uint8_t rx_phase; + uint8_t len; + + switch(phase) { - default: - //Binding - state++; - if(state & 1) - { - //Send packet on even states - //Note state has already incremented, so this is actually 'even' state - CYRF_WriteDataPacket(packet); - return 8500; +//#define BIND_TEST +#ifndef BIND_TEST + case DSM_BIND_WRITE: + if(bind_counter--==0) + phase=DSM_CHANSEL; + CYRF_WriteDataPacket(packet); + return 10000; +#else + case DSM_BIND_WRITE: + if(bind_counter--==0) + phase=DSM_BIND_CHECK; + CYRF_WriteDataPacket(packet); + return 10000; + case DSM_BIND_CHECK: + CYRF_ConfigDataCode((const uint8_t *)"\x98\x88\x1B\xE4\x30\x79\x03\x84\xC9\x2C\x06\x93\x86\xB9\x9E", 16); + CYRF_SetTxRxMode(RX_EN); //Receive mode + CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); //Prepare to receive + phase++; // change from BIND_CHECK to BIND_READ + return 2000; + case DSM_BIND_READ: + //Read data from RX + rx_phase = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS); + if((rx_phase & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing) + rx_phase |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS); + if((rx_phase & 0x07) == 0x02) + { // data received + CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // need to set RXOW before data read + len=CYRF_ReadRegister(CYRF_09_RX_COUNT); + if(len>MAX_PKT-2) + len=MAX_PKT-2; + CYRF_ReadDataPacketLen(pkt+1, len); + if(len==10 && DSM_Check_RX_packet()) + { + pkt[0]=0x80; + telemetry_link=1; // send received data on serial + CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); + CYRF_SetTxRxMode(TX_EN); //Write mode + phase++; + return 2000; + } } - else - { - //Check status on odd states - CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS); - return 1500; - } - case DSM2_CHANSEL: + //Force end read phase + CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x2C); // Force end phase + start=micros(); + while ((uint16_t)micros()-start < 100) // Wait max 100 µs + if((CYRF_ReadRegister(CYRF_0F_XACT_CFG) & 0x20) == 0) + break; + CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x0C); // Read + CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); //Prepare to receive + return 7000; +#endif + case DSM_CHANSEL: BIND_DONE; //Select channels and configure for writing data //CYRF_FindBestChannels(ch, 2, 10, 1, 79); cyrf_configdata(); CYRF_SetTxRxMode(TX_EN); hopping_frequency_no = 0; - state = DSM2_CH1_WRITE_A; // in fact state++ + phase = DSM_CH1_WRITE_A; // in fact phase++ set_sop_data_crc(); return 10000; - case DSM2_CH1_WRITE_A: - case DSM2_CH1_WRITE_B: - case DSM2_CH2_WRITE_A: - case DSM2_CH2_WRITE_B: - build_data_packet(state == DSM2_CH1_WRITE_B);// build lower or upper channels - CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS); // clear IRQ flags + case DSM_CH1_WRITE_A: + case DSM_CH1_WRITE_B: + case DSM_CH2_WRITE_A: + case DSM_CH2_WRITE_B: + build_data_packet(phase == DSM_CH1_WRITE_B||phase == DSM_CH2_WRITE_B); // build lower or upper channels + CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS); // clear IRQ flags CYRF_WriteDataPacket(packet); - state++; // change from WRITE to CHECK mode + phase++; // change from WRITE to CHECK mode return DSM_WRITE_DELAY; - case DSM2_CH1_CHECK_A: - case DSM2_CH1_CHECK_B: + case DSM_CH1_CHECK_A: + case DSM_CH1_CHECK_B: start=micros(); - while ((uint16_t)micros()-start < 500) // Wait max 500µs + while ((uint16_t)micros()-start < 500) // Wait max 500µs if(CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02) break; set_sop_data_crc(); - state++; // change from CH1_CHECK to CH2_WRITE + phase++; // change from CH1_CHECK to CH2_WRITE return DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY; - case DSM2_CH2_CHECK_A: - case DSM2_CH2_CHECK_B: + case DSM_CH2_CHECK_A: + case DSM_CH2_CHECK_B: start=micros(); - while ((uint16_t)micros()-start < 500) // Wait max 500µs + while ((uint16_t)micros()-start < 500) // Wait max 500µs if(CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02) break; - if (state == DSM2_CH2_CHECK_A) - CYRF_SetPower(0x28); //Keep transmit power in sync + if (phase == DSM_CH2_CHECK_A) + CYRF_SetPower(0x28); //Keep transmit power in sync #if defined DSM_TELEMETRY - state++; // change from CH2_CHECK to CH2_READ + phase++; // change from CH2_CHECK to CH2_READ if(option<=3 || option>7) { // disable telemetry for option between 4 and 7 ie 4,5,6,7 channels @11ms since it does not work... CYRF_SetTxRxMode(RX_EN); //Receive mode CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive } return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY; - case DSM2_CH2_READ_A: - case DSM2_CH2_READ_B: + case DSM_CH2_READ_A: + case DSM_CH2_READ_B: //Read telemetry - uint8_t rx_state = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS); - if((rx_state & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing) - rx_state |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS); - if((rx_state & 0x07) == 0x02) + rx_phase = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS); + if((rx_phase & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing) + rx_phase |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS); + if((rx_phase & 0x07) == 0x02) { // good data (complete with no errors) CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // need to set RXOW before data read - uint8_t len=CYRF_ReadRegister(CYRF_09_RX_COUNT); + len=CYRF_ReadRegister(CYRF_09_RX_COUNT); if(len>MAX_PKT-2) len=MAX_PKT-2; CYRF_ReadDataPacketLen(pkt+1, len); - pkt[0]=CYRF_ReadRegister(CYRF_13_RSSI)&0x1F; // store RSSI of the received telemetry signal + pkt[0]=CYRF_ReadRegister(CYRF_13_RSSI)&0x1F; // store RSSI of the received telemetry signal telemetry_link=1; } - if (state == DSM2_CH2_READ_A && option <= 3) // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms + if (phase == DSM_CH2_READ_A && option <= 3) // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms { - //Force end read state - CYRF_WriteRegister(CYRF_0F_XACT_CFG, (CYRF_ReadRegister(CYRF_0F_XACT_CFG) | 0x20)); // Force end state + //Force end read phase + CYRF_WriteRegister(CYRF_0F_XACT_CFG, (CYRF_ReadRegister(CYRF_0F_XACT_CFG) | 0x20)); // Force end phase start=micros(); - while ((uint16_t)micros()-start < 100) // Wait max 100 µs + while ((uint16_t)micros()-start < 100) // Wait max 100 µs if((CYRF_ReadRegister(CYRF_0F_XACT_CFG) & 0x20) == 0) break; - state = DSM2_CH2_READ_B; - CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive + phase = DSM_CH2_READ_B; + CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive return 11000; } - if (state == DSM2_CH2_READ_A && option>7) - state = DSM2_CH1_WRITE_B; //Transmit upper + if (phase == DSM_CH2_READ_A) + phase = DSM_CH1_WRITE_B; //Transmit upper else - state = DSM2_CH1_WRITE_A; //Force 11ms if option>3 ie 4,5,6,7 channels @11ms + phase = DSM_CH1_WRITE_A; //Transmit lower CYRF_SetTxRxMode(TX_EN); //Write mode set_sop_data_crc(); return DSM_READ_DELAY; #else // No telemetry set_sop_data_crc(); - if (state == DSM2_CH2_CHECK_A) + if (phase == DSM_CH2_CHECK_A) { - if(option < 8) + if(option < 4) //Normal mode 22ms { - state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper) - if(option>3) - return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ; // force 11ms if option>3 ie 4,5,6,7 channels @11ms - else - return 22000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ; // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms + phase = DSM_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper) + return 22000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ; // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms } - else - state = DSM2_CH1_WRITE_B; // change from CH2_CHECK_A to CH1_WRITE_A (to transmit upper) + else //11ms mode + phase = DSM_CH1_WRITE_B; // change from CH2_CHECK_A to CH1_WRITE_A (to transmit upper) } else - state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_B to CH1_WRITE_A (upper already transmitted so transmit lower) + phase = DSM_CH1_WRITE_A; // change from CH2_CHECK_B to CH1_WRITE_A (upper already transmitted so transmit lower) return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY; #endif } @@ -549,11 +529,10 @@ uint16_t initDsm() calc_dsmx_channel(); else { -#if RANDOM_CHANNELS == 1 +#if DSM2_RANDOM_CHANNELS == 1 uint8_t tmpch[10]; CYRF_FindBestChannels(tmpch, 10, 5, 3, 75); // - randomSeed((uint32_t)analogRead(A6)<<10|analogRead(A7));//seed uint8_t idx = random(0xfefefefe) % 10; hopping_frequency[0] = tmpch[idx]; while(1) @@ -574,23 +553,27 @@ uint16_t initDsm() crc = ~((cyrfmfg_id[0] << 8) + cyrfmfg_id[1]); // sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07; - data_col = 7 - sop_col; + + // Create channel map based on number of channels + uint8_t temp=option>3?option-4:option; + if(temp>8) + temp=8; + for(uint8_t i=0;i<12;i++) + ch_map[i]=pgm_read_byte_near(&ch_map_progmem[temp][i]); + ch_map[12]=0xFF; + ch_map[13]=0xFF; CYRF_SetTxRxMode(TX_EN); // if(IS_AUTOBIND_FLAG_on) { - state = DSM2_BIND; - PROTOCOL_SticksMoved(1); //Initialize Stick position - initialize_bind_state(); - binding = 1; + initialize_bind_phase(); + phase = DSM_BIND_WRITE; + bind_counter=DSM_BIND_COUNT; } else - { - state = DSM2_CHANSEL;// - binding = 0; - } + phase = DSM_CHANSEL;// return 10000; } -#endif +#endif \ No newline at end of file From 8470f4f7fbbfff31f0a6b475f1e054f7343c5d9c Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 12 Sep 2016 21:42:55 +0200 Subject: [PATCH 216/293] DSM: fixed BIND_TEST... --- Multiprotocol/DSM_cyrf6936.ino | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/Multiprotocol/DSM_cyrf6936.ino b/Multiprotocol/DSM_cyrf6936.ino index 8034462..b17cf21 100644 --- a/Multiprotocol/DSM_cyrf6936.ino +++ b/Multiprotocol/DSM_cyrf6936.ino @@ -101,6 +101,8 @@ const uint8_t PROGMEM pncodes[5][9][8] = { /* Col 6 */ {0xBF, 0x54, 0x98, 0xB9, 0xB7, 0x30, 0x5A, 0x88}, /* Col 7 */ {0x35, 0xD1, 0xFC, 0x97, 0x23, 0xD4, 0xC9, 0x88}, /* Col 8 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93} +// Wrong values used by Orange TX/RX +// /* Col 8 */ {0x88, 0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40} }, { /* Row 4 */ /* Col 0 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93}, @@ -346,7 +348,7 @@ static uint8_t __attribute__((unused)) DSM_Check_RX_packet() { sum += pkt[i]; if(i<5) - if(pkt[i] != (0xff ^ cyrfmfg_id[i])) + if(pkt[i] != (0xff ^ cyrfmfg_id[i-1])) result=0; // bad packet } if( pkt[9] != (sum>>8) && pkt[10] != (uint8_t)sum ) From 47bae635488923505d241d5fbba38de56ca6d501 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 12 Sep 2016 21:44:30 +0200 Subject: [PATCH 217/293] Orange TX module compilation fixes --- Multiprotocol/CYRF6936_SPI.ino | 6 + Multiprotocol/MultiOrange.cpp.xmega | 298 +++++++++++++++------------- Multiprotocol/Multiprotocol.ino | 28 ++- 3 files changed, 185 insertions(+), 147 deletions(-) diff --git a/Multiprotocol/CYRF6936_SPI.ino b/Multiprotocol/CYRF6936_SPI.ino index d37e484..2b2d52a 100644 --- a/Multiprotocol/CYRF6936_SPI.ino +++ b/Multiprotocol/CYRF6936_SPI.ino @@ -102,9 +102,15 @@ void CYRF_SetTxRxMode(uint8_t mode) //Set the post tx/rx state CYRF_WriteRegister(CYRF_0F_XACT_CFG, mode == TX_EN ? 0x28 : 0x2C); // 4=IDLE, 8=TX, C=RX if(mode == TX_EN) +#ifdef DSM_BLUE + CYRF_WriteRegister(CYRF_0E_GPIO_CTRL,0x20); // XOUT=1, PACTL=0 + else + CYRF_WriteRegister(CYRF_0E_GPIO_CTRL,0x80); // XOUT=0, PACTL=1 +#else CYRF_WriteRegister(CYRF_0E_GPIO_CTRL,0x80); // XOUT=1, PACTL=0 else CYRF_WriteRegister(CYRF_0E_GPIO_CTRL,0x20); // XOUT=0, PACTL=1 +#endif } } /* diff --git a/Multiprotocol/MultiOrange.cpp.xmega b/Multiprotocol/MultiOrange.cpp.xmega index 9c94c2d..37daadd 100644 --- a/Multiprotocol/MultiOrange.cpp.xmega +++ b/Multiprotocol/MultiOrange.cpp.xmega @@ -3,6 +3,15 @@ #define XMEGA 1 +#define XOUT 0x80 +#define PACTL 0x20 + +// For BLUE module use: +//#define DSM_BLUE +//#define XOUT 0x20 +//#define PACTL 0x80 + + #include #include #include @@ -25,6 +34,9 @@ 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) ; @@ -35,6 +47,7 @@ extern long map(long x, long in_min, long in_max, long out_min, long out_max) ; extern uint32_t millis(void) ; extern uint32_t micros(void) ; extern void delayMicroseconds(uint16_t x) ; +extern void delayMilliseconds(unsigned long ms) ; extern void init(void) ; extern int analogRead(uint8_t pin) ; @@ -74,9 +87,9 @@ extern uint16_t ReadDsm() ; #define FRACT_INC ((MICROSECONDS_PER_TIMER0_OVERFLOW % 1000) >> 3) #define FRACT_MAX (1000 >> 3) -volatile unsigned long timer0_overflow_count = 0; -volatile unsigned long timer0_millis = 0; -static unsigned char timer0_fract = 0; +//volatile unsigned long timer0_overflow_count = 0; +//volatile unsigned long timer0_millis = 0; +//static unsigned char timer0_fract = 0; @@ -155,137 +168,136 @@ static unsigned char timer0_fract = 0; //} - -ISR(TCC0_OVF_vect) -{ - // copy these to local variables so they can be stored in registers - // (volatile variables must be read from memory on every access) - unsigned long m = timer0_millis; - unsigned char f = timer0_fract; - - m += MILLIS_INC; - f += FRACT_INC; - if (f >= FRACT_MAX) { - f -= FRACT_MAX; - m += 1; - } - - timer0_fract = f; - timer0_millis = m; - timer0_overflow_count++; -} - -unsigned long millis() -{ - unsigned long m; - uint8_t oldSREG = SREG; - - // disable interrupts while we read timer0_millis or we might get an - // inconsistent value (e.g. in the middle of a write to timer0_millis) - cli(); - m = timer0_millis; - SREG = oldSREG; - - return m; -} - -unsigned long micros() -{ - unsigned long m; - uint8_t oldSREG = SREG, t; - - cli(); - m = timer0_overflow_count; - t = TCC0.CNT ; - - if ((TCC0.INTFLAGS & TC0_OVFIF_bm) && (t < 255)) - m++; - - SREG = oldSREG; - - return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond()); -} - -void delayMilliseconds(unsigned long ms) -{ - uint16_t start = (uint16_t)micros(); - - while (ms > 0) { - yield(); - if (((uint16_t)micros() - start) >= 1000) { - ms--; - start += 1000; - } - } -} - -/* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */ -void delayMicroseconds(unsigned int us) -{ - // calling avrlib's delay_us() function with low values (e.g. 1 or - // 2 microseconds) gives delays longer than desired. - //delay_us(us); -#if F_CPU >= 20000000L - // for the 20 MHz clock on rare Arduino boards - - // for a one-microsecond delay, simply wait 2 cycle and return. The overhead - // of the function call yields a delay of exactly a one microsecond. - __asm__ __volatile__ ( - "nop" "\n\t" - "nop"); //just waiting 2 cycle - if (--us == 0) - return; - - // the following loop takes a 1/5 of a microsecond (4 cycles) - // per iteration, so execute it five times for each microsecond of - // delay requested. - us = (us<<2) + us; // x5 us - - // account for the time taken in the preceeding commands. - us -= 2; - -#elif F_CPU >= 16000000L - // for the 16 MHz clock on most Arduino boards - - // for a one-microsecond delay, simply return. the overhead - // of the function call yields a delay of approximately 1 1/8 us. - if (--us == 0) - return; - - // the following loop takes a quarter of a microsecond (4 cycles) - // per iteration, so execute it four times for each microsecond of - // delay requested. - us <<= 2; - - // account for the time taken in the preceeding commands. - us -= 2; -#else - // for the 8 MHz internal clock on the ATmega168 - - // for a one- or two-microsecond delay, simply return. the overhead of - // the function calls takes more than two microseconds. can't just - // subtract two, since us is unsigned; we'd overflow. - if (--us == 0) - return; - if (--us == 0) - return; - - // the following loop takes half of a microsecond (4 cycles) - // per iteration, so execute it twice for each microsecond of - // delay requested. - us <<= 1; - - // partially compensate for the time taken by the preceeding commands. - // we can't subtract any more than this or we'd overflow w/ small delays. - us--; -#endif - - // busy wait - __asm__ __volatile__ ( - "1: sbiw %0,1" "\n\t" // 2 cycles - "brne 1b" : "=w" (us) : "0" (us) // 2 cycles - ); -} +//ISR(TCC0_OVF_vect) +//{ +// // copy these to local variables so they can be stored in registers +// // (volatile variables must be read from memory on every access) +// unsigned long m = timer0_millis; +// unsigned char f = timer0_fract; +// +// m += MILLIS_INC; +// f += FRACT_INC; +// if (f >= FRACT_MAX) { +// f -= FRACT_MAX; +// m += 1; +// } +// +// timer0_fract = f; +// timer0_millis = m; +// timer0_overflow_count++; +//} +// +//unsigned long millis() +//{ +// unsigned long m; +// uint8_t oldSREG = SREG; +// +// // disable interrupts while we read timer0_millis or we might get an +// // inconsistent value (e.g. in the middle of a write to timer0_millis) +// cli(); +// m = timer0_millis; +// SREG = oldSREG; +// +// return m; +//} +// +//unsigned long micros() +//{ +// unsigned long m; +// uint8_t oldSREG = SREG, t; +// +// cli(); +// m = timer0_overflow_count; +// t = TCC0.CNT ; +// +// if ((TCC0.INTFLAGS & TC0_OVFIF_bm) && (t < 255)) +// m++; +// +// SREG = oldSREG; +// +// return ((m << 8) + t) * (64 / clockCyclesPerMicrosecond()); +//} +// +//void delayMilliseconds(unsigned long ms) +//{ +// uint16_t start = (uint16_t)micros(); +// +// while (ms > 0) { +// yield(); +// if (((uint16_t)micros() - start) >= 1000) { +// ms--; +// start += 1000; +// } +// } +//} +// +///* Delay for the given number of microseconds. Assumes a 8 or 16 MHz clock. */ +//void delayMicroseconds(unsigned int us) +//{ +// // calling avrlib's delay_us() function with low values (e.g. 1 or +// // 2 microseconds) gives delays longer than desired. +// //delay_us(us); +//#if F_CPU >= 20000000L +// // for the 20 MHz clock on rare Arduino boards +// +// // for a one-microsecond delay, simply wait 2 cycle and return. The overhead +// // of the function call yields a delay of exactly a one microsecond. +// __asm__ __volatile__ ( +// "nop" "\n\t" +// "nop"); //just waiting 2 cycle +// if (--us == 0) +// return; +// +// // the following loop takes a 1/5 of a microsecond (4 cycles) +// // per iteration, so execute it five times for each microsecond of +// // delay requested. +// us = (us<<2) + us; // x5 us +// +// // account for the time taken in the preceeding commands. +// us -= 2; +// +//#elif F_CPU >= 16000000L +// // for the 16 MHz clock on most Arduino boards +// +// // for a one-microsecond delay, simply return. the overhead +// // of the function call yields a delay of approximately 1 1/8 us. +// if (--us == 0) +// return; +// +// // the following loop takes a quarter of a microsecond (4 cycles) +// // per iteration, so execute it four times for each microsecond of +// // delay requested. +// us <<= 2; +// +// // account for the time taken in the preceeding commands. +// us -= 2; +//#else +// // for the 8 MHz internal clock on the ATmega168 +// +// // for a one- or two-microsecond delay, simply return. the overhead of +// // the function calls takes more than two microseconds. can't just +// // subtract two, since us is unsigned; we'd overflow. +// if (--us == 0) +// return; +// if (--us == 0) +// return; +// +// // the following loop takes half of a microsecond (4 cycles) +// // per iteration, so execute it twice for each microsecond of +// // delay requested. +// us <<= 1; +// +// // partially compensate for the time taken by the preceeding commands. +// // we can't subtract any more than this or we'd overflow w/ small delays. +// us--; +//#endif +// +// // busy wait +// __asm__ __volatile__ ( +// "1: sbiw %0,1" "\n\t" // 2 cycles +// "brne 1b" : "=w" (us) : "0" (us) // 2 cycles +// ); +//} #ifndef cbi #define cbi(sfr, bit) (_SFR_BYTE(sfr) &= ~_BV(bit)) @@ -329,15 +341,15 @@ void init() // TCC0 counts 0-255 at 4uS clock rate - EVSYS.CH2MUX = 0x80 + 0x07 ; // Prescaler of 128 - TCC0.CTRLB = 0 ; - TCC0.CTRLC = 0 ; - TCC0.CTRLD = 0 ; - TCC0.CTRLE = 0 ; - TCC0.INTCTRLA = 0x01 ; - TCC0.INTCTRLB = 0 ; - TCC0.PER = 0x00FF ; - TCC0.CTRLA = 0x0A ; +// EVSYS.CH2MUX = 0x80 + 0x07 ; // Prescaler of 128 +// TCC0.CTRLB = 0 ; +// TCC0.CTRLC = 0 ; +// TCC0.CTRLD = 0 ; +// TCC0.CTRLE = 0 ; +// TCC0.INTCTRLA = 0x01 ; +// TCC0.INTCTRLB = 0 ; +// TCC0.PER = 0x00FF ; +// TCC0.CTRLA = 0x0A ; #if defined(ADCSRA) diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 7c00573..e548bef 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -95,9 +95,10 @@ uint8_t protocol_flags=0,protocol_flags2=0; // PPM variable volatile uint16_t PPM_data[NUM_CHN]; +#ifndef XMEGA //Random variable volatile uint32_t gWDT_entropy=0; - +#endif // Serial variables #ifdef INVERT_TELEMETRY // enable bit bash for serial @@ -183,8 +184,8 @@ void setup() // Timer1 config TCCR1A = 0; TCCR1B = (1 << CS11); //prescaler8, set timer1 to increment every 0.5us(16Mhz) and start timer + random_init(); #endif - random_init(); // Set Chip selects A7105_CS_on; @@ -225,8 +226,10 @@ void setup() //Init RF modules modules_reset(); +#ifndef XMEGA //Init the seed with a random value created from watchdog timer for all protocols requiring random values randomSeed(random_value()); +#endif // Read or create protocol id MProtocol_id_master=random_id(10,false); @@ -419,7 +422,9 @@ inline void tx_resume() if(!IS_TX_PAUSE_on) { #ifdef XMEGA + cli() ; USARTC0.CTRLA = (USARTC0.CTRLA & 0xFC) | 0x01 ; // Resume telemetry by enabling transmitter interrupt + sei() ; #else #ifndef BASH_SERIAL UCSR0B |= _BV(UDRIE0); // Resume telemetry by enabling transmitter interrupt @@ -865,6 +870,7 @@ static void set_rx_tx_addr(uint32_t id) rx_tx_addr[4] = 0xC1; // for YD717: always uses first data port } +#ifndef XMEGA static void random_init(void) { cli(); // Temporarily turn off interrupts, until WDT configured @@ -879,6 +885,7 @@ static uint32_t random_value(void) while (!gWDT_entropy); return gWDT_entropy; } +#endif static uint32_t random_id(uint16_t adress, uint8_t create_new) { @@ -963,7 +970,6 @@ uint8_t SPI_Read(void) // replacement millis() and micros() // These work polled, no interrupts // micros() MUST be called at least once every 32 milliseconds -#ifndef XMEGA uint16_t MillisPrecount ; uint16_t lastTimerValue ; uint32_t TotalMicros ; @@ -1052,12 +1058,24 @@ void delayMicroseconds(unsigned int us) return; us <<= 2; // * 4 us -= 2; // - 2 - __asm__ __volatile__ ( +#ifdef XMEGA + __asm__ __volatile__ ( + "1: sbiw %0,1" "\n\t" // 2 cycles + "nop \n" + "nop \n" + "nop \n" + "nop \n" + "brne 1b" : "=w" (us) : "0" (us) // 2 cycles + ); +#else + __asm__ __volatile__ ( "1: sbiw %0,1" "\n\t" // 2 cycles "brne 1b" : "=w" (us) : "0" (us) // 2 cycles ); +#endif } +#ifndef XMEGA void init() { // this needs to be called before setup() or some functions won't work there @@ -1180,6 +1198,7 @@ ISR(TIMER1_COMPB_vect, ISR_NOBLOCK ) } #endif //ENABLE_SERIAL +#ifndef XMEGA // Random interrupt service routine called every time the WDT interrupt is triggered. // It is only enabled at startup to generate a seed. ISR(WDT_vect) @@ -1204,3 +1223,4 @@ ISR(WDT_vect) WDTCSR = 0; // Disable Watchdog interrupt } } +#endif From ea7d0cdef5b21d032ae6e1881980910817b4dfe0 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 13 Sep 2016 16:38:04 +0200 Subject: [PATCH 218/293] E010 semi arbitrary transmitter ID --- Multiprotocol/MJXQ_nrf24l01.ino | 24 ++++++++---------------- 1 file changed, 8 insertions(+), 16 deletions(-) diff --git a/Multiprotocol/MJXQ_nrf24l01.ino b/Multiprotocol/MJXQ_nrf24l01.ino index cda417b..bd6ef81 100644 --- a/Multiprotocol/MJXQ_nrf24l01.ino +++ b/Multiprotocol/MJXQ_nrf24l01.ino @@ -68,10 +68,10 @@ static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind) packet[0] = convert_channel_8b(THROTTLE); packet[1] = convert_channel_s8b(RUDDER); packet[4] = 0x40; // rudder does not work well with dyntrim - packet[2] = convert_channel_s8b(ELEVATOR); - packet[5] = MJXQ_CHAN2TRIM(packet[2]); // trim elevator + packet[2] = 0x80 ^ convert_channel_s8b(ELEVATOR); + packet[5] = GET_FLAG(Servo_AUX5, 1) ? 0x40 : MJXQ_CHAN2TRIM(packet[2]); // trim elevator packet[3] = convert_channel_s8b(AILERON); - packet[6] = MJXQ_CHAN2TRIM(packet[3]); // trim aileron + packet[6] = GET_FLAG(Servo_AUX5, 1) ? 0x40 : MJXQ_CHAN2TRIM(packet[3]); // trim aileron packet[7] = rx_tx_addr[0]; packet[8] = rx_tx_addr[1]; packet[9] = rx_tx_addr[2]; @@ -109,11 +109,6 @@ static void __attribute__((unused)) MJXQ_send_packet(uint8_t bind) } break; case X600: - if(Servo_AUX5) //HEADLESS - { // driven trims cause issues when headless is enabled - packet[5] = 0x40; - packet[6] = 0x40; - } packet[10] = GET_FLAG(!Servo_AUX2, 0x02); //LED packet[11] = GET_FLAG(Servo_AUX6, 0x01); //RTH if (!bind) @@ -213,18 +208,15 @@ static void __attribute__((unused)) MJXQ_init2() static void __attribute__((unused)) MJXQ_initialize_txid() { + rx_tx_addr[0]&=0xF8; if (sub_protocol == E010) { - rx_tx_addr[0]=0x90; - rx_tx_addr[1]=0x1C; - rx_tx_addr[2]=0x00; + rx_tx_addr[1]=(rx_tx_addr[1]&0xF0)|0x0C; + rx_tx_addr[2]&=0xF0; } else - if (sub_protocol == WLH08) - rx_tx_addr[0]&=0xF8; // txid must be multiple of 8 - else - for(uint8_t i=0;i<3;i++) - rx_tx_addr[i]=pgm_read_byte_near( &MJXQ_map_txid[rx_tx_addr[4]%3][i] ); + for(uint8_t i=0;i<3;i++) + rx_tx_addr[i]=pgm_read_byte_near( &MJXQ_map_txid[rx_tx_addr[4]%3][i] ); } uint16_t MJXQ_callback() From 4c2d6d78ea1e6f1e356171bd8a93e5540553866d Mon Sep 17 00:00:00 2001 From: pascallanger Date: Tue, 13 Sep 2016 17:21:35 +0200 Subject: [PATCH 219/293] E010 now supports multi IDs --- Protocols_Details.md | 1 - 1 file changed, 1 deletion(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index bd898da..77c242c 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -357,7 +357,6 @@ Only 3 TX IDs available, change RX_Num value 0..2 to cycle through them Only 3 TX IDs available, change RX_Num value 0..2 to cycle through them ###Sub_protocol H26D ###Sub_protocol E010 -Only 1 TX ID available ##MT99XX Autobind protocol From cafeacf69ff4bbf28170db58bb283f7a4f43610c Mon Sep 17 00:00:00 2001 From: pascallanger Date: Wed, 14 Sep 2016 18:29:31 +0200 Subject: [PATCH 220/293] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fa2b3f5..81224bb 100644 --- a/README.md +++ b/README.md @@ -128,7 +128,7 @@ Dial|Protocol|Sub_protocol|RX Num|Power|Auto Bind|Option|RF Module 0|Select serial|||||| 1|FLYSKY|Flysky|0|High|No|0|A7105 2|HUBSAN|-|0|High|No|0|A7105 -3|FRSKYD|-|0|High|No|-41|CC2500 +3|FRSKYD|-|0|High|No|40|CC2500 4|HISKY|Hisky|0|High|No|0|NRF24L01 5|V2X2|-|0|High|No|0|NRF24L01 6|DSM|DSM2|0|High|No|6|CYRF6936 From 04bdf3f26a838c64a9886049b78b51b7952446e5 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 15 Sep 2016 12:38:49 +0200 Subject: [PATCH 221/293] Multi core extended to support up to 63 protocols Compatible with ersky9x at this time. --- Multiprotocol/Multiprotocol.h | 19 ++++-- Multiprotocol/Multiprotocol.ino | 112 ++++++++++++++++---------------- Multiprotocol/Telemetry.ino | 16 ++--- 3 files changed, 79 insertions(+), 68 deletions(-) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 34d3af8..4668f65 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -54,7 +54,8 @@ enum PROTOCOLS MODE_FQ777 = 23, // =>NRF24L01 MODE_ASSAN = 24, // =>NRF24L01 MODE_FRSKYV = 25, // =>CC2500 - MODE_HONTAI = 26 // =>NRF24L01 + MODE_HONTAI = 26, // =>NRF24L01 + MODE_OPENLRS = 27, // =>OpenLRS hardware }; enum Flysky @@ -74,6 +75,14 @@ enum DSM DSM2 = 0, DSMX = 1 }; +enum +{ + DSM2_22 = 0, + DSM2_11 = 1, + DSMX_22 = 2, + DSMX_11 = 3, + AUTO = 4 +}; enum YD717 { YD717 = 0, @@ -144,7 +153,7 @@ enum HONTAI struct PPM_Parameters { - uint8_t protocol : 5; + uint8_t protocol : 6; uint8_t sub_proto : 3; uint8_t rx_num : 4; uint8_t power : 1; @@ -515,10 +524,11 @@ enum { ************************** Serial: 100000 Baud 8e2 _ xxxx xxxx p -- Total of 26 bytes - Stream[0] = 0x55 + Stream[0] = 0x55 sub_protocol values are 0..31 + Stream[0] = 0x54 sub_protocol values are 32..63 header Stream[1] = sub_protocol|BindBit|RangeCheckBit|AutoBindBit; - sub_protocol is 0..31 (bits 0..4) + sub_protocol is 0..31 (bits 0..4), value should be added with 32 if Stream[0] = 0x54 => Reserved 0 Flysky 1 Hubsan 2 @@ -546,6 +556,7 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- ASSAN 24 FrskyV 25 HONTAI 26 + OpenLRS 27 BindBit=> 0x80 1=Bind/0=No AutoBindBit=> 0x40 1=Yes /0=No RangeCheck=> 0x20 1=Yes /0=No diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index e548bef..54a1ab8 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -40,8 +40,6 @@ uint32_t MProtocol_id;//tx id, uint32_t MProtocol_id_master; uint32_t blink=0; -uint8_t prev_option; -uint8_t prev_power=0xFD; // unused power value // uint16_t counter; uint8_t channel; @@ -108,7 +106,7 @@ volatile uint32_t gWDT_entropy=0; #define INVERT_SERIAL 1 #endif #define BAUD 100000 -#define RXBUFFER_SIZE 25 +#define RXBUFFER_SIZE 26 #define TXBUFFER_SIZE 32 volatile uint8_t rx_buff[RXBUFFER_SIZE]; volatile uint8_t rx_ok_buff[RXBUFFER_SIZE]; @@ -119,9 +117,11 @@ volatile uint8_t discard_frame = 0; //Serial protocol uint8_t sub_protocol; +uint8_t protocol; uint8_t option; -uint8_t cur_protocol[2]; -uint8_t prev_protocol=0; +uint8_t cur_protocol[3]; +uint8_t prev_option; +uint8_t prev_power=0xFD; // unused power value // Telemetry #define MAX_PKT 27 @@ -239,7 +239,7 @@ void setup() if(mode_select != MODE_SERIAL) { // PPM mode_select--; - cur_protocol[0] = PPM_prot[mode_select].protocol; + protocol = PPM_prot[mode_select].protocol; sub_protocol = PPM_prot[mode_select].sub_proto; RX_num = PPM_prot[mode_select].rx_num; MProtocol_id = RX_num + MProtocol_id_master; @@ -264,9 +264,9 @@ void setup() #endif //ENABLE_PPM { // Serial #ifdef ENABLE_SERIAL - cur_protocol[0]=0; - cur_protocol[1]=0; - prev_protocol=0; + for(uint i=0;i<3;i++) + cur_protocol[i]=0; + protocol=0; servo_max_100=SERIAL_MAX_100; servo_min_100=SERIAL_MIN_100; servo_max_125=SERIAL_MAX_125; servo_min_125=SERIAL_MIN_125; Mprotocol_serial_init(); // Configure serial and enable RX interrupt @@ -364,7 +364,6 @@ void Update_All() #endif //ENABLE_PPM update_led_status(); #if defined(TELEMETRY) - uint8_t protocol=cur_protocol[0]&0x1F; if( (protocol==MODE_FRSKYD) || (protocol==MODE_HUBSAN) || (protocol==MODE_FRSKYX) || (protocol==MODE_DSM) ) TelemetryUpdate(); #endif @@ -384,7 +383,7 @@ static void update_led_status(void) { if(blink>10)-2; delayMilliseconds(temp); - next_callback-=temp<<10; // between 2-3ms left at this stage + next_callback-=temp<<10; // between 2-3ms left at this stage } - cli(); // disable global int - OCR1A = TCNT1 + next_callback*2;// set compare A for callback - sei(); // enable global int - TIFR1 = OCF1A_bm ; // clear compare A flag - BIND_BUTTON_FLAG_off; // do not bind/reset id anymore even if protocol change + cli(); // disable global int + OCR1A = TCNT1 + next_callback*2; // set compare A for callback + sei(); // enable global int + TIFR1 = OCF1A_bm ; // clear compare A flag + BIND_BUTTON_FLAG_off; // do not bind/reset id anymore even if protocol change } void update_serial_data() { RX_DONOTUPDTAE_on; - RX_FLAG_off; //data is being processed - if(rx_ok_buff[0]&0x20) //check range + RX_FLAG_off; //data is being processed + if(rx_ok_buff[1]&0x20) //check range RANGE_FLAG_on; else RANGE_FLAG_off; - if(rx_ok_buff[0]&0xC0) //check autobind(0x40) & bind(0x80) together + if(rx_ok_buff[1]&0xC0) //check autobind(0x40) & bind(0x80) together AUTOBIND_FLAG_on; else AUTOBIND_FLAG_off; - if(rx_ok_buff[1]&0x80) //if rx_ok_buff[1] ==1,power is low ,0-power high - POWER_FLAG_off; //power low + if(rx_ok_buff[2]&0x80) //if rx_ok_buff[2] ==1,power is low ,0-power high + POWER_FLAG_off; //power low else - POWER_FLAG_on; //power high - - option=rx_ok_buff[2]; + POWER_FLAG_on; //power high - if( ((rx_ok_buff[0]&0x5F) != (cur_protocol[0]&0x5F)) || ( (rx_ok_buff[1]&0x7F) != cur_protocol[1] ) ) + option=rx_ok_buff[3]; + + if( (rx_ok_buff[0] != cur_protocol[0]) || ((rx_ok_buff[1]&0x5F) != (cur_protocol[1]&0x5F)) || ( (rx_ok_buff[2]&0x7F) != (cur_protocol[2]&0x7F) ) ) { // New model has been selected - prev_protocol=cur_protocol[0]&0x1F; //store previous protocol so we can reset the module - cur_protocol[1] = rx_ok_buff[1]&0x7F; //store current protocol CHANGE_PROTOCOL_FLAG_on; //change protocol - sub_protocol=(rx_ok_buff[1]>>4)& 0x07; //subprotocol no (0-7) bits 4-6 - RX_num=rx_ok_buff[1]& 0x0F; - MProtocol_id=MProtocol_id_master+RX_num;//personalized RX bind + rx num // rx_num bits 0---3 + protocol=(rx_ok_buff[0]==0x55?0:32) + (rx_ok_buff[1]&0x1F); //protocol no (0-63) bits 4-6 of buff[1] and bit 0 of buf[0] + sub_protocol=(rx_ok_buff[2]>>4)& 0x07; //subprotocol no (0-7) bits 4-6 + RX_num=rx_ok_buff[2]& 0x0F; // rx_num bits 0---3 + MProtocol_id=MProtocol_id_master+RX_num;//personalized RX bind + rx num + set_rx_tx_addr(MProtocol_id); //set rx_tx_addr } else - if( ((rx_ok_buff[0]&0x80)!=0) && ((cur_protocol[0]&0x80)==0) ) // Bind flag has been set + if( ((rx_ok_buff[1]&0x80)!=0) && ((cur_protocol[1]&0x80)==0) ) // Bind flag has been set CHANGE_PROTOCOL_FLAG_on; //restart protocol with bind else CHANGE_PROTOCOL_FLAG_off; //no need to restart - cur_protocol[0] = rx_ok_buff[0]; //store current protocol - + //store current protocol values + for(uint8_t i=0;i<3;i++) + cur_protocol[i] = rx_ok_buff[i]; + // decode channel values - volatile uint8_t *p=rx_ok_buff+2; + volatile uint8_t *p=rx_ok_buff+3; uint8_t dec=-3; for(uint8_t i=0;i4840) { - chan=0; // start of frame - PPM_FLAG_on; // full frame present (even at startup since PPM_data has been initialized) + chan=0; // start of frame + PPM_FLAG_on; // full frame present (even at startup since PPM_data has been initialized) } else - if(chan!=-1) // need to wait for start of frame + if(chan!=-1) // need to wait for start of frame { //servo values between 500us and 2420us will end up here PPM_data[chan]= Cur_TCNT1>>1;; if(chan++>=NUM_CHN) - chan=-1; // don't accept any new channels + chan=-1; // don't accept any new channels } Prev_TCNT1+=Cur_TCNT1; } @@ -1141,7 +1140,9 @@ ISR(USART_RX_vect) if(idx==0||discard_frame==1) { // Let's try to sync at this point idx=0;discard_frame=0; - if(UDR0==0x55) // If 1st byte is 0x55 it looks ok + RX_MISSED_BUFF_off; // If rx_buff was good it's not anymore... + rx_buff[0]=UDR0; + if((rx_buff[0]&0xFE)==0x54) // If 1st byte is 0x54 or 0x55 it looks ok { TX_RX_PAUSE_on; tx_pause(); @@ -1153,14 +1154,13 @@ ISR(USART_RX_vect) } else { - RX_MISSED_BUFF_off; // if rx_buff was good it's not anymore... - rx_buff[(idx++)-1]=UDR0; // Store received byte - if(idx>RXBUFFER_SIZE) + rx_buff[idx++]=UDR0; // Store received byte + if(idx>=RXBUFFER_SIZE) { // A full frame has been received if(!IS_RX_DONOTUPDTAE_on) { //Good frame received and main is not working on the buffer memcpy((void*)rx_ok_buff,(const void*)rx_buff,RXBUFFER_SIZE);// Duplicate the buffer - RX_FLAG_on; // flag for main to process servo data + RX_FLAG_on; // flag for main to process servo data } else RX_MISSED_BUFF_on; // notify that rx_buff is good @@ -1175,13 +1175,13 @@ ISR(USART_RX_vect) } if(discard_frame==1) { - CLR_TIMSK1_OCIE1B; // Disable interrupt on compare B match + CLR_TIMSK1_OCIE1B; // Disable interrupt on compare B match TX_RX_PAUSE_off; tx_resume(); } #ifndef XMEGA cli() ; - UCSR0B |= _BV(RXCIE0) ; // RX interrupt enable + UCSR0B |= _BV(RXCIE0) ; // RX interrupt enable #endif } @@ -1193,7 +1193,7 @@ ISR(TIMER1_COMPB_vect, ISR_NOBLOCK ) #endif { // Timer1 compare B interrupt discard_frame=1; - CLR_TIMSK1_OCIE1B; // Disable interrupt on compare B match + CLR_TIMSK1_OCIE1B; // Disable interrupt on compare B match tx_resume(); } #endif //ENABLE_SERIAL diff --git a/Multiprotocol/Telemetry.ino b/Multiprotocol/Telemetry.ino index f728214..6476339 100644 --- a/Multiprotocol/Telemetry.ino +++ b/Multiprotocol/Telemetry.ino @@ -85,7 +85,7 @@ void frsky_check_telemetry(uint8_t *pkt,uint8_t len) telemetry_counter=(telemetry_counter+1)%32; // #if defined FRSKYX_CC2500_INO - if ((cur_protocol[0]&0x1F)==MODE_FRSKYX) + if (protocol==MODE_FRSKYX) { if ((pktt[5] >> 4 & 0x0f) == 0x08) { @@ -108,7 +108,7 @@ void frsky_check_telemetry(uint8_t *pkt,uint8_t len) void frsky_link_frame() { frame[0] = 0xFE; - if ((cur_protocol[0]&0x1F)==MODE_FRSKYD) + if (protocol==MODE_FRSKYD) { compute_RSSIdbm(); frame[1] = pktt[3]; @@ -117,7 +117,7 @@ void frsky_link_frame() frame[4] = (uint8_t)RSSI_dBm; } else - if ((cur_protocol[0]&0x1F)==MODE_HUBSAN) + if (protocol==MODE_HUBSAN) { frame[1] = v_lipo*2; //v_lipo; common 0x2A=42/10=4.2V frame[2] = frame[1]; @@ -396,7 +396,7 @@ void proces_sport_data(uint8_t data) void TelemetryUpdate() { #if defined SPORT_TELEMETRY - if ((cur_protocol[0]&0x1F)==MODE_FRSKYX) + if (protocol==MODE_FRSKYX) { // FrSkyX if(telemetry_link) { @@ -451,28 +451,28 @@ void TelemetryUpdate() #endif #if defined DSM_TELEMETRY - if(telemetry_link && (cur_protocol[0]&0x1F) == MODE_DSM ) + if(telemetry_link && protocol == MODE_DSM ) { // DSM DSM_frame(); telemetry_link=0; return; } #endif - if(telemetry_link && (cur_protocol[0]&0x1F) != MODE_FRSKYX ) + if(telemetry_link && protocol != MODE_FRSKYX ) { // FrSky + Hubsan frsky_link_frame(); telemetry_link=0; return; } #if defined HUB_TELEMETRY - if(!telemetry_link && (cur_protocol[0]&0x1F) == MODE_FRSKYD) + if(!telemetry_link && protocol == MODE_FRSKYD) { // FrSky frsky_user_frame(); return; } #endif #if defined SPORT_TELEMETRY - if ((cur_protocol[0]&0x1F)==MODE_FRSKYX) + if (protocol==MODE_FRSKYX) { // FrSkyX uint32_t now = micros(); if ((now - last) > SPORT_TIME) From b1c38cc79349afc71ac3a8c3e7d65cddb4d36aa8 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Thu, 15 Sep 2016 16:02:36 +0200 Subject: [PATCH 222/293] Typo... --- Multiprotocol/Multiprotocol.ino | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 54a1ab8..51cc5b3 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -264,7 +264,7 @@ void setup() #endif //ENABLE_PPM { // Serial #ifdef ENABLE_SERIAL - for(uint i=0;i<3;i++) + for(uint8_t i=0;i<3;i++) cur_protocol[i]=0; protocol=0; servo_max_100=SERIAL_MAX_100; servo_min_100=SERIAL_MIN_100; From 99e8be227ef5a374ceaf897b192069ac64859a6e Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 16 Sep 2016 10:39:44 +0200 Subject: [PATCH 223/293] PPM Telemetry: added serial speeds Only supported for none invert telemetry: FrSkyD (Incl Hubsan): 9600bps FrSkyX: 57600bps DSM: 125000bps --- Multiprotocol/Multiprotocol.h | 2 + Multiprotocol/Multiprotocol.ino | 7 ++- Multiprotocol/Telemetry.ino | 75 ++++++++++++++++++++++++--------- 3 files changed, 63 insertions(+), 21 deletions(-) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 4668f65..195797d 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -514,6 +514,8 @@ enum { // baudrate defines for serial #define SPEED_100K 0 #define SPEED_9600 1 +#define SPEED_57600 2 +#define SPEED_125K 3 //**************************************** //*** MULTI protocol serial definition *** diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 51cc5b3..ac9d8ad 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -855,7 +855,12 @@ void Mprotocol_serial_init() #if defined(TELEMETRY) void PPM_Telemetry_serial_init() { - initTXSerial( SPEED_9600 ) ; + if( (protocol==MODE_FRSKYD) || (protocol==MODE_HUBSAN)) + initTXSerial( SPEED_9600 ) ; + if(protocol==MODE_FRSKYX) + initTXSerial( SPEED_57600 ) ; + if(protocol==MODE_DSM) + initTXSerial( SPEED_125K ) ; } #endif diff --git a/Multiprotocol/Telemetry.ino b/Multiprotocol/Telemetry.ino index 6476339..44ea947 100644 --- a/Multiprotocol/Telemetry.ino +++ b/Multiprotocol/Telemetry.ino @@ -504,28 +504,63 @@ void Serial_write(uint8_t data) tx_resume(); } -// Speed is 0 for 100K and 1 for 9600 void initTXSerial( uint8_t speed) { - if(speed==SPEED_9600) - { // 9600 - #ifdef XMEGA - USARTC0.BAUDCTRLA = 207 ; - USARTC0.BAUDCTRLB = 0 ; - - USARTC0.CTRLB = 0x18 ; - USARTC0.CTRLA = (USARTC0.CTRLA & 0xCF) | 0x10 ; - USARTC0.CTRLC = 0x03 ; - } - #else - //9600 bauds - UBRR0H = 0x00; - UBRR0L = 0x67; - UCSR0A = 0 ; // Clear X2 bit - //Set frame format to 8 data bits, none, 1 stop bit - UCSR0C = (1< Date: Fri, 16 Sep 2016 16:56:46 +0200 Subject: [PATCH 224/293] Fix LED blink in PPM mode --- Multiprotocol/Multiprotocol.ino | 1 + 1 file changed, 1 insertion(+) diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index ac9d8ad..8c51981 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -240,6 +240,7 @@ void setup() { // PPM mode_select--; protocol = PPM_prot[mode_select].protocol; + cur_protocol[1] = protocol; sub_protocol = PPM_prot[mode_select].sub_proto; RX_num = PPM_prot[mode_select].rx_num; MProtocol_id = RX_num + MProtocol_id_master; From b09b4183bb8cb07c8c63de957dbcef9842f1cda8 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Fri, 16 Sep 2016 17:59:57 +0200 Subject: [PATCH 225/293] DSM revert changes due to issues --- Multiprotocol/DSM_cyrf6936.ino | 397 +++++++++++++++++---------------- 1 file changed, 206 insertions(+), 191 deletions(-) diff --git a/Multiprotocol/DSM_cyrf6936.ino b/Multiprotocol/DSM_cyrf6936.ino index b17cf21..27d1ad3 100644 --- a/Multiprotocol/DSM_cyrf6936.ino +++ b/Multiprotocol/DSM_cyrf6936.ino @@ -17,45 +17,29 @@ #include "iface_cyrf6936.h" -#define DSM2_RANDOM_CHANNELS 0 // disabled -//#define DSM2_RANDOM_CHANNELS 1 // enabled -#define DSM_BIND_CHANNEL 0x0d //13 This can be any odd channel +#define RANDOM_CHANNELS 0 // disabled +//#define RANDOM_CHANNELS 1 // enabled +#define BIND_CHANNEL 0x0d //13 This can be any odd channel //During binding we will send BIND_COUNT/2 packets //One packet each 10msec -#define DSM_BIND_COUNT 300 +#define BIND_COUNT1 600 enum { - DSM_BIND_WRITE=0, - DSM_BIND_CHECK, - DSM_BIND_READ, - DSM_CHANSEL, - DSM_CH1_WRITE_A, - DSM_CH1_CHECK_A, - DSM_CH2_WRITE_A, - DSM_CH2_CHECK_A, - DSM_CH2_READ_A, - DSM_CH1_WRITE_B, - DSM_CH1_CHECK_B, - DSM_CH2_WRITE_B, - DSM_CH2_CHECK_B, - DSM_CH2_READ_B, + DSM2_BIND = 0, + DSM2_CHANSEL = BIND_COUNT1 + 0, + DSM2_CH1_WRITE_A = BIND_COUNT1 + 1, + DSM2_CH1_CHECK_A = BIND_COUNT1 + 2, + DSM2_CH2_WRITE_A = BIND_COUNT1 + 3, + DSM2_CH2_CHECK_A = BIND_COUNT1 + 4, + DSM2_CH2_READ_A = BIND_COUNT1 + 5, + DSM2_CH1_WRITE_B = BIND_COUNT1 + 6, + DSM2_CH1_CHECK_B = BIND_COUNT1 + 7, + DSM2_CH2_WRITE_B = BIND_COUNT1 + 8, + DSM2_CH2_CHECK_B = BIND_COUNT1 + 9, + DSM2_CH2_READ_B = BIND_COUNT1 + 10, }; -// -uint8_t sop_col; -uint8_t ch_map[14]; -const uint8_t PROGMEM ch_map_progmem[][12] = { - {0, 1, 2, 3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, //Guess - {0, 1, 2, 3, 4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, //Guess - {1, 5, 2, 3, 0, 4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, //HP6DSM - {1, 5, 2, 4, 3, 6, 0, 0xff, 0xff, 0xff, 0xff, 0xff}, //DX6i - {1, 5, 2, 3, 6, 0xff, 0xff, 4, 0, 7, 0xff, 0xff}, //DX8 - {3, 2, 1, 5, 0, 4, 6, 7, 8, 0xff, 0xff, 0xff}, //DM9 - {3, 2, 1, 5, 0, 4, 6, 7, 8, 9, 0xff, 0xff}, //Guess - {3, 2, 1, 5, 0, 4, 6, 7, 8, 9, 10, 0xff}, //Guess - {3, 2, 1, 5, 0, 4, 6, 7, 8, 9, 10, 11} }; //Guess - const uint8_t PROGMEM pncodes[5][9][8] = { /* Note these are in order transmitted (LSB 1st) */ { /* Row 0 */ @@ -101,8 +85,6 @@ const uint8_t PROGMEM pncodes[5][9][8] = { /* Col 6 */ {0xBF, 0x54, 0x98, 0xB9, 0xB7, 0x30, 0x5A, 0x88}, /* Col 7 */ {0x35, 0xD1, 0xFC, 0x97, 0x23, 0xD4, 0xC9, 0x88}, /* Col 8 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93} -// Wrong values used by Orange TX/RX -// /* Col 8 */ {0x88, 0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40} }, { /* Row 4 */ /* Col 0 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93}, @@ -123,6 +105,11 @@ static void __attribute__((unused)) read_code(uint8_t *buf, uint8_t row, uint8_t buf[i]=pgm_read_byte_near( &pncodes[row][col][i] ); } +// +uint8_t sop_col; +uint8_t data_col; +uint8_t binding; + static void __attribute__((unused)) build_bind_packet() { uint8_t i; @@ -141,16 +128,14 @@ static void __attribute__((unused)) build_bind_packet() packet[9] = sum & 0xff; packet[10] = 0x01; //??? packet[11] = option>3?option:option+4; - if(sub_protocol==DSMX) //DSMX type + if(sub_protocol==DSMX) //DSMX type #if defined DSM_TELEMETRY - packet[12] = 0xb2; // Telemetry on + packet[12] = 0xb2; // Telemetry on #else packet[12] = option<8? 0xa2 : 0xb2; // Telemetry off #endif else packet[12] = option<8?0x01:0x02; - //TODO: packet[12]=0x12 for DSM/2048@11ms - packet[13] = 0x00; //??? for(i = 8; i < 14; i++) sum += packet[i]; @@ -158,44 +143,128 @@ static void __attribute__((unused)) build_bind_packet() packet[15] = sum & 0xff; } -static void __attribute__((unused)) build_data_packet(uint8_t upper) +static uint8_t __attribute__((unused)) PROTOCOL_SticksMoved(uint8_t init) +{ +#define STICK_MOVEMENT 15*(servo_max_125-servo_min_125)/100 // defines when the bind dialog should be interrupted (stick movement STICK_MOVEMENT %) + static uint16_t ele_start, ail_start; + uint16_t ele = Servo_data[ELEVATOR];//CHAN_ReadInput(MIXER_MapChannel(INP_ELEVATOR)); + uint16_t ail = Servo_data[AILERON];//CHAN_ReadInput(MIXER_MapChannel(INP_AILERON)); + if(init) { + ele_start = ele; + ail_start = ail; + return 0; + } + uint16_t ele_diff = ele_start - ele;//abs(ele_start - ele); + uint16_t ail_diff = ail_start - ail;//abs(ail_start - ail); + return ((ele_diff + ail_diff) > STICK_MOVEMENT);// +} + +static void __attribute__((unused)) build_data_packet(uint8_t upper)// { uint8_t i; - uint8_t bits=11; //2048 + uint8_t bits; + uint8_t ch_map[] = {3, 2, 1, 5, 0, 4, 6, 7, 8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //9 Channels - DM9 TX + switch(option>3?option:option+4) // Create channel map based on number of channels + { + case 12: + ch_map[11]=11; // 12 channels + case 11: + ch_map[10]=10; // 11 channels + case 10: + ch_map[9]=9; // 10 channels + break; + case 8: + memcpy(ch_map,"\x01\x05\x02\x03\x06\xFF\xFF\x04\x00\x07",10); // 8 channels - DX8 TX + break; + case 7: + memcpy(ch_map,"\x01\x05\x02\x04\x03\x06\x00",7); // 7 channels - DX6i TX + break; + case 6: + memcpy(ch_map,"\x01\x05\x02\x03\x00\x04\xFF",7); // 6 channels - HP6DSM TX + break; + case 4: + case 5: + memcpy(ch_map,"\x00\x01\x02\x03\xFF\xFF\xFF",7); // 4 channels - Guess + if(option&0x01) + ch_map[4]=4; // 5 channels - Guess + break; + } // + if( binding && PROTOCOL_SticksMoved(0) ) + binding = 0; if (sub_protocol==DSMX) { packet[0] = cyrfmfg_id[2]; packet[1] = cyrfmfg_id[3]; + bits=11; } else { packet[0] = (0xff ^ cyrfmfg_id[2]); packet[1] = (0xff ^ cyrfmfg_id[3]); - if(option<8) //1024 for 7 channels or less -> Note this is not true for DSM2 @11ms... TODO - bits=10; + bits=10; } // - uint16_t max = (1 << bits) - 1; - uint8_t chans=0; - if(upper && option>7) - chans=7; + uint16_t max = 1 << bits;//max=2048 for DSMX & 1024 for DSM2 less than 8 ch and 2048 otherwise + //uint16_t pct_100 = (uint32_t)max * 100 / 150;//682 1024*100/150 + // for (i = 0; i < 7; i++) { - uint8_t idx = ch_map[chans + i];//1,5,2,3,0,4 + uint8_t idx = ch_map[upper * 7 + i];//1,5,2,3,0,4 uint16_t value = 0xffff;; if (idx != 0xff) { - if (!IS_BIND_DONE_on) + if (binding) { // Failsafe position during binding value=max/2; //all channels to middle if(idx==0) value=1; //except throttle } else - value=map(Servo_data[CH_TAER[idx]],servo_min_125,servo_max_125,0,max); - value |= (upper ? 0x8000 : 0) | (idx << bits); + { + switch(idx) + { + case 0: + value=Servo_data[THROTTLE];//85.75-938.25=125%//171-853=100% + break; + case 1: + value=Servo_data[AILERON]; + break; + case 2: + value=Servo_data[ELEVATOR]; + break; + case 3: + value=Servo_data[RUDDER]; + break; + case 4: + value=Servo_data[AUX1]; + break; + case 5: + value=Servo_data[AUX2]; + break; + case 6: + value=Servo_data[AUX3]; + break; + case 7: + value=Servo_data[AUX4]; + break; + case 8: + value=Servo_data[AUX5]; + break; + case 9: + value=Servo_data[AUX6]; + break; + case 10: + value=Servo_data[AUX7]; + break; + case 11: + value=Servo_data[AUX8]; + break; + } + value=map(value,servo_min_125,servo_max_125,0,max-1); + } + value |= (upper && i == 0 ? 0x8000 : 0) | (idx << bits); } packet[i*2+2] = (value >> 8) & 0xff; packet[i*2+3] = (value >> 0) & 0xff; @@ -207,7 +276,7 @@ static uint8_t __attribute__((unused)) get_pn_row(uint8_t channel) return (sub_protocol == DSMX ? (channel - 2) % 5 : channel % 5); } -const uint8_t PROGMEM init_vals[][2] = { +const uint8_t init_vals[][2] = { {CYRF_02_TX_CTRL, 0x02}, //0x00 in deviation but needed to know when transmit is over {CYRF_05_RX_CTRL, 0x00}, {CYRF_28_CLK_EN, 0x02}, @@ -227,7 +296,7 @@ const uint8_t PROGMEM init_vals[][2] = { {CYRF_10_FRAMING_CFG, 0x4a}, //set sop len and threshold {CYRF_29_RX_ABORT, 0x0f}, //Clear RX abort? {CYRF_03_TX_CFG, 0x38 | CYRF_BIND_POWER}, //Set 64chip, SDR mode - {CYRF_10_FRAMING_CFG, 0x4E}, //0x4a}, //set sop len and threshold + {CYRF_10_FRAMING_CFG, 0x4a}, //set sop len and threshold {CYRF_1F_TX_OVERRIDE, 0x04}, //disable tx CRC {CYRF_1E_RX_OVERRIDE, 0x14}, //disable rx crc {CYRF_14_EOP_CTRL, 0x02}, //set EOP sync == 2 @@ -237,23 +306,23 @@ const uint8_t PROGMEM init_vals[][2] = { static void __attribute__((unused)) cyrf_config() { for(uint8_t i = 0; i < sizeof(init_vals) / 2; i++) - CYRF_WriteRegister(pgm_read_byte_near(&init_vals[i][0]), pgm_read_byte_near(&init_vals[i][1])); + CYRF_WriteRegister(init_vals[i][0], init_vals[i][1]); CYRF_WritePreamble(0x333304); CYRF_ConfigRFChannel(0x61); } -static void __attribute__((unused)) initialize_bind_phase() +static void __attribute__((unused)) initialize_bind_state() { uint8_t code[32]; - CYRF_ConfigRFChannel(DSM_BIND_CHANNEL); //This seems to be random? - uint8_t pn_row = get_pn_row(DSM_BIND_CHANNEL); - //printf("Ch: %d Row: %d SOP: %d Data: %d\n", DSM_BIND_CHANNEL, pn_row, sop_col, 7 - sop_col); + CYRF_ConfigRFChannel(BIND_CHANNEL); //This seems to be random? + uint8_t pn_row = get_pn_row(BIND_CHANNEL); + //printf("Ch: %d Row: %d SOP: %d Data: %d\n", BIND_CHANNEL, pn_row, sop_col, data_col); CYRF_ConfigCRCSeed(crc); read_code(code,pn_row,sop_col,8); CYRF_ConfigSOPCode(code); - read_code(code,pn_row,7 - sop_col,16); + read_code(code,pn_row,data_col,16); read_code(code+16,0,8,8); memcpy(code + 24, (void *)"\xc6\x94\x22\xfe\x48\xe6\x57\x4e", 8); CYRF_ConfigDataCode(code, 32); @@ -261,7 +330,7 @@ static void __attribute__((unused)) initialize_bind_phase() build_bind_packet(); } -const uint8_t PROGMEM data_vals[][2] = { +const uint8_t data_vals[][2] = { {CYRF_05_RX_CTRL, 0x83}, //Initialize for reading RSSI {CYRF_29_RX_ABORT, 0x20}, {CYRF_0F_XACT_CFG, 0x24}, @@ -282,21 +351,21 @@ const uint8_t PROGMEM data_vals[][2] = { static void __attribute__((unused)) cyrf_configdata() { for(uint8_t i = 0; i < sizeof(data_vals) / 2; i++) - CYRF_WriteRegister(pgm_read_byte_near(&data_vals[i][0]), pgm_read_byte_near(&data_vals[i][1])); + CYRF_WriteRegister(data_vals[i][0], data_vals[i][1]); } static void __attribute__((unused)) set_sop_data_crc() { uint8_t code[16]; uint8_t pn_row = get_pn_row(hopping_frequency[hopping_frequency_no]); - //printf("Ch: %d Row: %d SOP: %d Data: %d\n", ch[hopping_frequency_no], pn_row, sop_col, 7 - sop_col); + //printf("Ch: %d Row: %d SOP: %d Data: %d\n", ch[hopping_frequency_no], pn_row, sop_col, data_col); CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]); CYRF_ConfigCRCSeed(crc); crc=~crc; read_code(code,pn_row,sop_col,8); CYRF_ConfigSOPCode(code); - read_code(code,pn_row,7 - sop_col,16); + read_code(code,pn_row,data_col,16); CYRF_ConfigDataCode(code, 16); if(sub_protocol == DSMX) @@ -339,179 +408,128 @@ static void __attribute__((unused)) calc_dsmx_channel() } } -static uint8_t __attribute__((unused)) DSM_Check_RX_packet() -{ - uint8_t result=1; // assume good packet - - uint16_t sum = 384 - 0x10; - for(uint8_t i = 1; i < 9; i++) - { - sum += pkt[i]; - if(i<5) - if(pkt[i] != (0xff ^ cyrfmfg_id[i-1])) - result=0; // bad packet - } - if( pkt[9] != (sum>>8) && pkt[10] != (uint8_t)sum ) - result=0; - return result; -} - uint16_t ReadDsm() { #define DSM_CH1_CH2_DELAY 4010 // Time between write of channel 1 and channel 2 #define DSM_WRITE_DELAY 1550 // Time after write to verify write complete -#define DSM_READ_DELAY 600 // Time before write to check read phase, and switch channels. Was 400 but 600 seems what the 328p needs to read a packet +#define DSM_READ_DELAY 600 // Time before write to check read state, and switch channels. Was 400 but 500 seems what the 328p needs to read a packet uint16_t start; - uint8_t rx_phase; - uint8_t len; - - switch(phase) + + switch(state) { -//#define BIND_TEST -#ifndef BIND_TEST - case DSM_BIND_WRITE: - if(bind_counter--==0) - phase=DSM_CHANSEL; - CYRF_WriteDataPacket(packet); - return 10000; -#else - case DSM_BIND_WRITE: - if(bind_counter--==0) - phase=DSM_BIND_CHECK; - CYRF_WriteDataPacket(packet); - return 10000; - case DSM_BIND_CHECK: - CYRF_ConfigDataCode((const uint8_t *)"\x98\x88\x1B\xE4\x30\x79\x03\x84\xC9\x2C\x06\x93\x86\xB9\x9E", 16); - CYRF_SetTxRxMode(RX_EN); //Receive mode - CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); //Prepare to receive - phase++; // change from BIND_CHECK to BIND_READ - return 2000; - case DSM_BIND_READ: - //Read data from RX - rx_phase = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS); - if((rx_phase & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing) - rx_phase |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS); - if((rx_phase & 0x07) == 0x02) - { // data received - CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // need to set RXOW before data read - len=CYRF_ReadRegister(CYRF_09_RX_COUNT); - if(len>MAX_PKT-2) - len=MAX_PKT-2; - CYRF_ReadDataPacketLen(pkt+1, len); - if(len==10 && DSM_Check_RX_packet()) - { - pkt[0]=0x80; - telemetry_link=1; // send received data on serial - CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); - CYRF_SetTxRxMode(TX_EN); //Write mode - phase++; - return 2000; - } + default: + //Binding + state++; + if(state & 1) + { + //Send packet on even states + //Note state has already incremented, so this is actually 'even' state + CYRF_WriteDataPacket(packet); + return 8500; } - //Force end read phase - CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x2C); // Force end phase - start=micros(); - while ((uint16_t)micros()-start < 100) // Wait max 100 µs - if((CYRF_ReadRegister(CYRF_0F_XACT_CFG) & 0x20) == 0) - break; - CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x0C); // Read - CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); //Prepare to receive - return 7000; -#endif - case DSM_CHANSEL: + else + { + //Check status on odd states + CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS); + return 1500; + } + case DSM2_CHANSEL: BIND_DONE; //Select channels and configure for writing data //CYRF_FindBestChannels(ch, 2, 10, 1, 79); cyrf_configdata(); CYRF_SetTxRxMode(TX_EN); hopping_frequency_no = 0; - phase = DSM_CH1_WRITE_A; // in fact phase++ + state = DSM2_CH1_WRITE_A; // in fact state++ set_sop_data_crc(); return 10000; - case DSM_CH1_WRITE_A: - case DSM_CH1_WRITE_B: - case DSM_CH2_WRITE_A: - case DSM_CH2_WRITE_B: - build_data_packet(phase == DSM_CH1_WRITE_B||phase == DSM_CH2_WRITE_B); // build lower or upper channels - CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS); // clear IRQ flags + case DSM2_CH1_WRITE_A: + case DSM2_CH1_WRITE_B: + case DSM2_CH2_WRITE_A: + case DSM2_CH2_WRITE_B: + build_data_packet(state == DSM2_CH1_WRITE_B);// build lower or upper channels + CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS); // clear IRQ flags CYRF_WriteDataPacket(packet); - phase++; // change from WRITE to CHECK mode + state++; // change from WRITE to CHECK mode return DSM_WRITE_DELAY; - case DSM_CH1_CHECK_A: - case DSM_CH1_CHECK_B: + case DSM2_CH1_CHECK_A: + case DSM2_CH1_CHECK_B: start=micros(); - while ((uint16_t)micros()-start < 500) // Wait max 500µs + while ((uint16_t)micros()-start < 500) // Wait max 500µs if(CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02) break; set_sop_data_crc(); - phase++; // change from CH1_CHECK to CH2_WRITE + state++; // change from CH1_CHECK to CH2_WRITE return DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY; - case DSM_CH2_CHECK_A: - case DSM_CH2_CHECK_B: + case DSM2_CH2_CHECK_A: + case DSM2_CH2_CHECK_B: start=micros(); - while ((uint16_t)micros()-start < 500) // Wait max 500µs + while ((uint16_t)micros()-start < 500) // Wait max 500µs if(CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02) break; - if (phase == DSM_CH2_CHECK_A) - CYRF_SetPower(0x28); //Keep transmit power in sync + if (state == DSM2_CH2_CHECK_A) + CYRF_SetPower(0x28); //Keep transmit power in sync #if defined DSM_TELEMETRY - phase++; // change from CH2_CHECK to CH2_READ + state++; // change from CH2_CHECK to CH2_READ if(option<=3 || option>7) { // disable telemetry for option between 4 and 7 ie 4,5,6,7 channels @11ms since it does not work... CYRF_SetTxRxMode(RX_EN); //Receive mode CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive } return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY; - case DSM_CH2_READ_A: - case DSM_CH2_READ_B: + case DSM2_CH2_READ_A: + case DSM2_CH2_READ_B: //Read telemetry - rx_phase = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS); - if((rx_phase & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing) - rx_phase |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS); - if((rx_phase & 0x07) == 0x02) + uint8_t rx_state = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS); + if((rx_state & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing) + rx_state |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS); + if((rx_state & 0x07) == 0x02) { // good data (complete with no errors) CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // need to set RXOW before data read - len=CYRF_ReadRegister(CYRF_09_RX_COUNT); + uint8_t len=CYRF_ReadRegister(CYRF_09_RX_COUNT); if(len>MAX_PKT-2) len=MAX_PKT-2; CYRF_ReadDataPacketLen(pkt+1, len); - pkt[0]=CYRF_ReadRegister(CYRF_13_RSSI)&0x1F; // store RSSI of the received telemetry signal + pkt[0]=CYRF_ReadRegister(CYRF_13_RSSI)&0x1F; // store RSSI of the received telemetry signal telemetry_link=1; } - if (phase == DSM_CH2_READ_A && option <= 3) // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms + if (state == DSM2_CH2_READ_A && option <= 3) // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms { - //Force end read phase - CYRF_WriteRegister(CYRF_0F_XACT_CFG, (CYRF_ReadRegister(CYRF_0F_XACT_CFG) | 0x20)); // Force end phase + //Force end read state + CYRF_WriteRegister(CYRF_0F_XACT_CFG, (CYRF_ReadRegister(CYRF_0F_XACT_CFG) | 0x20)); // Force end state start=micros(); - while ((uint16_t)micros()-start < 100) // Wait max 100 µs + while ((uint16_t)micros()-start < 100) // Wait max 100 µs if((CYRF_ReadRegister(CYRF_0F_XACT_CFG) & 0x20) == 0) break; - phase = DSM_CH2_READ_B; - CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive + state = DSM2_CH2_READ_B; + CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive return 11000; } - if (phase == DSM_CH2_READ_A) - phase = DSM_CH1_WRITE_B; //Transmit upper + if (state == DSM2_CH2_READ_A && option>7) + state = DSM2_CH1_WRITE_B; //Transmit upper else - phase = DSM_CH1_WRITE_A; //Transmit lower + state = DSM2_CH1_WRITE_A; //Force 11ms if option>3 ie 4,5,6,7 channels @11ms CYRF_SetTxRxMode(TX_EN); //Write mode set_sop_data_crc(); return DSM_READ_DELAY; #else // No telemetry set_sop_data_crc(); - if (phase == DSM_CH2_CHECK_A) + if (state == DSM2_CH2_CHECK_A) { - if(option < 4) //Normal mode 22ms + if(option < 8) { - phase = DSM_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper) - return 22000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ; // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms + state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper) + if(option>3) + return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ; // force 11ms if option>3 ie 4,5,6,7 channels @11ms + else + return 22000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ; // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms } - else //11ms mode - phase = DSM_CH1_WRITE_B; // change from CH2_CHECK_A to CH1_WRITE_A (to transmit upper) + else + state = DSM2_CH1_WRITE_B; // change from CH2_CHECK_A to CH1_WRITE_A (to transmit upper) } else - phase = DSM_CH1_WRITE_A; // change from CH2_CHECK_B to CH1_WRITE_A (upper already transmitted so transmit lower) + state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_B to CH1_WRITE_A (upper already transmitted so transmit lower) return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY; #endif } @@ -531,10 +549,11 @@ uint16_t initDsm() calc_dsmx_channel(); else { -#if DSM2_RANDOM_CHANNELS == 1 +#if RANDOM_CHANNELS == 1 uint8_t tmpch[10]; CYRF_FindBestChannels(tmpch, 10, 5, 3, 75); // + randomSeed((uint32_t)analogRead(A6)<<10|analogRead(A7));//seed uint8_t idx = random(0xfefefefe) % 10; hopping_frequency[0] = tmpch[idx]; while(1) @@ -555,26 +574,22 @@ uint16_t initDsm() crc = ~((cyrfmfg_id[0] << 8) + cyrfmfg_id[1]); // sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07; - - // Create channel map based on number of channels - uint8_t temp=option>3?option-4:option; - if(temp>8) - temp=8; - for(uint8_t i=0;i<12;i++) - ch_map[i]=pgm_read_byte_near(&ch_map_progmem[temp][i]); - ch_map[12]=0xFF; - ch_map[13]=0xFF; + data_col = 7 - sop_col; CYRF_SetTxRxMode(TX_EN); // if(IS_AUTOBIND_FLAG_on) { - initialize_bind_phase(); - phase = DSM_BIND_WRITE; - bind_counter=DSM_BIND_COUNT; + state = DSM2_BIND; + PROTOCOL_SticksMoved(1); //Initialize Stick position + initialize_bind_state(); + binding = 1; } else - phase = DSM_CHANSEL;// + { + state = DSM2_CHANSEL;// + binding = 0; + } return 10000; } From bb9018c094d95481d8ea41c99f8ab5ec702cf05f Mon Sep 17 00:00:00 2001 From: Mike Morrison Date: Fri, 9 Sep 2016 06:58:08 -0700 Subject: [PATCH 226/293] made pins configurable and added support for nano --- Multiprotocol/Multiprotocol.h | 162 ++++++++++++++++++++------------ Multiprotocol/Multiprotocol.ino | 65 +++++++++++-- Multiprotocol/Telemetry.ino | 18 ++-- Multiprotocol/_Config.h | 4 +- 4 files changed, 173 insertions(+), 76 deletions(-) diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 195797d..68564d7 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -15,7 +15,7 @@ // Check selected board type #ifndef XMEGA -#if not defined(ARDUINO_AVR_PRO) && not defined(ARDUINO_AVR_MINI) +#if not defined(ARDUINO_AVR_PRO) && not defined(ARDUINO_AVR_MINI) && not defined(ARDUINO_AVR_NANO) #error You must select the board type "Arduino Pro or Pro Mini" or "Arduino Mini" #endif #if F_CPU != 16000000L || not defined(__AVR_ATmega328P__) @@ -185,22 +185,68 @@ struct PPM_Parameters //******************* //*** Pinouts *** //******************* + +#define TELEMETRY_SERIAL_TX_pin 2 +#define TELEMETRY_SERIAL_TX_port PORTD +#define TELEMETRY_SERIAL_TX_ddr DDRD +#define DEBUG_TX_pin 1 +#define DEBUG_TX_port PORTD +#define DEBUG_TX_ddr DDRD +#define MODE_DIAL1_PIN 2 +#define MODE_DIAL1_PORT PORTB +#define MODE_DIAL2_PIN 3 +#define MODE_DIAL2_PORT PORTB +#define MODE_DIAL3_PIN 4 +#define MODE_DIAL3_PORT PORTB +#define MODE_DIAL4_PIN 0 +#define MODE_DIAL4_PORT PORTC #define LED_pin 5 //D13 = PB5 +#define LED_port PORTB +#define LED_ddr DDRB #define BIND_pin 5 //D13 = PB5 +#define BIND_port PORTB +#define BIND_ipr PINB +#define BIND_ddr DDRB #define PPM_pin 3 //D3 = PD3 +#define PPM_port PORTD #ifdef XMEGA #define SDI_pin 6 //SDIO-D6 + #define SDI_port PORTD + #define SDI_ipr PIND + #define SDI_ddr DDRD #else #define SDI_pin 5 //D5 = PD5 + #define SDI_port PORTD + #define SDI_ipr PIND + #define SDI_ddr DDRD #endif -#define SCLK_pin 4 //D4 = PD4 +#define SCLK_pin 4 //D4 = PD4 +#define SCLK_port PORTD +#define SCLK_ddr DDRD #define A7105_CS_pin 2 //D2 = PD2 +#define A7105_CS_port PORTD +#define A7105_CS_ddr DDRD #define SDO_pin 6 //D6 = PD6 +#define SDO_port PORTD +#define SDO_ipr PIND #define CC25_CSN_pin 7 //D7 = PD7 +#define CC25_CSN_port PORTD +#define CC25_CSN_ddr DDRD #define NRF_CSN_pin 0 //D8 = PB0 +#define NRF_CSN_port PORTB +#define NRF_CSN_ddr DDRB #define CYRF_CSN_pin 1 //D9 = PB1 +#define CYRF_CSN_port PORTB +#define CYRF_CSN_ddr DDRB +#define CYRF_RST_pin 5 //D9 = PB1 +#define CYRF_RST_port PORTC +#define CYRF_RST_ddr DDRC #define CTRL1_pin 1 //A1 = PC1 +#define CTRL1_port PORTC +#define CTRL1_ddr DDRC #define CTRL2_pin 2 //A2 = PC2 +#define CTRL2_port PORTC +#define CTRL2_ddr DDRC // #ifdef XMEGA #define CTRL1_on @@ -208,53 +254,53 @@ struct PPM_Parameters #define CTRL2_on #define CTRL2_off #else - #define CTRL1_on PORTC |= _BV(1) - #define CTRL1_off PORTC &= ~_BV(1) - #define CTRL2_on PORTC |= _BV(2) - #define CTRL2_off PORTC &= ~_BV(2) + #define CTRL1_on CTRL1_port |= _BV(CTRL1_pin) + #define CTRL1_off CTRL1_port &= ~_BV(CTRL1_pin) + #define CTRL2_on CTRL2_port |= _BV(CTRL2_pin) + #define CTRL2_off CTRL2_port &= ~_BV(CTRL2_pin) #endif // #ifdef XMEGA - #define A7105_CS_on PORTD.OUTSET = _BV(4) //D4 - #define A7105_CS_off PORTD.OUTCLR = _BV(4) //D4 + #define A7105_CS_on A7105_CS_port.OUTSET = _BV(A7105_CS_pin) //D4 + #define A7105_CS_off A7105_CS_port.OUTCLR = _BV(A7105_CS_pin) //D4 #else - #define A7105_CS_on PORTD |= _BV(2) //D2 - #define A7105_CS_off PORTD &= ~_BV(2) //D2 + #define A7105_CS_on A7105_CS_port |= _BV(A7105_CS_pin) //D2 + #define A7105_CS_off A7105_CS_port &= ~_BV(A7105_CS_pin) //D2 #endif // #ifdef XMEGA - #define SCK_on PORTD.OUTSET = _BV(7) //D7 - #define SCK_off PORTD.OUTCLR = _BV(7) //D7 + #define SCK_on SCLK_port.OUTSET = _BV(SCLK_pin) //D7 + #define SCK_off SCLK_port.OUTCLR = _BV(SCLK_pin) //D7 #else - #define SCK_on PORTD |= _BV(4) //D4 - #define SCK_off PORTD &= ~_BV(4) //D4 + #define SCK_on SCLK_port |= _BV(SCLK_pin) //D4 + #define SCK_off SCLK_port &= ~_BV(SCLK_pin) //D4 #endif // #ifdef XMEGA - #define SDI_on PORTD.OUTSET = _BV(5) //D5 - #define SDI_off PORTD.OUTCLR = _BV(5) //D5 + #define SDI_on SDI_port.OUTSET = _BV(SDI_pin) //D5 + #define SDI_off SDI_port.OUTCLR = _BV(SDI_pin) //D5 #else - #define SDI_on PORTD |= _BV(5) //D5 - #define SDI_off PORTD &= ~_BV(5) //D5 + #define SDI_on SDI_port |= _BV(SDI_pin) //D5 + #define SDI_off SDI_port &= ~_BV(SDI_pin) //D5 #endif // #ifdef XMEGA - #define SDI_1 (PORTD.IN & _BV(SDI_pin)) == _BV(SDI_pin) //D5 - #define SDI_0 (PORTD.IN & _BV(SDI_pin)) == 0x00 //D5 + #define SDI_1 (SDI_port.IN & _BV(SDI_pin)) == _BV(SDI_pin) //D5 + #define SDI_0 (SDI_port.IN & _BV(SDI_pin)) == 0x00 //D5 #else - #define SDI_1 (PIND & _BV(SDI_pin)) == _BV(SDI_pin) //D5 - #define SDI_0 (PIND & _BV(SDI_pin)) == 0x00 //D5 + #define SDI_1 (SDI_ipr & _BV(SDI_pin)) == _BV(SDI_pin) //D5 + #define SDI_0 (SDI_ipr & _BV(SDI_pin)) == 0x00 //D5 #endif // -#define SDI_SET_INPUT DDRD &= ~_BV(5) //D5 -#define SDI_SET_OUTPUT DDRD |= _BV(5) //D5 +#define SDI_SET_INPUT SDI_ddr &= ~_BV(SDI_pin) //D5 +#define SDI_SET_OUTPUT SDI_ddr |= _BV(SDI_pin) //D5 // #ifdef XMEGA - #define CC25_CSN_on PORTD.OUTSET = _BV(7) //D7 - #define CC25_CSN_off PORTD.OUTCLR = _BV(7) //D7 + #define CC25_CSN_on CC25_CSN_port.OUTSET = _BV(CC25_CSN_pin) //D7 + #define CC25_CSN_off CC25_CSN_port.OUTCLR = _BV(CC25_CSN_pin) //D7 #else - #define CC25_CSN_on PORTD |= _BV(7) //D7 - #define CC25_CSN_off PORTD &= ~_BV(7) //D7 + #define CC25_CSN_on CC25_CSN_port |= _BV(CC25_CSN_pin) //D7 + #define CC25_CSN_off CC25_CSN_port &= ~_BV(CC25_CSN_pin) //D7 #endif // #ifdef XMEGA @@ -263,64 +309,64 @@ struct PPM_Parameters #define NRF_CE_on #define NRF_CE_off #else - #define NRF_CSN_on PORTB |= _BV(0) //D8 - #define NRF_CSN_off PORTB &= ~_BV(0) //D8 + #define NRF_CSN_on NRF_CSN_port |= _BV(NRF_CSN_pin) //D8 + #define NRF_CSN_off NRF_CSN_port &= ~_BV(NRF_CSN_pin) //D8 #define NRF_CE_on #define NRF_CE_off #endif // #ifdef XMEGA - #define CYRF_CSN_on PORTD.OUTSET = _BV(4) - #define CYRF_CSN_off PORTD.OUTCLR = _BV(4) + #define CYRF_CSN_on CYRF_CSN_port.OUTSET = _BV(CYRF_CSN_pin) + #define CYRF_CSN_off CYRF_CSN_port.OUTCLR = _BV(CYRF_CSN_pin) #else - #define CYRF_CSN_on PORTB |= _BV(1) //D9 - #define CYRF_CSN_off PORTB &= ~_BV(1) //D9 - #define CYRF_RST_HI PORTC |= _BV(5) //A5 - #define CYRF_RST_LO PORTC &= ~_BV(5) //A5 + #define CYRF_CSN_on CYRF_CSN_port |= _BV(CYRF_CSN_pin) //D9 + #define CYRF_CSN_off CYRF_CSN_port &= ~_BV(CYRF_CSN_pin) //D9 + #define CYRF_RST_HI CYRF_RST_port |= _BV(CYRF_RST_pin) //A5 + #define CYRF_RST_LO CYRF_RST_port &= ~_BV(CYRF_RST_pin) //A5 #define CYRF_RST_pin 5 #endif // #ifdef XMEGA - #define SDO_1 (PORTD.IN & _BV(SDO_pin)) == _BV(SDO_pin) //D6 - #define SDO_0 (PORTD.IN & _BV(SDO_pin)) == 0x00 //D6 + #define SDO_1 (SDO_port.IN & _BV(SDO_pin)) == _BV(SDO_pin) //D6 + #define SDO_0 (SDO_port.IN & _BV(SDO_pin)) == 0x00 //D6 #else - #define SDO_1 (PIND & _BV(SDO_pin)) == _BV(SDO_pin) //D6 - #define SDO_0 (PIND & _BV(SDO_pin)) == 0x00 //D6 + #define SDO_1 (SDO_ipr & _BV(SDO_pin)) == _BV(SDO_pin) //D6 + #define SDO_0 (SDO_ipr & _BV(SDO_pin)) == 0x00 //D6 #endif // // // LED #ifdef XMEGA - #define LED_ON PORTD.OUTCLR = _BV(1) - #define LED_OFF PORTD.OUTSET = _BV(1) - #define LED_TOGGLE PORTD.OUTTGL = _BV(1) - #define LED_SET_OUTPUT PORTD.DIRSET = _BV(1) - #define IS_LED_on ( (PORTD.OUT & _BV(1)) != 0x00 ) + #define LED_ON LED_port.OUTCLR = _BV(LED_pin) + #define LED_OFF LED_port.OUTSET = _BV(LED_pin) + #define LED_TOGGLE LED_port.OUTTGL = _BV(LED_pin) + #define LED_SET_OUTPUT LED_port.DIRSET = _BV(LED_pin) + #define IS_LED_on ( (LED_port.OUT & _BV(LED_pin)) != 0x00 ) #else - #define LED_ON PORTB |= _BV(5) - #define LED_OFF PORTB &= ~_BV(5) - #define LED_TOGGLE PORTB ^= _BV(5) - #define LED_SET_OUTPUT DDRB |= _BV(5) - #define IS_LED_on ( (PORTB & _BV(5)) != 0x00 ) + #define LED_ON LED_port |= _BV(LED_pin) + #define LED_OFF LED_port &= ~_BV(LED_pin) + #define LED_TOGGLE LED_port ^= _BV(LED_pin) + #define LED_SET_OUTPUT LED_ddr |= _BV(LED_pin) + #define IS_LED_on ( (LED_port & _BV(LED_pin)) != 0x00 ) #endif //BIND #ifdef XMEGA #define IS_BIND_BUTTON_on ( (PORTD.IN & _BV(2)) == 0x00 ) #else - #define BIND_SET_INPUT DDRB &= ~_BV(5) - #define BIND_SET_PULLUP PORTB |= _BV(5) - #define IS_BIND_BUTTON_on ( (PINB & _BV(5)) == 0x00 ) - #define BIND_SET_OUTPUT DDRB |= _BV(5) + #define BIND_SET_INPUT BIND_ddr &= ~_BV(BIND_pin) + #define BIND_SET_PULLUP BIND_port |= _BV(BIND_pin) + #define IS_BIND_BUTTON_on ( (BIND_ipr & _BV(BIND_pin)) == 0x00 ) + #define BIND_SET_OUTPUT BIND_ddr |= _BV(BIND_pin) #endif // TX #ifdef DEBUG_TX - #define TX_ON PORTD |= _BV(1) - #define TX_OFF PORTD &= ~_BV(1) - #define TX_TOGGLE PORTD ^= _BV(1) - #define TX_SET_OUTPUT DDRD |= _BV(1) + #define TX_ON DEBUG_TX_port |= _BV(DEBUG_TX_pin) + #define TX_OFF DEBUG_TX_port &= ~_BV(DEBUG_TX_pin) + #define TX_TOGGLE DEBUG_TX_port ^= _BV(DEBUG_TX_pin) + #define TX_SET_OUTPUT DEBUG_TX_ddr |= _BV(DEBUG_TX_pin) #else #define TX_ON #define TX_OFF diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 8c51981..112c7af 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -172,11 +172,34 @@ void setup() TCC1.CTRLA = 0x0B ; // Event3 (prescale of 16) #else // General pinout - DDRD = _BV(A7105_CS_pin)|_BV(SDI_pin)|_BV(SCLK_pin)|_BV( CC25_CSN_pin);//pin output - DDRC = _BV(CTRL1_pin)|_BV(CTRL2_pin)|_BV(CYRF_RST_pin); //pin output - DDRB = _BV(NRF_CSN_pin)|_BV(CYRF_CSN_pin); //pin output - PORTB = _BV(2)|_BV(3)|_BV(4)|_BV(BIND_pin); //pullup on dial (D10=PB2,D11=PB3,D12=PB4) and bind button - PORTC = _BV(0); //pullup on dial (A0=PC0) + + // outputs +#ifdef A7105_INSTALLED + A7105_CS_ddr |= _BV(A7105_CS_pin); +#endif + SDI_SET_OUTPUT; + SCLK_ddr |= _BV(SCLK_pin); +#ifdef CC2500_INSTALLED + CC25_CSN_ddr |= _BV(CC25_CSN_pin); +#endif + CTRL1_ddr |= _BV(CTRL1_pin); + CTRL2_ddr |= _BV(CTRL2_pin); +#ifdef CYRF6936_INSTALLED + CYRF_RST_ddr |= _BV(CYRF_RST_pin); + CYRF_CSN_ddr |= _BV(CYRF_CSN_pin); +#endif +#ifdef NRF24L01_INSTALLED + NRF_CSN_ddr |= _BV(NRF_CSN_pin); +#endif + + //pullup on dial (D10=PB2,D11=PB3,D12=PB4) and bind button + MODE_DIAL1_PORT |= _BV(MODE_DIAL1_PIN); + MODE_DIAL2_PORT |= _BV(MODE_DIAL2_PIN); + MODE_DIAL3_PORT |= _BV(MODE_DIAL3_PIN); + MODE_DIAL4_PORT |= _BV(MODE_DIAL4_PIN); + BIND_port |= _BV(BIND_pin); + + #ifdef DEBUG_TX TX_SET_OUTPUT; #endif @@ -188,10 +211,18 @@ void setup() #endif // Set Chip selects +#ifdef A7105_INSTALLED A7105_CS_on; +#endif +#ifdef CC2500_INSTALLED CC25_CSN_on; +#endif +#ifdef NRF24L01_INSTALLED NRF_CSN_on; +#endif +#ifdef CYRF6936_INSTALLED CYRF_CSN_on; +#endif // Set SPI lines SDI_on; SCK_off; @@ -216,7 +247,11 @@ void setup() #ifndef ENABLE_PPM mode_select = MODE_SERIAL ; // force serial mode #else - mode_select=0x0F - ( ( (PINB>>2)&0x07 ) | ( (PINC<<3)&0x08) );//encoder dip switches 1,2,4,8=>B2,B3,B4,C0 + mode_select = + ((MODE_DIAL1_PORT & MODE_DIAL1_PIN) ? 1 : 0) + + ((MODE_DIAL2_PORT & MODE_DIAL2_PIN) ? 2 : 0) + + ((MODE_DIAL3_PORT & MODE_DIAL3_PIN) ? 4 : 0) + + ((MODE_DIAL4_PORT & MODE_DIAL4_PIN) ? 8 : 0); #endif // Update LED @@ -254,8 +289,16 @@ void setup() protocol_init(); //Configure PPM interrupt - EICRA |=_BV(ISC11); // The rising edge of INT1 pin D3 generates an interrupt request + #if PPM_pin == 2 + EICRA |= _BV(ISC01); // The rising edge of INT1 pin D3 generates an interrupt request + EIMSK |= _BV(INT0); // INT1 interrupt enable + #elif PPM_pin == 3 + EICRA |= _BV(ISC11); // The rising edge of INT1 pin D3 generates an interrupt request EIMSK |= _BV(INT1); // INT1 interrupt enable + #else + #error PPM pin can only be 2 or 3 + #endif + #if defined(TELEMETRY) PPM_Telemetry_serial_init(); // Configure serial for telemetry @@ -1097,10 +1140,18 @@ void init() //PPM #ifdef ENABLE_PPM #ifdef XMEGA +#if PPM_pin == 2 ISR(PORTD_INT0_vect) #else +ISR(PORTD_INT1_vect) +#endif +#else +#if PPM_pin == 2 +ISR(INT0_vect, ISR_NOBLOCK) +#else ISR(INT1_vect, ISR_NOBLOCK) #endif +#endif { // Interrupt on PPM pin static int8_t chan=-1; static uint16_t Prev_TCNT1=0; diff --git a/Multiprotocol/Telemetry.ino b/Multiprotocol/Telemetry.ino index 44ea947..24ffc83 100644 --- a/Multiprotocol/Telemetry.ino +++ b/Multiprotocol/Telemetry.ino @@ -588,11 +588,11 @@ void initTXSerial( uint8_t speed) { TIMSK0 = 0 ; // Stop all timer 0 interrupts #ifdef INVERT_SERIAL - PORTD &= ~2 ; + TELEMETRY_SERIAL_TX_port &= ~_BV(TELEMETRY_SERIAL_TX_pin); #else - PORTD |= 2 ; + TELEMETRY_SERIAL_TX_port |= _BV(TELEMETRY_SERIAL_TX_pin); #endif - DDRD |= 2 ; // TxD pin is an output + TELEMETRY_SERIAL_TX_ddr |= _BV(TELEMETRY_SERIAL_TX_pin) ; // TxD pin is an output UCSR0B &= ~(1<>= 1 GPIOR0 = byte ; @@ -732,11 +732,11 @@ ISR(TIMER0_COMPB_vect) byte = GPIOR2 ; if ( byte & 0x01 ) { - PORTD |= 0x02 ; + TELEMETRY_SERIAL_TX_port |= _BV(TELEMETRY_SERIAL_TX_pin); } else { - PORTD &= ~0x02 ; + TELEMETRY_SERIAL_TX_port &= ~_BV(TELEMETRY_SERIAL_TX_pin); } byte /= 2 ; // Generates shorter code than byte >>= 1 GPIOR2 = byte ; @@ -787,11 +787,11 @@ ISR(TIMER0_OVF_vect) } if ( byte & 0x01 ) { - PORTD |= 0x02 ; + TELEMETRY_SERIAL_TX_port |= _BV(TELEMETRY_SERIAL_TX_pin); } else { - PORTD &= ~0x02 ; + TELEMETRY_SERIAL_TX_port &= ~_BV(TELEMETRY_SERIAL_TX_pin); } byte /= 2 ; // Generates shorter code than byte >>= 1 if ( GPIOR1 > 2 ) diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 7316233..9468a65 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -36,7 +36,7 @@ #define A7105_INSTALLED #define CYRF6936_INSTALLED #define CC2500_INSTALLED -#define NFR24L01_INSTALLED +#define NRF24L01_INSTALLED //Bellow is the list of all available protocols. Comment the protocols you are not using with "//" to save Flash space. #ifdef A7105_INSTALLED @@ -54,7 +54,7 @@ #define FRSKYX_CC2500_INO #define SFHSS_CC2500_INO #endif -#ifdef NFR24L01_INSTALLED +#ifdef NRF24L01_INSTALLED #define BAYANG_NRF24L01_INO #define CG023_NRF24L01_INO #define CX10_NRF24L01_INO From 9c55a898f7873c3784145a3d8030c725210ea7dd Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 19 Sep 2016 18:58:09 +0200 Subject: [PATCH 227/293] New DSM protocol DSM sub_protocols are now: - DSM2/1024@22ms - DSM2/2048@11ms - DSMX/2048@22ms - DSMX/2048@11ms Option=number of channels from 4 to 12 for normal receivers or -4 to -12 fro OrangeRX. An invalid option value will end up with 6 channels. --- Multiprotocol/DSM_cyrf6936.ino | 508 +++++++++++++++++---------------- Multiprotocol/Multiprotocol.h | 43 ++- Multiprotocol/_Config.h | 8 +- 3 files changed, 288 insertions(+), 271 deletions(-) diff --git a/Multiprotocol/DSM_cyrf6936.ino b/Multiprotocol/DSM_cyrf6936.ino index 27d1ad3..ea27d71 100644 --- a/Multiprotocol/DSM_cyrf6936.ino +++ b/Multiprotocol/DSM_cyrf6936.ino @@ -17,29 +17,47 @@ #include "iface_cyrf6936.h" -#define RANDOM_CHANNELS 0 // disabled -//#define RANDOM_CHANNELS 1 // enabled -#define BIND_CHANNEL 0x0d //13 This can be any odd channel +#define DSM2_RANDOM_CHANNELS 0 // disabled +//#define DSM2_RANDOM_CHANNELS 1 // enabled +#define DSM_BIND_CHANNEL 0x0d //13 This can be any odd channel //During binding we will send BIND_COUNT/2 packets //One packet each 10msec -#define BIND_COUNT1 600 +#define DSM_BIND_COUNT 300 enum { - DSM2_BIND = 0, - DSM2_CHANSEL = BIND_COUNT1 + 0, - DSM2_CH1_WRITE_A = BIND_COUNT1 + 1, - DSM2_CH1_CHECK_A = BIND_COUNT1 + 2, - DSM2_CH2_WRITE_A = BIND_COUNT1 + 3, - DSM2_CH2_CHECK_A = BIND_COUNT1 + 4, - DSM2_CH2_READ_A = BIND_COUNT1 + 5, - DSM2_CH1_WRITE_B = BIND_COUNT1 + 6, - DSM2_CH1_CHECK_B = BIND_COUNT1 + 7, - DSM2_CH2_WRITE_B = BIND_COUNT1 + 8, - DSM2_CH2_CHECK_B = BIND_COUNT1 + 9, - DSM2_CH2_READ_B = BIND_COUNT1 + 10, + DSM_BIND_WRITE=0, + DSM_BIND_CHECK, + DSM_BIND_READ, + DSM_CHANSEL, + DSM_CH1_WRITE_A, + DSM_CH1_CHECK_A, + DSM_CH2_WRITE_A, + DSM_CH2_CHECK_A, + DSM_CH2_READ_A, + DSM_CH1_WRITE_B, + DSM_CH1_CHECK_B, + DSM_CH2_WRITE_B, + DSM_CH2_CHECK_B, + DSM_CH2_READ_B, }; +// +uint8_t sop_col; +uint8_t DSM_orx=0; +uint8_t DSM_num_ch=0; +uint8_t ch_map[14]; +const uint8_t PROGMEM ch_map_progmem[][12] = { + {0, 1, 2, 3, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, //Guess + {0, 1, 2, 3, 4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, //Guess + {1, 5, 2, 3, 0, 4, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff}, //HP6DSM + {1, 5, 2, 4, 3, 6, 0, 0xff, 0xff, 0xff, 0xff, 0xff}, //DX6i + {1, 5, 2, 3, 6, 0xff, 0xff, 4, 0, 7, 0xff, 0xff}, //DX8 + {3, 2, 1, 5, 0, 4, 6, 7, 8, 0xff, 0xff, 0xff}, //DM9 + {3, 2, 1, 5, 0, 4, 6, 7, 8, 9, 0xff, 0xff}, //Guess + {3, 2, 1, 5, 0, 4, 6, 7, 8, 9, 10, 0xff}, //Guess + {3, 2, 1, 5, 0, 4, 6, 7, 8, 9, 10, 11} }; //Guess + const uint8_t PROGMEM pncodes[5][9][8] = { /* Note these are in order transmitted (LSB 1st) */ { /* Row 0 */ @@ -85,6 +103,8 @@ const uint8_t PROGMEM pncodes[5][9][8] = { /* Col 6 */ {0xBF, 0x54, 0x98, 0xB9, 0xB7, 0x30, 0x5A, 0x88}, /* Col 7 */ {0x35, 0xD1, 0xFC, 0x97, 0x23, 0xD4, 0xC9, 0x88}, /* Col 8 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93} +// Wrong values used by Orange TX/RX +// /* Col 8 */ {0x88, 0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40} }, { /* Row 4 */ /* Col 0 */ {0xE1, 0xD6, 0x31, 0x26, 0x5F, 0xBD, 0x40, 0x93}, @@ -101,15 +121,25 @@ const uint8_t PROGMEM pncodes[5][9][8] = { static void __attribute__((unused)) read_code(uint8_t *buf, uint8_t row, uint8_t col, uint8_t len) { - for(uint8_t i=0;i> 8; packet[9] = sum & 0xff; packet[10] = 0x01; //??? - packet[11] = option>3?option:option+4; - if(sub_protocol==DSMX) //DSMX type -#if defined DSM_TELEMETRY - packet[12] = 0xb2; // Telemetry on -#else - packet[12] = option<8? 0xa2 : 0xb2; // Telemetry off -#endif - else - packet[12] = option<8?0x01:0x02; + packet[11] = DSM_num_ch; + + if (sub_protocol==DSM2_22) + packet[12]=DSM_num_ch<8?0x01:0x02; // DSM2/1024 1 or 2 packets depending on the number of channels + if(sub_protocol==DSM2_11) + packet[12]=0x12; // DSM2/2048 2 packets + if(sub_protocol==DSMX_22) + #if defined DSM_TELEMETRY + packet[12] = 0xb2; // DSMX/2048 2 packets + #else + packet[12] = DSM_num_ch<8? 0xa2 : 0xb2; // DSMX/2048 1 or 2 packets depending on the number of channels + #endif + if(sub_protocol==DSMX_11 || sub_protocol==DSM_AUTO) // Force DSMX/1024 in mode Auto + packet[12]=0xb2; // DSMX/1024 2 packets + packet[13] = 0x00; //??? for(i = 8; i < 14; i++) sum += packet[i]; @@ -143,128 +179,75 @@ static void __attribute__((unused)) build_bind_packet() packet[15] = sum & 0xff; } -static uint8_t __attribute__((unused)) PROTOCOL_SticksMoved(uint8_t init) +static void __attribute__((unused)) update_channels() { -#define STICK_MOVEMENT 15*(servo_max_125-servo_min_125)/100 // defines when the bind dialog should be interrupted (stick movement STICK_MOVEMENT %) - static uint16_t ele_start, ail_start; - uint16_t ele = Servo_data[ELEVATOR];//CHAN_ReadInput(MIXER_MapChannel(INP_ELEVATOR)); - uint16_t ail = Servo_data[AILERON];//CHAN_ReadInput(MIXER_MapChannel(INP_AILERON)); - if(init) { - ele_start = ele; - ail_start = ail; - return 0; - } - uint16_t ele_diff = ele_start - ele;//abs(ele_start - ele); - uint16_t ail_diff = ail_start - ail;//abs(ail_start - ail); - return ((ele_diff + ail_diff) > STICK_MOVEMENT);// + prev_option=option; + if(sub_protocol==DSM_AUTO) + DSM_num_ch=12; // Force 12 channels in mode Auto + else + if(option&0x80) + { + DSM_num_ch=-option; + DSM_orx=1; // Use orange table + } + else + { + DSM_num_ch=option; + DSM_orx=0; // Use normal table + } + if(DSM_num_ch<4 || DSM_num_ch>12) + DSM_num_ch=6; // Default to 6 channels if invalid choice... + + // Create channel map based on number of channels + for(uint8_t i=0;i<12;i++) + ch_map[i]=pgm_read_byte_near(&ch_map_progmem[DSM_num_ch-4][i]); + ch_map[12]=0xFF; + ch_map[13]=0xFF; + // TODO: if DSM2_11 or DSMX_11 then repeat lower channels to upper channels need to rewrite this part + if(DSM_num_ch<8) + for(uint8_t i=7;i<14;i++) + ch_map[i]=ch_map[i-7]; } -static void __attribute__((unused)) build_data_packet(uint8_t upper)// +static void __attribute__((unused)) build_data_packet(uint8_t upper) { - uint8_t i; - uint8_t bits; + uint16_t max = 2047; + uint8_t bits = 11; - uint8_t ch_map[] = {3, 2, 1, 5, 0, 4, 6, 7, 8, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}; //9 Channels - DM9 TX - switch(option>3?option:option+4) // Create channel map based on number of channels - { - case 12: - ch_map[11]=11; // 12 channels - case 11: - ch_map[10]=10; // 11 channels - case 10: - ch_map[9]=9; // 10 channels - break; - case 8: - memcpy(ch_map,"\x01\x05\x02\x03\x06\xFF\xFF\x04\x00\x07",10); // 8 channels - DX8 TX - break; - case 7: - memcpy(ch_map,"\x01\x05\x02\x04\x03\x06\x00",7); // 7 channels - DX6i TX - break; - case 6: - memcpy(ch_map,"\x01\x05\x02\x03\x00\x04\xFF",7); // 6 channels - HP6DSM TX - break; - case 4: - case 5: - memcpy(ch_map,"\x00\x01\x02\x03\xFF\xFF\xFF",7); // 4 channels - Guess - if(option&0x01) - ch_map[4]=4; // 5 channels - Guess - break; - } - // - if( binding && PROTOCOL_SticksMoved(0) ) - binding = 0; - if (sub_protocol==DSMX) + if(prev_option!=option) + update_channels(); + + if (sub_protocol==DSMX_11 || sub_protocol==DSMX_22 ) { packet[0] = cyrfmfg_id[2]; packet[1] = cyrfmfg_id[3]; - bits=11; } else { packet[0] = (0xff ^ cyrfmfg_id[2]); packet[1] = (0xff ^ cyrfmfg_id[3]); - bits=10; + if(sub_protocol==DSM2_22) + { + max=1023; // Only DSM_22 is using a resolution of 1024 + bits=10; + } } - // - uint16_t max = 1 << bits;//max=2048 for DSMX & 1024 for DSM2 less than 8 ch and 2048 otherwise - //uint16_t pct_100 = (uint32_t)max * 100 / 150;//682 1024*100/150 - // - for (i = 0; i < 7; i++) + + for (uint8_t i = 0; i < 7; i++) { - uint8_t idx = ch_map[upper * 7 + i];//1,5,2,3,0,4 + uint8_t idx = ch_map[(upper?7:0) + i];//1,5,2,3,0,4 uint16_t value = 0xffff;; if (idx != 0xff) { - if (binding) + if (!IS_BIND_DONE_on) { // Failsafe position during binding - value=max/2; //all channels to middle + value=max/2; //all channels to middle if(idx==0) - value=1; //except throttle + value=1; //except throttle } else - { - switch(idx) - { - case 0: - value=Servo_data[THROTTLE];//85.75-938.25=125%//171-853=100% - break; - case 1: - value=Servo_data[AILERON]; - break; - case 2: - value=Servo_data[ELEVATOR]; - break; - case 3: - value=Servo_data[RUDDER]; - break; - case 4: - value=Servo_data[AUX1]; - break; - case 5: - value=Servo_data[AUX2]; - break; - case 6: - value=Servo_data[AUX3]; - break; - case 7: - value=Servo_data[AUX4]; - break; - case 8: - value=Servo_data[AUX5]; - break; - case 9: - value=Servo_data[AUX6]; - break; - case 10: - value=Servo_data[AUX7]; - break; - case 11: - value=Servo_data[AUX8]; - break; - } - value=map(value,servo_min_125,servo_max_125,0,max-1); - } - value |= (upper && i == 0 ? 0x8000 : 0) | (idx << bits); + value=map(Servo_data[CH_TAER[idx]],servo_min_125,servo_max_125,0,max); + value |= (upper ? 0x8000 : 0) | (idx << bits); } packet[i*2+2] = (value >> 8) & 0xff; packet[i*2+3] = (value >> 0) & 0xff; @@ -273,11 +256,11 @@ static void __attribute__((unused)) build_data_packet(uint8_t upper)// static uint8_t __attribute__((unused)) get_pn_row(uint8_t channel) { - return (sub_protocol == DSMX ? (channel - 2) % 5 : channel % 5); + return ((sub_protocol == DSMX_11 || sub_protocol == DSMX_22 )? (channel - 2) % 5 : channel % 5); } -const uint8_t init_vals[][2] = { - {CYRF_02_TX_CTRL, 0x02}, //0x00 in deviation but needed to know when transmit is over +const uint8_t PROGMEM init_vals[][2] = { + {CYRF_02_TX_CTRL, 0x02}, //0x00 in deviation but needed to know when transmit is over {CYRF_05_RX_CTRL, 0x00}, {CYRF_28_CLK_EN, 0x02}, {CYRF_32_AUTO_CAL_TIME, 0x3c}, @@ -285,44 +268,44 @@ const uint8_t init_vals[][2] = { {CYRF_06_RX_CFG, 0x4A}, {CYRF_1B_TX_OFFSET_LSB, 0x55}, {CYRF_1C_TX_OFFSET_MSB, 0x05}, - {CYRF_0F_XACT_CFG, 0x24}, // Force Idle + {CYRF_0F_XACT_CFG, 0x24}, // Force Idle {CYRF_03_TX_CFG, 0x38 | CYRF_BIND_POWER}, //Set 64chip, SDR mode {CYRF_12_DATA64_THOLD, 0x0a}, - {CYRF_0F_XACT_CFG, 0x04}, // Idle + {CYRF_0F_XACT_CFG, 0x04}, // Idle {CYRF_39_ANALOG_CTRL, 0x01}, - {CYRF_0F_XACT_CFG, 0x24}, //Force IDLE - {CYRF_29_RX_ABORT, 0x00}, //Clear RX abort - {CYRF_12_DATA64_THOLD, 0x0a}, //set pn correlation threshold - {CYRF_10_FRAMING_CFG, 0x4a}, //set sop len and threshold - {CYRF_29_RX_ABORT, 0x0f}, //Clear RX abort? + {CYRF_0F_XACT_CFG, 0x24}, //Force IDLE + {CYRF_29_RX_ABORT, 0x00}, //Clear RX abort + {CYRF_12_DATA64_THOLD, 0x0a}, //set pn correlation threshold + {CYRF_10_FRAMING_CFG, 0x4a}, //set sop len and threshold + {CYRF_29_RX_ABORT, 0x0f}, //Clear RX abort? {CYRF_03_TX_CFG, 0x38 | CYRF_BIND_POWER}, //Set 64chip, SDR mode - {CYRF_10_FRAMING_CFG, 0x4a}, //set sop len and threshold - {CYRF_1F_TX_OVERRIDE, 0x04}, //disable tx CRC - {CYRF_1E_RX_OVERRIDE, 0x14}, //disable rx crc - {CYRF_14_EOP_CTRL, 0x02}, //set EOP sync == 2 - {CYRF_01_TX_LENGTH, 0x10}, //16byte packet + {CYRF_10_FRAMING_CFG, 0x4E}, //0x4a}, //set sop len and threshold + {CYRF_1F_TX_OVERRIDE, 0x04}, //disable tx CRC + {CYRF_1E_RX_OVERRIDE, 0x14}, //disable rx crc + {CYRF_14_EOP_CTRL, 0x02}, //set EOP sync == 2 + {CYRF_01_TX_LENGTH, 0x10}, //16byte packet }; static void __attribute__((unused)) cyrf_config() { for(uint8_t i = 0; i < sizeof(init_vals) / 2; i++) - CYRF_WriteRegister(init_vals[i][0], init_vals[i][1]); + CYRF_WriteRegister(pgm_read_byte_near(&init_vals[i][0]), pgm_read_byte_near(&init_vals[i][1])); CYRF_WritePreamble(0x333304); CYRF_ConfigRFChannel(0x61); } -static void __attribute__((unused)) initialize_bind_state() +static void __attribute__((unused)) initialize_bind_phase() { uint8_t code[32]; - CYRF_ConfigRFChannel(BIND_CHANNEL); //This seems to be random? - uint8_t pn_row = get_pn_row(BIND_CHANNEL); - //printf("Ch: %d Row: %d SOP: %d Data: %d\n", BIND_CHANNEL, pn_row, sop_col, data_col); + CYRF_ConfigRFChannel(DSM_BIND_CHANNEL); //This seems to be random? + uint8_t pn_row = get_pn_row(DSM_BIND_CHANNEL); + //printf("Ch: %d Row: %d SOP: %d Data: %d\n", DSM_BIND_CHANNEL, pn_row, sop_col, 7 - sop_col); CYRF_ConfigCRCSeed(crc); read_code(code,pn_row,sop_col,8); CYRF_ConfigSOPCode(code); - read_code(code,pn_row,data_col,16); + read_code(code,pn_row,7 - sop_col,16); read_code(code+16,0,8,8); memcpy(code + 24, (void *)"\xc6\x94\x22\xfe\x48\xe6\x57\x4e", 8); CYRF_ConfigDataCode(code, 32); @@ -330,8 +313,8 @@ static void __attribute__((unused)) initialize_bind_state() build_bind_packet(); } -const uint8_t data_vals[][2] = { - {CYRF_05_RX_CTRL, 0x83}, //Initialize for reading RSSI +const uint8_t PROGMEM data_vals[][2] = { + {CYRF_05_RX_CTRL, 0x83}, //Initialize for reading RSSI {CYRF_29_RX_ABORT, 0x20}, {CYRF_0F_XACT_CFG, 0x24}, {CYRF_29_RX_ABORT, 0x00}, @@ -342,7 +325,7 @@ const uint8_t data_vals[][2] = { {CYRF_03_TX_CFG, 0x28 | CYRF_HIGH_POWER}, {CYRF_12_DATA64_THOLD, 0x3f}, {CYRF_10_FRAMING_CFG, 0xff}, - {CYRF_0F_XACT_CFG, 0x24}, //Switch from reading RSSI to Writing + {CYRF_0F_XACT_CFG, 0x24}, //Switch from reading RSSI to Writing {CYRF_29_RX_ABORT, 0x00}, {CYRF_12_DATA64_THOLD, 0x0a}, {CYRF_10_FRAMING_CFG, 0xea}, @@ -351,24 +334,24 @@ const uint8_t data_vals[][2] = { static void __attribute__((unused)) cyrf_configdata() { for(uint8_t i = 0; i < sizeof(data_vals) / 2; i++) - CYRF_WriteRegister(data_vals[i][0], data_vals[i][1]); + CYRF_WriteRegister(pgm_read_byte_near(&data_vals[i][0]), pgm_read_byte_near(&data_vals[i][1])); } static void __attribute__((unused)) set_sop_data_crc() { uint8_t code[16]; uint8_t pn_row = get_pn_row(hopping_frequency[hopping_frequency_no]); - //printf("Ch: %d Row: %d SOP: %d Data: %d\n", ch[hopping_frequency_no], pn_row, sop_col, data_col); + //printf("Ch: %d Row: %d SOP: %d Data: %d\n", ch[hopping_frequency_no], pn_row, sop_col, 7 - sop_col); CYRF_ConfigRFChannel(hopping_frequency[hopping_frequency_no]); CYRF_ConfigCRCSeed(crc); crc=~crc; read_code(code,pn_row,sop_col,8); CYRF_ConfigSOPCode(code); - read_code(code,pn_row,data_col,16); + read_code(code,pn_row,7 - sop_col,16); CYRF_ConfigDataCode(code, 16); - if(sub_protocol == DSMX) + if(sub_protocol == DSMX_11 || sub_protocol == DSMX_22) hopping_frequency_no = (hopping_frequency_no + 1) % 23; else hopping_frequency_no = (hopping_frequency_no + 1) % 2; @@ -408,128 +391,167 @@ static void __attribute__((unused)) calc_dsmx_channel() } } +static uint8_t __attribute__((unused)) DSM_Check_RX_packet() +{ + uint8_t result=1; // assume good packet + + uint16_t sum = 384 - 0x10; + for(uint8_t i = 1; i < 9; i++) + { + sum += pkt[i]; + if(i<5) + if(pkt[i] != (0xff ^ cyrfmfg_id[i-1])) + result=0; // bad packet + } + if( pkt[9] != (sum>>8) && pkt[10] != (uint8_t)sum ) + result=0; + return result; +} + uint16_t ReadDsm() { -#define DSM_CH1_CH2_DELAY 4010 // Time between write of channel 1 and channel 2 -#define DSM_WRITE_DELAY 1550 // Time after write to verify write complete -#define DSM_READ_DELAY 600 // Time before write to check read state, and switch channels. Was 400 but 500 seems what the 328p needs to read a packet +#define DSM_CH1_CH2_DELAY 4010 // Time between write of channel 1 and channel 2 +#define DSM_WRITE_DELAY 1550 // Time after write to verify write complete +#define DSM_READ_DELAY 600 // Time before write to check read phase, and switch channels. Was 400 but 600 seems what the 328p needs to read a packet uint16_t start; - - switch(state) + uint8_t rx_phase; + uint8_t len; + + switch(phase) { - default: - //Binding - state++; - if(state & 1) - { - //Send packet on even states - //Note state has already incremented, so this is actually 'even' state - CYRF_WriteDataPacket(packet); - return 8500; + case DSM_BIND_WRITE: + if(bind_counter--==0) + phase=DSM_BIND_CHECK; //Check RX answer + CYRF_WriteDataPacket(packet); + return 10000; + case DSM_BIND_CHECK: + CYRF_ConfigDataCode((const uint8_t *)"\x98\x88\x1B\xE4\x30\x79\x03\x84\xC9\x2C\x06\x93\x86\xB9\x9E", 16); + CYRF_SetTxRxMode(RX_EN); //Receive mode + CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); //Prepare to receive + phase++; // change from BIND_CHECK to BIND_READ + return 2000; + case DSM_BIND_READ: + //Read data from RX + rx_phase = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS); + if((rx_phase & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing) + rx_phase |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS); + if((rx_phase & 0x07) == 0x02) + { // data received + CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // need to set RXOW before data read + len=CYRF_ReadRegister(CYRF_09_RX_COUNT); + if(len>MAX_PKT-2) + len=MAX_PKT-2; + CYRF_ReadDataPacketLen(pkt+1, len); + if(len==10 && DSM_Check_RX_packet()) + { + pkt[0]=0x80; + telemetry_link=1; // send received data on serial + CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); + CYRF_SetTxRxMode(TX_EN); //Write mode + phase++; + return 2000; + } } - else - { - //Check status on odd states - CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS); - return 1500; - } - case DSM2_CHANSEL: + //Force end read phase + CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x2C); // Force end phase + start=micros(); + while ((uint16_t)micros()-start < 100) // Wait max 100 µs + if((CYRF_ReadRegister(CYRF_0F_XACT_CFG) & 0x20) == 0) + break; + CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x0C); // Read + CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); //Prepare to receive + return 7000; + case DSM_CHANSEL: BIND_DONE; //Select channels and configure for writing data //CYRF_FindBestChannels(ch, 2, 10, 1, 79); cyrf_configdata(); CYRF_SetTxRxMode(TX_EN); hopping_frequency_no = 0; - state = DSM2_CH1_WRITE_A; // in fact state++ + phase = DSM_CH1_WRITE_A; // in fact phase++ set_sop_data_crc(); return 10000; - case DSM2_CH1_WRITE_A: - case DSM2_CH1_WRITE_B: - case DSM2_CH2_WRITE_A: - case DSM2_CH2_WRITE_B: - build_data_packet(state == DSM2_CH1_WRITE_B);// build lower or upper channels - CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS); // clear IRQ flags + case DSM_CH1_WRITE_A: + case DSM_CH1_WRITE_B: + case DSM_CH2_WRITE_A: + case DSM_CH2_WRITE_B: + build_data_packet(phase == DSM_CH1_WRITE_B||phase == DSM_CH2_WRITE_B); // build lower or upper channels + CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS); // clear IRQ flags CYRF_WriteDataPacket(packet); - state++; // change from WRITE to CHECK mode + phase++; // change from WRITE to CHECK mode return DSM_WRITE_DELAY; - case DSM2_CH1_CHECK_A: - case DSM2_CH1_CHECK_B: + case DSM_CH1_CHECK_A: + case DSM_CH1_CHECK_B: start=micros(); - while ((uint16_t)micros()-start < 500) // Wait max 500µs + while ((uint16_t)micros()-start < 500) // Wait max 500µs if(CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02) break; set_sop_data_crc(); - state++; // change from CH1_CHECK to CH2_WRITE + phase++; // change from CH1_CHECK to CH2_WRITE return DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY; - case DSM2_CH2_CHECK_A: - case DSM2_CH2_CHECK_B: + case DSM_CH2_CHECK_A: + case DSM_CH2_CHECK_B: start=micros(); - while ((uint16_t)micros()-start < 500) // Wait max 500µs + while ((uint16_t)micros()-start < 500) // Wait max 500µs if(CYRF_ReadRegister(CYRF_04_TX_IRQ_STATUS) & 0x02) break; - if (state == DSM2_CH2_CHECK_A) - CYRF_SetPower(0x28); //Keep transmit power in sync + if (phase == DSM_CH2_CHECK_A) + CYRF_SetPower(0x28); //Keep transmit power in sync #if defined DSM_TELEMETRY - state++; // change from CH2_CHECK to CH2_READ - if(option<=3 || option>7) - { // disable telemetry for option between 4 and 7 ie 4,5,6,7 channels @11ms since it does not work... - CYRF_SetTxRxMode(RX_EN); //Receive mode - CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive - } + phase++; // change from CH2_CHECK to CH2_READ + CYRF_SetTxRxMode(RX_EN); //Receive mode + CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY - DSM_READ_DELAY; - case DSM2_CH2_READ_A: - case DSM2_CH2_READ_B: + case DSM_CH2_READ_A: + case DSM_CH2_READ_B: //Read telemetry - uint8_t rx_state = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS); - if((rx_state & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing) - rx_state |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS); - if((rx_state & 0x07) == 0x02) + rx_phase = CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS); + if((rx_phase & 0x03) == 0x02) // RXC=1, RXE=0 then 2nd check is required (debouncing) + rx_phase |= CYRF_ReadRegister(CYRF_07_RX_IRQ_STATUS); + if((rx_phase & 0x07) == 0x02) { // good data (complete with no errors) CYRF_WriteRegister(CYRF_07_RX_IRQ_STATUS, 0x80); // need to set RXOW before data read - uint8_t len=CYRF_ReadRegister(CYRF_09_RX_COUNT); + len=CYRF_ReadRegister(CYRF_09_RX_COUNT); if(len>MAX_PKT-2) len=MAX_PKT-2; CYRF_ReadDataPacketLen(pkt+1, len); - pkt[0]=CYRF_ReadRegister(CYRF_13_RSSI)&0x1F; // store RSSI of the received telemetry signal + pkt[0]=CYRF_ReadRegister(CYRF_13_RSSI)&0x1F;// store RSSI of the received telemetry signal telemetry_link=1; } - if (state == DSM2_CH2_READ_A && option <= 3) // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms + if (phase == DSM_CH2_READ_A && (sub_protocol==DSM2_22 || sub_protocol==DSMX_22) && DSM_num_ch < 8) // 22ms mode { - //Force end read state - CYRF_WriteRegister(CYRF_0F_XACT_CFG, (CYRF_ReadRegister(CYRF_0F_XACT_CFG) | 0x20)); // Force end state + //Force end read phase + CYRF_WriteRegister(CYRF_0F_XACT_CFG, (CYRF_ReadRegister(CYRF_0F_XACT_CFG) | 0x20)); // Force end phase start=micros(); - while ((uint16_t)micros()-start < 100) // Wait max 100 µs + while ((uint16_t)micros()-start < 100) // Wait max 100 µs if((CYRF_ReadRegister(CYRF_0F_XACT_CFG) & 0x20) == 0) break; - state = DSM2_CH2_READ_B; - CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive + phase = DSM_CH2_READ_B; + CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x87); //0x80??? //Prepare to receive return 11000; } - if (state == DSM2_CH2_READ_A && option>7) - state = DSM2_CH1_WRITE_B; //Transmit upper + if (phase == DSM_CH2_READ_A) + phase = DSM_CH1_WRITE_B; //Transmit upper else - state = DSM2_CH1_WRITE_A; //Force 11ms if option>3 ie 4,5,6,7 channels @11ms + phase = DSM_CH1_WRITE_A; //Transmit lower CYRF_SetTxRxMode(TX_EN); //Write mode set_sop_data_crc(); return DSM_READ_DELAY; #else // No telemetry set_sop_data_crc(); - if (state == DSM2_CH2_CHECK_A) + if (phase == DSM_CH2_CHECK_A) { - if(option < 8) - { - state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper) - if(option>3) - return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ; // force 11ms if option>3 ie 4,5,6,7 channels @11ms - else - return 22000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ; // normal 22ms mode if option<=3 ie 4,5,6,7 channels @22ms + if(DSM_num_ch > 7 || sub_protocol==DSM2_11 || sub_protocol==DSMX_11) + phase = DSM_CH1_WRITE_B; //11ms mode or upper to transmit change from CH2_CHECK_A to CH1_WRITE_A + else + { //Normal mode 22ms + phase = DSM_CH1_WRITE_A; // change from CH2_CHECK_A to CH1_WRITE_A (ie no upper) + return 22000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY ; } - else - state = DSM2_CH1_WRITE_B; // change from CH2_CHECK_A to CH1_WRITE_A (to transmit upper) } else - state = DSM2_CH1_WRITE_A; // change from CH2_CHECK_B to CH1_WRITE_A (upper already transmitted so transmit lower) + phase = DSM_CH1_WRITE_A; // change from CH2_CHECK_B to CH1_WRITE_A (upper already transmitted so transmit lower) return 11000 - DSM_CH1_CH2_DELAY - DSM_WRITE_DELAY; #endif } @@ -545,15 +567,14 @@ uint16_t initDsm() cyrf_config(); - if (sub_protocol == DSMX) + if (sub_protocol == DSMX_11 || sub_protocol == DSMX_22) calc_dsmx_channel(); else { -#if RANDOM_CHANNELS == 1 +#if DSM2_RANDOM_CHANNELS == 1 uint8_t tmpch[10]; CYRF_FindBestChannels(tmpch, 10, 5, 3, 75); // - randomSeed((uint32_t)analogRead(A6)<<10|analogRead(A7));//seed uint8_t idx = random(0xfefefefe) % 10; hopping_frequency[0] = tmpch[idx]; while(1) @@ -574,22 +595,19 @@ uint16_t initDsm() crc = ~((cyrfmfg_id[0] << 8) + cyrfmfg_id[1]); // sop_col = (cyrfmfg_id[0] + cyrfmfg_id[1] + cyrfmfg_id[2] + 2) & 0x07; - data_col = 7 - sop_col; CYRF_SetTxRxMode(TX_EN); // - if(IS_AUTOBIND_FLAG_on) + update_channels(); + if(IS_AUTOBIND_FLAG_on ) { - state = DSM2_BIND; - PROTOCOL_SticksMoved(1); //Initialize Stick position - initialize_bind_state(); - binding = 1; + BIND_IN_PROGRESS; + initialize_bind_phase(); + phase = DSM_BIND_WRITE; + bind_counter=DSM_BIND_COUNT; } else - { - state = DSM2_CHANSEL;// - binding = 0; - } + phase = DSM_CHANSEL;// return 10000; } diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 195797d..d10046a 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -71,17 +71,12 @@ enum Hisky HK310 = 1 }; enum DSM -{ - DSM2 = 0, - DSMX = 1 -}; -enum { DSM2_22 = 0, DSM2_11 = 1, DSMX_22 = 2, DSMX_11 = 3, - AUTO = 4 + DSM_AUTO = 4 }; enum YD717 { @@ -566,28 +561,30 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- RxNum value is 0..15 (bits 0..3) Type is 0..7 <<4 (bit 4..6) sub_protocol==Flysky - Flysky 0 - V9x9 1 - V6x6 2 - V912 3 + Flysky 0 + V9x9 1 + V6x6 2 + V912 3 sub_protocol==Hisky - Hisky 0 - HK310 1 + Hisky 0 + HK310 1 sub_protocol==DSM - DSM2 0 - DSMX 1 + DSM2_22 0 + DSM2_11 1 + DSMX_22 2 + DSMX_11 3 sub_protocol==YD717 - YD717 0 - SKYWLKR 1 - SYMAX4 2 - XINXUN 3 - NIHUI 4 + YD717 0 + SKYWLKR 1 + SYMAX4 2 + XINXUN 3 + NIHUI 4 sub_protocol==KN - WLTOYS 0 - FEILUN 1 + WLTOYS 0 + FEILUN 1 sub_protocol==SYMAX - SYMAX 0 - SYMAX5C 1 + SYMAX 0 + SYMAX5C 1 sub_protocol==CX10 CX10_GREEN 0 CX10_BLUE 1 // also compatible with CX10-A, CX12 diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index 7316233..cdb4e77 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -152,7 +152,7 @@ const PPM_Parameters PPM_prot[15]= { /* 3 */ {MODE_FRSKYD, 0 , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning /* 4 */ {MODE_HISKY , Hisky , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 5 */ {MODE_V2X2 , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, -/* 6 */ {MODE_DSM , DSM2 , 0 , P_HIGH , NO_AUTOBIND , 2 }, // option=2=6 channels @ 22ms +/* 6 */ {MODE_DSM , DSM2_22 , 0 , P_HIGH , NO_AUTOBIND , 2 }, // option=2=6 channels @ 22ms /* 7 */ {MODE_DEVO , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 8 */ {MODE_YD717 , YD717 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 9 */ {MODE_KN , WLTOYS , 0 , P_HIGH , NO_AUTOBIND , 0 }, @@ -179,8 +179,10 @@ const PPM_Parameters PPM_prot[15]= { MODE_V2X2 NONE MODE_DSM - DSM2 - DSMX + DSM2_22 + DSM2_11 + DSMX_22 + DSMX_11 MODE_DEVO NONE MODE_YD717 From dd13ac5cbb990cb46babc8a276e769c79d70acc6 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 19 Sep 2016 19:18:56 +0200 Subject: [PATCH 228/293] Update Protocols_Details.md --- Protocols_Details.md | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 77c242c..46c3be9 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -136,38 +136,28 @@ Bind procedure using PPM: - Note: Autobind/fixed ID mode is linked to the dial number. Which means that you can have multiple dial numbers set to the same protocol DEVO with different RX_Num and have different bind modes at the same time. It enables PPM users to get model match under DEVO. ##DSM -###Sub_protocol DSM2 Extended limits supported Telemetry enabled for TSSI and plugins -option=number of channels and frame rate: - - 0 : 4 channels @22ms - - 1 : 5 channels @22ms - - 2 : 6 channels @22ms - - 3 : 7 channels @22ms - - - 4 : 4 channels @11ms - - 5 : 5 channels @11ms - - 6 : 6 channels @11ms - - 7 : 7 channels @11ms - - - 8 : 8 channels @22ms - - 9 : 9 channels @22ms - - 10 : 10 channels @22ms - - 11 : 11 channels @22ms - - 12 : 12 channels @22ms - -Value 6 is usually giving the best results with most of the RX. +option=number of channels from 4 to 12 for normal receivers or -4 to -12 for OrangeRX. An invalid option value will end up with 6 channels. CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 ---|---|---|---|---|---|---|---|---|----|----|---- A|E|T|R|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 -Note that the RX ouput will be TAER. +Notes: + - model/type/number of channels indicated on the RX can be different from what the RX is in fact wanting to see. So don't hesitate to test different combinations until you have something working. Using Auto is the best way to find it out. + - OrangeRX are using a wrong table which causes issues with some RX_Num values. It is recommended to use the minus number of channels. + - RX ouput will be TAER. -###Sub_protocol DSMX -Same as above +###Sub_protocol DSM2_22 +###Sub_protocol DSM2_11 +###Sub_protocol DSMX_22 +###Sub_protocol DSMX_11 +###Sub_protocol AUTO +The current radio firmware which are able to use the "AUTO" feature are ersky9x (9XR Pro, 9Xtreme, Taranis, ...) and er9x for M128 (9XR) and M2561. +For these firmwares, you must have a telemetry enabled TX and you have to make sure you set the Telemetry "Usr proto" to "DSMx" to be sure of receiving the bind response packet. Also on er9x you will need to be sure to match the polarity of the telemetry serial (normal or inverted by bitbashing), while on ersky9x you can set "Invert COM1" accordinlgy. ##J6Pro From 2ac4097e3245954bc3c42534fa57c69ee55f4a77 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 19 Sep 2016 19:23:40 +0200 Subject: [PATCH 229/293] Update Protocols_Details.md --- Protocols_Details.md | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/Protocols_Details.md b/Protocols_Details.md index 46c3be9..aff27a5 100644 --- a/Protocols_Details.md +++ b/Protocols_Details.md @@ -152,12 +152,19 @@ Notes: - RX ouput will be TAER. ###Sub_protocol DSM2_22 +DSM2, Resolution 1024, refresh rate 22ms ###Sub_protocol DSM2_11 +DSM2, Resolution 2048, refresh rate 11ms ###Sub_protocol DSMX_22 +DSMX, Resolution 2048, refresh rate 22ms ###Sub_protocol DSMX_11 +DSMX, Resolution 2048, refresh rate 11ms ###Sub_protocol AUTO +The "AUTO" feature enables the TX to automatically choose what are the best settings for your DSM RX and update your model protocol settings accordingly. + The current radio firmware which are able to use the "AUTO" feature are ersky9x (9XR Pro, 9Xtreme, Taranis, ...) and er9x for M128 (9XR) and M2561. -For these firmwares, you must have a telemetry enabled TX and you have to make sure you set the Telemetry "Usr proto" to "DSMx" to be sure of receiving the bind response packet. Also on er9x you will need to be sure to match the polarity of the telemetry serial (normal or inverted by bitbashing), while on ersky9x you can set "Invert COM1" accordinlgy. +For these firmwares, you must have a telemetry enabled TX and you have to make sure you set the Telemetry "Usr proto" to "DSMx". +Also on er9x you will need to be sure to match the polarity of the telemetry serial (normal or inverted by bitbashing), while on ersky9x you can set "Invert COM1" accordinlgy. ##J6Pro From fcd47ecec62aeb38389fce88b4e76e2e7d1a180c Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 19 Sep 2016 23:43:14 +0200 Subject: [PATCH 230/293] Correct pins... --- Multiprotocol/A7105_SPI.ino | 32 +-- Multiprotocol/DSM_cyrf6936.ino | 12 +- Multiprotocol/Multiprotocol.h | 315 ++++++++++++------------ Multiprotocol/Multiprotocol.ino | 408 ++++++++++++++++---------------- Multiprotocol/Telemetry.ino | 75 +++--- Multiprotocol/_Config.h | 2 +- 6 files changed, 414 insertions(+), 430 deletions(-) diff --git a/Multiprotocol/A7105_SPI.ino b/Multiprotocol/A7105_SPI.ino index f5c83d2..8327c77 100644 --- a/Multiprotocol/A7105_SPI.ino +++ b/Multiprotocol/A7105_SPI.ino @@ -23,12 +23,12 @@ void A7105_WriteData(uint8_t len, uint8_t channel) { uint8_t i; - A7105_CS_off; + A7105_CSN_off; SPI_Write(A7105_RST_WRPTR); SPI_Write(0x05); for (i = 0; i < len; i++) SPI_Write(packet[i]); - A7105_CS_on; + A7105_CSN_on; A7105_WriteReg(0x0F, channel); A7105_Strobe(A7105_TX); } @@ -36,44 +36,44 @@ void A7105_WriteData(uint8_t len, uint8_t channel) void A7105_ReadData() { uint8_t i; A7105_Strobe(0xF0); //A7105_RST_RDPTR - A7105_CS_off; + A7105_CSN_off; SPI_Write(0x45); for (i=0;i<16;i++) packet[i]=A7105_Read(); - A7105_CS_on; + A7105_CSN_on; } void A7105_WriteReg(uint8_t address, uint8_t data) { - A7105_CS_off; + A7105_CSN_off; SPI_Write(address); NOP(); SPI_Write(data); - A7105_CS_on; + A7105_CSN_on; } uint8_t A7105_ReadReg(uint8_t address) { uint8_t result; - A7105_CS_off; + A7105_CSN_off; SPI_Write(address |=0x40); //bit 6 =1 for reading result = A7105_Read(); - A7105_CS_on; + A7105_CSN_on; return(result); } uint8_t A7105_Read(void) { uint8_t result=0; - SDI_SET_INPUT; + SDI_input; for(uint8_t i=0;i<8;i++) { result=result<<1; if(SDI_1) ///if SDIO =1 result |= 0x01; - SCK_on; + SCLK_on; NOP(); - SCK_off; + SCLK_off; } - SDI_SET_OUTPUT; + SDI_output; return result; } @@ -110,13 +110,13 @@ uint8_t A7105_Reset() } void A7105_WriteID(uint32_t ida) { - A7105_CS_off; + A7105_CSN_off; SPI_Write(0x06);//ex id=0x5475c52a ;txid3txid2txid1txid0 SPI_Write((ida>>24)&0xff);//53 SPI_Write((ida>>16)&0xff);//75 SPI_Write((ida>>8)&0xff);//c5 SPI_Write((ida>>0)&0xff);//2a - A7105_CS_on; + A7105_CSN_on; } /* @@ -162,9 +162,9 @@ void A7105_SetPower() } void A7105_Strobe(uint8_t address) { - A7105_CS_off; + A7105_CSN_off; SPI_Write(address); - A7105_CS_on; + A7105_CSN_on; } const uint8_t PROGMEM HUBSAN_A7105_regs[] = { diff --git a/Multiprotocol/DSM_cyrf6936.ino b/Multiprotocol/DSM_cyrf6936.ino index ea27d71..609f6f6 100644 --- a/Multiprotocol/DSM_cyrf6936.ino +++ b/Multiprotocol/DSM_cyrf6936.ino @@ -428,6 +428,7 @@ uint16_t ReadDsm() CYRF_ConfigDataCode((const uint8_t *)"\x98\x88\x1B\xE4\x30\x79\x03\x84\xC9\x2C\x06\x93\x86\xB9\x9E", 16); CYRF_SetTxRxMode(RX_EN); //Receive mode CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); //Prepare to receive + bind_counter=300; phase++; // change from BIND_CHECK to BIND_READ return 2000; case DSM_BIND_READ: @@ -447,7 +448,7 @@ uint16_t ReadDsm() pkt[0]=0x80; telemetry_link=1; // send received data on serial CYRF_WriteRegister(CYRF_29_RX_ABORT, 0x20); - CYRF_SetTxRxMode(TX_EN); //Write mode + CYRF_SetTxRxMode(TX_EN); // Write mode phase++; return 2000; } @@ -458,8 +459,13 @@ uint16_t ReadDsm() while ((uint16_t)micros()-start < 100) // Wait max 100 µs if((CYRF_ReadRegister(CYRF_0F_XACT_CFG) & 0x20) == 0) break; - CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x0C); // Read - CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); //Prepare to receive + if( --bind_counter == 0 ) + { + phase++; // Exit if no answer has been received for some time + return 7000 ; + } + CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x0C); // Read mode + CYRF_WriteRegister(CYRF_05_RX_CTRL, 0x83); // Prepare to receive return 7000; case DSM_CHANSEL: BIND_DONE; diff --git a/Multiprotocol/Multiprotocol.h b/Multiprotocol/Multiprotocol.h index 396bea0..1e19dac 100644 --- a/Multiprotocol/Multiprotocol.h +++ b/Multiprotocol/Multiprotocol.h @@ -181,194 +181,188 @@ struct PPM_Parameters //*** Pinouts *** //******************* -#define TELEMETRY_SERIAL_TX_pin 2 -#define TELEMETRY_SERIAL_TX_port PORTD -#define TELEMETRY_SERIAL_TX_ddr DDRD -#define DEBUG_TX_pin 1 -#define DEBUG_TX_port PORTD -#define DEBUG_TX_ddr DDRD -#define MODE_DIAL1_PIN 2 -#define MODE_DIAL1_PORT PORTB -#define MODE_DIAL2_PIN 3 -#define MODE_DIAL2_PORT PORTB -#define MODE_DIAL3_PIN 4 -#define MODE_DIAL3_PORT PORTB -#define MODE_DIAL4_PIN 0 -#define MODE_DIAL4_PORT PORTC -#define LED_pin 5 //D13 = PB5 -#define LED_port PORTB -#define LED_ddr DDRB -#define BIND_pin 5 //D13 = PB5 -#define BIND_port PORTB -#define BIND_ipr PINB -#define BIND_ddr DDRB -#define PPM_pin 3 //D3 = PD3 -#define PPM_port PORTD -#ifdef XMEGA - #define SDI_pin 6 //SDIO-D6 - #define SDI_port PORTD - #define SDI_ipr PIND - #define SDI_ddr DDRD +// TX +#define SERIAL_TX_pin 1 // PD1 +#define SERIAL_TX_port PORTD +#define SERIAL_TX_ddr DDRD +#define SERIAL_TX_output SERIAL_TX_ddr |= _BV(SERIAL_TX_pin) +#define SERIAL_TX_on SERIAL_TX_port |= _BV(SERIAL_TX_pin) +#define SERIAL_TX_off SERIAL_TX_port &= ~_BV(SERIAL_TX_pin) +#ifdef DEBUG_TX + #define DEBUG_TX_on SERIAL_TX_ON + #define DEBUG_TX_off SERIAL_TX_OFF + #define DEBUG_TX_toggle SERIAL_TX_port ^= _BV(SERIAL_TX_pin) #else - #define SDI_pin 5 //D5 = PD5 - #define SDI_port PORTD - #define SDI_ipr PIND - #define SDI_ddr DDRD + #define DEBUG_TX_on + #define DEBUG_TX_off + #define DEBUG_TX_toggle #endif -#define SCLK_pin 4 //D4 = PD4 + +// Dial +#define MODE_DIAL1_pin 2 +#define MODE_DIAL1_port PORTB +#define MODE_DIAL2_pin 3 +#define MODE_DIAL2_port PORTB +#define MODE_DIAL3_pin 4 +#define MODE_DIAL3_port PORTB +#define MODE_DIAL4_pin 0 +#define MODE_DIAL4_port PORTC + +// PPM +#define PPM_pin 3 //D3 = PD3 +#define PPM_port PORTD + +// SDIO +#define SDI_pin 5 //D5 = PD5 +#define SDI_port PORTD +#define SDI_ipr PIND +#define SDI_ddr DDRD +#ifdef XMEGA + #define SDI_on SDI_port.OUTSET = _BV(SDI_pin) + #define SDI_off SDI_port.OUTCLR = _BV(SDI_pin) +#else + #define SDI_on SDI_port |= _BV(SDI_pin) + #define SDI_off SDI_port &= ~_BV(SDI_pin) + #define SDI_1 (SDI_ipr & _BV(SDI_pin)) != 0x00 + #define SDI_0 (SDI_ipr & _BV(SDI_pin)) == 0x00 +#endif +#define SDI_input SDI_ddr &= ~_BV(SDI_pin) +#define SDI_output SDI_ddr |= _BV(SDI_pin) + +//SDO +#define SDO_pin 6 //D6 = PD6 +#define SDO_port PORTD +#define SDO_ipr PIND +#ifdef XMEGA + #define SDO_1 (SDO_port.IN & _BV(SDO_pin)) != 0x00 + #define SDO_0 (SDO_port.IN & _BV(SDO_pin)) == 0x00 +#else + #define SDO_1 (SDO_ipr & _BV(SDO_pin)) != 0x00 + #define SDO_0 (SDO_ipr & _BV(SDO_pin)) == 0x00 +#endif + +// SCLK #define SCLK_port PORTD #define SCLK_ddr DDRD -#define A7105_CS_pin 2 //D2 = PD2 -#define A7105_CS_port PORTD -#define A7105_CS_ddr DDRD -#define SDO_pin 6 //D6 = PD6 -#define SDO_port PORTD -#define SDO_ipr PIND -#define CC25_CSN_pin 7 //D7 = PD7 -#define CC25_CSN_port PORTD -#define CC25_CSN_ddr DDRD -#define NRF_CSN_pin 0 //D8 = PB0 -#define NRF_CSN_port PORTB -#define NRF_CSN_ddr DDRB -#define CYRF_CSN_pin 1 //D9 = PB1 -#define CYRF_CSN_port PORTB -#define CYRF_CSN_ddr DDRB -#define CYRF_RST_pin 5 //D9 = PB1 -#define CYRF_RST_port PORTC -#define CYRF_RST_ddr DDRC -#define CTRL1_pin 1 //A1 = PC1 -#define CTRL1_port PORTC -#define CTRL1_ddr DDRC -#define CTRL2_pin 2 //A2 = PC2 -#define CTRL2_port PORTC -#define CTRL2_ddr DDRC -// #ifdef XMEGA - #define CTRL1_on - #define CTRL1_off - #define CTRL2_on - #define CTRL2_off + #define SCLK_pin 7 //D7 + #define SCLK_on SCLK_port.OUTSET = _BV(SCLK_pin) + #define SCLK_off SCLK_port.OUTCLR = _BV(SCLK_pin) #else - #define CTRL1_on CTRL1_port |= _BV(CTRL1_pin) - #define CTRL1_off CTRL1_port &= ~_BV(CTRL1_pin) - #define CTRL2_on CTRL2_port |= _BV(CTRL2_pin) - #define CTRL2_off CTRL2_port &= ~_BV(CTRL2_pin) + #define SCLK_pin 4 //D4 = PD4 + #define SCLK_output SCLK_ddr |= _BV(SCLK_pin) + #define SCLK_on SCLK_port |= _BV(SCLK_pin) + #define SCLK_off SCLK_port &= ~_BV(SCLK_pin) #endif -// + +// A7105 +#define A7105_CSN_pin 2 //D2 = PD2 +#define A7105_CSN_port PORTD +#define A7105_CSN_ddr DDRD +#define A7105_CSN_output A7105_CSN_ddr |= _BV(A7105_CSN_pin) +#define A7105_CSN_on A7105_CSN_port |= _BV(A7105_CSN_pin) +#define A7105_CSN_off A7105_CSN_port &= ~_BV(A7105_CSN_pin) + +// CC2500 +#define CC25_CSN_pin 7 //D7 = PD7 +#define CC25_CSN_port PORTD +#define CC25_CSN_ddr DDRD +#define CC25_CSN_output CC25_CSN_ddr |= _BV(CC25_CSN_pin) +#define CC25_CSN_on CC25_CSN_port |= _BV(CC25_CSN_pin) +#define CC25_CSN_off CC25_CSN_port &= ~_BV(CC25_CSN_pin) + +// NRF24L01 +#define NRF_CSN_pin 0 //D8 = PB0 +#define NRF_CSN_port PORTB +#define NRF_CSN_ddr DDRB +#define NRF_CSN_output NRF_CSN_ddr |= _BV(NRF_CSN_pin) +#define NRF_CSN_on NRF_CSN_port |= _BV(NRF_CSN_pin) +#define NRF_CSN_off NRF_CSN_port &= ~_BV(NRF_CSN_pin) +#define NRF_CE_on +#define NRF_CE_off + +// CYRF6936 #ifdef XMEGA - #define A7105_CS_on A7105_CS_port.OUTSET = _BV(A7105_CS_pin) //D4 - #define A7105_CS_off A7105_CS_port.OUTCLR = _BV(A7105_CS_pin) //D4 + #define CYRF_CSN_pin 4 //D4 + #define CYRF_CSN_port PORTD + #define CYRF_CSN_ddr DDRD + #define CYRF_CSN_on CYRF_CSN_port.OUTSET = _BV(CYRF_CSN_pin) + #define CYRF_CSN_off CYRF_CSN_port.OUTCLR = _BV(CYRF_CSN_pin) #else - #define A7105_CS_on A7105_CS_port |= _BV(A7105_CS_pin) //D2 - #define A7105_CS_off A7105_CS_port &= ~_BV(A7105_CS_pin) //D2 + #define CYRF_CSN_pin 1 //D9 = PB1 + #define CYRF_CSN_port PORTB + #define CYRF_CSN_ddr DDRB + #define CYRF_CSN_output CYRF_CSN_ddr |= _BV(CYRF_CSN_pin) + #define CYRF_CSN_on CYRF_CSN_port |= _BV(CYRF_CSN_pin) + #define CYRF_CSN_off CYRF_CSN_port &= ~_BV(CYRF_CSN_pin) + + #define CYRF_RST_pin 5 //A5 = PC5 + #define CYRF_RST_port PORTC + #define CYRF_RST_ddr DDRC + #define CYRF_RST_output CYRF_RST_ddr |= _BV(CYRF_RST_pin) + #define CYRF_RST_HI CYRF_RST_port |= _BV(CYRF_RST_pin) + #define CYRF_RST_LO CYRF_RST_port &= ~_BV(CYRF_RST_pin) #endif -// + +//RF Switch #ifdef XMEGA - #define SCK_on SCLK_port.OUTSET = _BV(SCLK_pin) //D7 - #define SCK_off SCLK_port.OUTCLR = _BV(SCLK_pin) //D7 + #define PE1_on + #define PE1_off + #define PE2_on + #define PE2_off #else - #define SCK_on SCLK_port |= _BV(SCLK_pin) //D4 - #define SCK_off SCLK_port &= ~_BV(SCLK_pin) //D4 + #define PE1_pin 1 //A1 = PC1 + #define PE1_port PORTC + #define PE1_ddr DDRC + #define PE1_output PE1_ddr |= _BV(PE1_pin) + #define PE1_on PE1_port |= _BV(PE1_pin) + #define PE1_off PE1_port &= ~_BV(PE1_pin) + + #define PE2_pin 2 //A2 = PC2 + #define PE2_port PORTC + #define PE2_ddr DDRC + #define PE2_output PE2_ddr |= _BV(PE2_pin) + #define PE2_on PE2_port |= _BV(PE2_pin) + #define PE2_off PE2_port &= ~_BV(PE2_pin) #endif -// -#ifdef XMEGA - #define SDI_on SDI_port.OUTSET = _BV(SDI_pin) //D5 - #define SDI_off SDI_port.OUTCLR = _BV(SDI_pin) //D5 -#else - #define SDI_on SDI_port |= _BV(SDI_pin) //D5 - #define SDI_off SDI_port &= ~_BV(SDI_pin) //D5 -#endif -// -#ifdef XMEGA - #define SDI_1 (SDI_port.IN & _BV(SDI_pin)) == _BV(SDI_pin) //D5 - #define SDI_0 (SDI_port.IN & _BV(SDI_pin)) == 0x00 //D5 -#else - #define SDI_1 (SDI_ipr & _BV(SDI_pin)) == _BV(SDI_pin) //D5 - #define SDI_0 (SDI_ipr & _BV(SDI_pin)) == 0x00 //D5 -#endif -// -#define SDI_SET_INPUT SDI_ddr &= ~_BV(SDI_pin) //D5 -#define SDI_SET_OUTPUT SDI_ddr |= _BV(SDI_pin) //D5 -// -#ifdef XMEGA - #define CC25_CSN_on CC25_CSN_port.OUTSET = _BV(CC25_CSN_pin) //D7 - #define CC25_CSN_off CC25_CSN_port.OUTCLR = _BV(CC25_CSN_pin) //D7 -#else - #define CC25_CSN_on CC25_CSN_port |= _BV(CC25_CSN_pin) //D7 - #define CC25_CSN_off CC25_CSN_port &= ~_BV(CC25_CSN_pin) //D7 -#endif -// -#ifdef XMEGA - #define NRF_CSN_on - #define NRF_CSN_off - #define NRF_CE_on - #define NRF_CE_off -#else - #define NRF_CSN_on NRF_CSN_port |= _BV(NRF_CSN_pin) //D8 - #define NRF_CSN_off NRF_CSN_port &= ~_BV(NRF_CSN_pin) //D8 - #define NRF_CE_on - #define NRF_CE_off -#endif -// -#ifdef XMEGA - #define CYRF_CSN_on CYRF_CSN_port.OUTSET = _BV(CYRF_CSN_pin) - #define CYRF_CSN_off CYRF_CSN_port.OUTCLR = _BV(CYRF_CSN_pin) -#else - #define CYRF_CSN_on CYRF_CSN_port |= _BV(CYRF_CSN_pin) //D9 - #define CYRF_CSN_off CYRF_CSN_port &= ~_BV(CYRF_CSN_pin) //D9 - #define CYRF_RST_HI CYRF_RST_port |= _BV(CYRF_RST_pin) //A5 - #define CYRF_RST_LO CYRF_RST_port &= ~_BV(CYRF_RST_pin) //A5 - #define CYRF_RST_pin 5 -#endif -// -#ifdef XMEGA - #define SDO_1 (SDO_port.IN & _BV(SDO_pin)) == _BV(SDO_pin) //D6 - #define SDO_0 (SDO_port.IN & _BV(SDO_pin)) == 0x00 //D6 -#else - #define SDO_1 (SDO_ipr & _BV(SDO_pin)) == _BV(SDO_pin) //D6 - #define SDO_0 (SDO_ipr & _BV(SDO_pin)) == 0x00 //D6 -#endif -// -// // LED #ifdef XMEGA - #define LED_ON LED_port.OUTCLR = _BV(LED_pin) - #define LED_OFF LED_port.OUTSET = _BV(LED_pin) - #define LED_TOGGLE LED_port.OUTTGL = _BV(LED_pin) - #define LED_SET_OUTPUT LED_port.DIRSET = _BV(LED_pin) - #define IS_LED_on ( (LED_port.OUT & _BV(LED_pin)) != 0x00 ) + #define LED_pin 1 //PD1 + #define LED_port PORTD + #define LED_ddr DDRD + #define LED_on LED_port.OUTCLR = _BV(LED_pin) + #define LED_off LED_port.OUTSET = _BV(LED_pin) + #define LED_toggle LED_port.OUTTGL = _BV(LED_pin) + #define LED_output LED_port.DIRSET = _BV(LED_pin) + #define IS_LED_on ( (LED_port.OUT & _BV(LED_pin)) != 0x00 ) #else - #define LED_ON LED_port |= _BV(LED_pin) - #define LED_OFF LED_port &= ~_BV(LED_pin) - #define LED_TOGGLE LED_port ^= _BV(LED_pin) - #define LED_SET_OUTPUT LED_ddr |= _BV(LED_pin) - #define IS_LED_on ( (LED_port & _BV(LED_pin)) != 0x00 ) + #define LED_pin 5 //D13 = PB5 + #define LED_port PORTB + #define LED_ddr DDRB + #define LED_on LED_port |= _BV(LED_pin) + #define LED_off LED_port &= ~_BV(LED_pin) + #define LED_toggle LED_port ^= _BV(LED_pin) + #define LED_output LED_ddr |= _BV(LED_pin) + #define IS_LED_on ( (LED_port & _BV(LED_pin)) != 0x00 ) #endif //BIND #ifdef XMEGA - #define IS_BIND_BUTTON_on ( (PORTD.IN & _BV(2)) == 0x00 ) + #define BIND_pin 2 //PD2 + #define BIND_port PORTD + #define IS_BIND_BUTTON_on ( (BIND_port.IN & _BV(BIND_pin)) == 0x00 ) #else + #define BIND_pin 5 //D13 = PB5 + #define BIND_port PORTB + #define BIND_ipr PINB + #define BIND_ddr DDRB #define BIND_SET_INPUT BIND_ddr &= ~_BV(BIND_pin) #define BIND_SET_PULLUP BIND_port |= _BV(BIND_pin) #define IS_BIND_BUTTON_on ( (BIND_ipr & _BV(BIND_pin)) == 0x00 ) #define BIND_SET_OUTPUT BIND_ddr |= _BV(BIND_pin) #endif -// TX -#ifdef DEBUG_TX - #define TX_ON DEBUG_TX_port |= _BV(DEBUG_TX_pin) - #define TX_OFF DEBUG_TX_port &= ~_BV(DEBUG_TX_pin) - #define TX_TOGGLE DEBUG_TX_port ^= _BV(DEBUG_TX_pin) - #define TX_SET_OUTPUT DEBUG_TX_ddr |= _BV(DEBUG_TX_pin) -#else - #define TX_ON - #define TX_OFF - #define TX_TOGGLE - #define TX_SET_OUTPUT -#endif - // Macros #define NOP() __asm__ __volatile__("nop") #define BV(bit) (1 << bit) @@ -674,4 +668,3 @@ Serial: 100000 Baud 8e2 _ xxxx xxxx p -- 2047 +125% Channels bits are concatenated to fit in 22 bytes like in SBUS protocol */ - diff --git a/Multiprotocol/Multiprotocol.ino b/Multiprotocol/Multiprotocol.ino index 112c7af..2694055 100644 --- a/Multiprotocol/Multiprotocol.ino +++ b/Multiprotocol/Multiprotocol.ino @@ -33,7 +33,7 @@ #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 + #undef NRF24L01_INSTALLED // Disable NRF for orange module #endif //Global constants/variables @@ -172,60 +172,59 @@ void setup() TCC1.CTRLA = 0x0B ; // Event3 (prescale of 16) #else // General pinout - - // outputs -#ifdef A7105_INSTALLED - A7105_CS_ddr |= _BV(A7105_CS_pin); -#endif - SDI_SET_OUTPUT; - SCLK_ddr |= _BV(SCLK_pin); -#ifdef CC2500_INSTALLED - CC25_CSN_ddr |= _BV(CC25_CSN_pin); -#endif - CTRL1_ddr |= _BV(CTRL1_pin); - CTRL2_ddr |= _BV(CTRL2_pin); -#ifdef CYRF6936_INSTALLED - CYRF_RST_ddr |= _BV(CYRF_RST_pin); - CYRF_CSN_ddr |= _BV(CYRF_CSN_pin); -#endif -#ifdef NRF24L01_INSTALLED - NRF_CSN_ddr |= _BV(NRF_CSN_pin); -#endif - - //pullup on dial (D10=PB2,D11=PB3,D12=PB4) and bind button - MODE_DIAL1_PORT |= _BV(MODE_DIAL1_PIN); - MODE_DIAL2_PORT |= _BV(MODE_DIAL2_PIN); - MODE_DIAL3_PORT |= _BV(MODE_DIAL3_PIN); - MODE_DIAL4_PORT |= _BV(MODE_DIAL4_PIN); - BIND_port |= _BV(BIND_pin); - - - #ifdef DEBUG_TX - TX_SET_OUTPUT; + // all inputs + DDRB=DDRC=DDRD=0x00; + // outputs + SDI_output; + SCLK_output; + #ifdef A7105_INSTALLED + A7105_CSN_output; #endif + #ifdef CC2500_INSTALLED + CC25_CSN_output; + #endif + #ifdef CYRF6936_INSTALLED + CYRF_RST_output; + CYRF_CSN_output; + #endif + #ifdef NRF24L01_INSTALLED + NRF_CSN_output; + #endif + PE1_output; + PE2_output; + SERIAL_TX_output; + + // pullups + MODE_DIAL1_port |= _BV(MODE_DIAL1_pin); + MODE_DIAL2_port |= _BV(MODE_DIAL2_pin); + MODE_DIAL3_port |= _BV(MODE_DIAL3_pin); + MODE_DIAL4_port |= _BV(MODE_DIAL4_pin); + BIND_port |= _BV(BIND_pin); // Timer1 config TCCR1A = 0; TCCR1B = (1 << CS11); //prescaler8, set timer1 to increment every 0.5us(16Mhz) and start timer + + // Random random_init(); #endif // Set Chip selects -#ifdef A7105_INSTALLED - A7105_CS_on; -#endif -#ifdef CC2500_INSTALLED - CC25_CSN_on; -#endif -#ifdef NRF24L01_INSTALLED - NRF_CSN_on; -#endif -#ifdef CYRF6936_INSTALLED - CYRF_CSN_on; -#endif + #ifdef A7105_INSTALLED + A7105_CSN_on; + #endif + #ifdef CC2500_INSTALLED + CC25_CSN_on; + #endif + #ifdef NRF24L01_INSTALLED + NRF_CSN_on; + #endif + #ifdef CYRF6936_INSTALLED + CYRF_CSN_on; + #endif // Set SPI lines SDI_on; - SCK_off; + SCLK_off; // Set servos positions for(uint8_t i=0;i led on + LED_off; //bind completed -> led on else blink+=BLINK_BIND_TIME; //blink fastly during binding - LED_TOGGLE; + LED_toggle; } } @@ -504,21 +502,21 @@ static void protocol_init() else BIND_DONE; - CTRL1_on; //NRF24L01 antenna RF3 by default - CTRL2_off; //NRF24L01 antenna RF3 by default + PE1_on; //NRF24L01 antenna RF3 by default + PE2_off; //NRF24L01 antenna RF3 by default switch(protocol) // Init the requested protocol { #if defined(FLYSKY_A7105_INO) case MODE_FLYSKY: - CTRL1_off; //antenna RF1 + PE1_off; //antenna RF1 next_callback = initFlySky(); remote_callback = ReadFlySky; break; #endif #if defined(HUBSAN_A7105_INO) case MODE_HUBSAN: - CTRL1_off; //antenna RF1 + PE1_off; //antenna RF1 if(IS_BIND_BUTTON_FLAG_on) random_id(10,true); // Generate new ID if bind button is pressed. next_callback = initHubsan(); remote_callback = ReadHubsan; @@ -526,39 +524,39 @@ static void protocol_init() #endif #if defined(FRSKYD_CC2500_INO) case MODE_FRSKYD: - CTRL1_off; //antenna RF2 - CTRL2_on; + PE1_off; //antenna RF2 + PE2_on; next_callback = initFrSky_2way(); remote_callback = ReadFrSky_2way; break; #endif #if defined(FRSKYV_CC2500_INO) case MODE_FRSKYV: - CTRL1_off; //antenna RF2 - CTRL2_on; + PE1_off; //antenna RF2 + PE2_on; next_callback = initFRSKYV(); remote_callback = ReadFRSKYV; break; #endif #if defined(FRSKYX_CC2500_INO) case MODE_FRSKYX: - CTRL1_off; //antenna RF2 - CTRL2_on; + PE1_off; //antenna RF2 + PE2_on; next_callback = initFrSkyX(); remote_callback = ReadFrSkyX; break; #endif #if defined(SFHSS_CC2500_INO) case MODE_SFHSS: - CTRL1_off; //antenna RF2 - CTRL2_on; + PE1_off; //antenna RF2 + PE2_on; next_callback = initSFHSS(); remote_callback = ReadSFHSS; break; #endif #if defined(DSM_CYRF6936_INO) case MODE_DSM: - CTRL2_on; //antenna RF4 + PE2_on; //antenna RF4 next_callback = initDsm(); //Servo_data[2]=1500;//before binding remote_callback = ReadDsm; @@ -581,14 +579,14 @@ static void protocol_init() } } #endif //ENABLE_PPM - CTRL2_on; //antenna RF4 + PE2_on; //antenna RF4 next_callback = DevoInit(); remote_callback = devo_callback; break; #endif #if defined(J6PRO_CYRF6936_INO) case MODE_J6PRO: - CTRL2_on; //antenna RF4 + PE2_on; //antenna RF4 next_callback = initJ6Pro(); remote_callback = ReadJ6Pro; break; @@ -790,7 +788,7 @@ void modules_reset() #ifdef CYRF6936_INSTALLED CYRF_Reset(); #endif - #ifdef NFR24L01_INSTALLED + #ifdef NRF24L01_INSTALLED NRF24L01_Reset(); #endif @@ -971,7 +969,7 @@ void SPI_Write(uint8_t command) { uint8_t n=8; - SCK_off;//SCK start low + SCLK_off;//SCK start low XNOP(); SDI_off; XNOP(); @@ -982,11 +980,11 @@ void SPI_Write(uint8_t command) else SDI_off; XNOP(); - SCK_on; + SCLK_on; XNOP(); XNOP(); command = command << 1; - SCK_off; + SCLK_off; XNOP(); } while(--n) ; @@ -1001,11 +999,11 @@ uint8_t SPI_Read(void) result=result<<1; if(SDO_1) result |= 0x01; - SCK_on; + SCLK_on; XNOP(); XNOP(); NOP(); - SCK_off; + SCLK_off; XNOP(); XNOP(); } @@ -1124,11 +1122,11 @@ void delayMicroseconds(unsigned int us) } #ifndef XMEGA -void init() -{ - // this needs to be called before setup() or some functions won't work there - sei(); -} + void init() + { + // this needs to be called before setup() or some functions won't work there + sei(); + } #endif //XMEGA /**************************/ @@ -1139,145 +1137,145 @@ void init() //PPM #ifdef ENABLE_PPM -#ifdef XMEGA -#if PPM_pin == 2 -ISR(PORTD_INT0_vect) -#else -ISR(PORTD_INT1_vect) -#endif -#else -#if PPM_pin == 2 -ISR(INT0_vect, ISR_NOBLOCK) -#else -ISR(INT1_vect, ISR_NOBLOCK) -#endif -#endif -{ // Interrupt on PPM pin - static int8_t chan=-1; - static uint16_t Prev_TCNT1=0; - uint16_t Cur_TCNT1; + #ifdef XMEGA + #if PPM_pin == 2 + ISR(PORTD_INT0_vect) + #else + ISR(PORTD_INT1_vect) + #endif + #else + #if PPM_pin == 2 + ISR(INT0_vect, ISR_NOBLOCK) + #else + ISR(INT1_vect, ISR_NOBLOCK) + #endif + #endif + { // Interrupt on PPM pin + static int8_t chan=-1; + static uint16_t Prev_TCNT1=0; + uint16_t Cur_TCNT1; - Cur_TCNT1 = TCNT1 - Prev_TCNT1 ; // Capture current Timer1 value - if(Cur_TCNT1<1000) - chan=-1; // bad frame - else - if(Cur_TCNT1>4840) - { - chan=0; // start of frame - PPM_FLAG_on; // full frame present (even at startup since PPM_data has been initialized) - } + Cur_TCNT1 = TCNT1 - Prev_TCNT1 ; // Capture current Timer1 value + if(Cur_TCNT1<1000) + chan=-1; // bad frame else - if(chan!=-1) // need to wait for start of frame - { //servo values between 500us and 2420us will end up here - PPM_data[chan]= Cur_TCNT1>>1;; - if(chan++>=NUM_CHN) - chan=-1; // don't accept any new channels + if(Cur_TCNT1>4840) + { + chan=0; // start of frame + PPM_FLAG_on; // full frame present (even at startup since PPM_data has been initialized) } - Prev_TCNT1+=Cur_TCNT1; -} + else + if(chan!=-1) // need to wait for start of frame + { //servo values between 500us and 2420us will end up here + PPM_data[chan]= Cur_TCNT1>>1;; + if(chan++>=NUM_CHN) + chan=-1; // don't accept any new channels + } + Prev_TCNT1+=Cur_TCNT1; + } #endif //ENABLE_PPM //Serial RX #ifdef ENABLE_SERIAL -#ifdef XMEGA -ISR(USARTC0_RXC_vect) -#else -ISR(USART_RX_vect) -#endif -{ // RX interrupt - static uint8_t idx=0; #ifdef XMEGA - if((USARTC0.STATUS & 0x1C)==0) // Check frame error, data overrun and parity error + ISR(USARTC0_RXC_vect) #else - UCSR0B &= ~_BV(RXCIE0) ; // RX interrupt disable - sei() ; - if((UCSR0A&0x1C)==0) // Check frame error, data overrun and parity error + ISR(USART_RX_vect) #endif - { // received byte is ok to process - if(idx==0||discard_frame==1) - { // Let's try to sync at this point - idx=0;discard_frame=0; - RX_MISSED_BUFF_off; // If rx_buff was good it's not anymore... - rx_buff[0]=UDR0; - if((rx_buff[0]&0xFE)==0x54) // If 1st byte is 0x54 or 0x55 it looks ok + { // RX interrupt + static uint8_t idx=0; + #ifdef XMEGA + if((USARTC0.STATUS & 0x1C)==0) // Check frame error, data overrun and parity error + #else + UCSR0B &= ~_BV(RXCIE0) ; // RX interrupt disable + sei() ; + if((UCSR0A&0x1C)==0) // Check frame error, data overrun and parity error + #endif + { // received byte is ok to process + if(idx==0||discard_frame==1) + { // Let's try to sync at this point + idx=0;discard_frame=0; + RX_MISSED_BUFF_off; // If rx_buff was good it's not anymore... + rx_buff[0]=UDR0; + if((rx_buff[0]&0xFE)==0x54) // If 1st byte is 0x54 or 0x55 it looks ok + { + TX_RX_PAUSE_on; + tx_pause(); + OCR1B = TCNT1+(6500L) ; // Full message should be received within timer of 3250us + TIFR1 = OCF1B_bm ; // clear OCR1B match flag + SET_TIMSK1_OCIE1B ; // enable interrupt on compare B match + idx++; + } + } + else { - TX_RX_PAUSE_on; - tx_pause(); - OCR1B = TCNT1+(6500L) ; // Full message should be received within timer of 3250us - TIFR1 = OCF1B_bm ; // clear OCR1B match flag - SET_TIMSK1_OCIE1B ; // enable interrupt on compare B match - idx++; + rx_buff[idx++]=UDR0; // Store received byte + if(idx>=RXBUFFER_SIZE) + { // A full frame has been received + if(!IS_RX_DONOTUPDTAE_on) + { //Good frame received and main is not working on the buffer + memcpy((void*)rx_ok_buff,(const void*)rx_buff,RXBUFFER_SIZE);// Duplicate the buffer + RX_FLAG_on; // flag for main to process servo data + } + else + RX_MISSED_BUFF_on; // notify that rx_buff is good + discard_frame=1; // start again + } } } else { - rx_buff[idx++]=UDR0; // Store received byte - if(idx>=RXBUFFER_SIZE) - { // A full frame has been received - if(!IS_RX_DONOTUPDTAE_on) - { //Good frame received and main is not working on the buffer - memcpy((void*)rx_ok_buff,(const void*)rx_buff,RXBUFFER_SIZE);// Duplicate the buffer - RX_FLAG_on; // flag for main to process servo data - } - else - RX_MISSED_BUFF_on; // notify that rx_buff is good - discard_frame=1; // start again - } + idx=UDR0; // Dummy read + discard_frame=1; // Error encountered discard full frame... } + if(discard_frame==1) + { + CLR_TIMSK1_OCIE1B; // Disable interrupt on compare B match + TX_RX_PAUSE_off; + tx_resume(); + } + #ifndef XMEGA + cli() ; + UCSR0B |= _BV(RXCIE0) ; // RX interrupt enable + #endif } - else - { - idx=UDR0; // Dummy read - discard_frame=1; // Error encountered discard full frame... - } - if(discard_frame==1) - { - CLR_TIMSK1_OCIE1B; // Disable interrupt on compare B match - TX_RX_PAUSE_off; + + //Serial timer + #ifdef XMEGA + ISR(TCC1_CCB_vect) + #else + ISR(TIMER1_COMPB_vect, ISR_NOBLOCK ) + #endif + { // Timer1 compare B interrupt + discard_frame=1; + CLR_TIMSK1_OCIE1B; // Disable interrupt on compare B match tx_resume(); } - #ifndef XMEGA - cli() ; - UCSR0B |= _BV(RXCIE0) ; // RX interrupt enable - #endif -} - -//Serial timer -#ifdef XMEGA -ISR(TCC1_CCB_vect) -#else -ISR(TIMER1_COMPB_vect, ISR_NOBLOCK ) -#endif -{ // Timer1 compare B interrupt - discard_frame=1; - CLR_TIMSK1_OCIE1B; // Disable interrupt on compare B match - tx_resume(); -} #endif //ENABLE_SERIAL #ifndef XMEGA -// Random interrupt service routine called every time the WDT interrupt is triggered. -// It is only enabled at startup to generate a seed. -ISR(WDT_vect) -{ - static uint8_t gWDT_buffer_position=0; - #define gWDT_buffer_SIZE 32 - static uint8_t gWDT_buffer[gWDT_buffer_SIZE]; - gWDT_buffer[gWDT_buffer_position] = TCNT1L; // Record the Timer 1 low byte (only one needed) - gWDT_buffer_position++; // every time the WDT interrupt is triggered - if (gWDT_buffer_position >= gWDT_buffer_SIZE) + // Random interrupt service routine called every time the WDT interrupt is triggered. + // It is only enabled at startup to generate a seed. + ISR(WDT_vect) { - // The following code is an implementation of Jenkin's one at a time hash - for(uint8_t gWDT_loop_counter = 0; gWDT_loop_counter < gWDT_buffer_SIZE; ++gWDT_loop_counter) + static uint8_t gWDT_buffer_position=0; + #define gWDT_buffer_SIZE 32 + static uint8_t gWDT_buffer[gWDT_buffer_SIZE]; + gWDT_buffer[gWDT_buffer_position] = TCNT1L; // Record the Timer 1 low byte (only one needed) + gWDT_buffer_position++; // every time the WDT interrupt is triggered + if (gWDT_buffer_position >= gWDT_buffer_SIZE) { - gWDT_entropy += gWDT_buffer[gWDT_loop_counter]; - gWDT_entropy += (gWDT_entropy << 10); - gWDT_entropy ^= (gWDT_entropy >> 6); + // The following code is an implementation of Jenkin's one at a time hash + for(uint8_t gWDT_loop_counter = 0; gWDT_loop_counter < gWDT_buffer_SIZE; ++gWDT_loop_counter) + { + gWDT_entropy += gWDT_buffer[gWDT_loop_counter]; + gWDT_entropy += (gWDT_entropy << 10); + gWDT_entropy ^= (gWDT_entropy >> 6); + } + gWDT_entropy += (gWDT_entropy << 3); + gWDT_entropy ^= (gWDT_entropy >> 11); + gWDT_entropy += (gWDT_entropy << 15); + WDTCSR = 0; // Disable Watchdog interrupt } - gWDT_entropy += (gWDT_entropy << 3); - gWDT_entropy ^= (gWDT_entropy >> 11); - gWDT_entropy += (gWDT_entropy << 15); - WDTCSR = 0; // Disable Watchdog interrupt } -} #endif diff --git a/Multiprotocol/Telemetry.ino b/Multiprotocol/Telemetry.ino index 24ffc83..88fda00 100644 --- a/Multiprotocol/Telemetry.ino +++ b/Multiprotocol/Telemetry.ino @@ -588,11 +588,10 @@ void initTXSerial( uint8_t speed) { TIMSK0 = 0 ; // Stop all timer 0 interrupts #ifdef INVERT_SERIAL - TELEMETRY_SERIAL_TX_port &= ~_BV(TELEMETRY_SERIAL_TX_pin); + SERIAL_TX_off; #else - TELEMETRY_SERIAL_TX_port |= _BV(TELEMETRY_SERIAL_TX_pin); + SERIAL_TX_on; #endif - TELEMETRY_SERIAL_TX_ddr |= _BV(TELEMETRY_SERIAL_TX_pin) ; // TxD pin is an output UCSR0B &= ~(1<>= 7 ; // Top bit if ( SerialControl.speed == SPEED_100K ) { -#ifdef INVERT_SERIAL - byteLo |= 0x02 ; // Parity bit -#else - byteLo |= 0xFC ; // Stop bits -#endif - // calc parity + #ifdef INVERT_SERIAL + byteLo |= 0x02 ; // Parity bit + #else + byteLo |= 0xFC ; // Stop bits + #endif + // calc parity temp = byte ; temp >>= 4 ; temp = byte ^ temp ; @@ -639,21 +638,21 @@ void Serial_write( uint8_t byte ) temp1 <<= 1 ; temp ^= temp1 ; temp &= 0x02 ; -#ifdef INVERT_SERIAL - byteLo ^= temp ; -#else - byteLo |= temp ; -#endif + #ifdef INVERT_SERIAL + byteLo ^= temp ; + #else + byteLo |= temp ; + #endif } else { byteLo |= 0xFE ; // Stop bit } byte <<= 1 ; -#ifdef INVERT_SERIAL - byte |= 1 ; // Start bit -#endif - uint8_t next = (SerialControl.head + 2) & 0x3f ; + #ifdef INVERT_SERIAL + byte |= 1 ; // Start bit + #endif + uint8_t next = (SerialControl.head + 2) & 0x3f ; if ( next != SerialControl.tail ) { SerialControl.data[SerialControl.head] = byte ; @@ -671,11 +670,11 @@ void resumeBashSerial() { sei() ; // Start the transmission here -#ifdef INVERT_SERIAL - GPIOR2 = 0 ; -#else - GPIOR2 = 0x01 ; -#endif + #ifdef INVERT_SERIAL + GPIOR2 = 0 ; + #else + GPIOR2 = 0x01 ; + #endif if ( SerialControl.speed == SPEED_100K ) { GPIOR1 = 1 ; @@ -706,13 +705,9 @@ ISR(TIMER0_COMPA_vect) uint8_t byte ; byte = GPIOR0 ; if ( byte & 0x01 ) - { - TELEMETRY_SERIAL_TX_port |= _BV(TELEMETRY_SERIAL_TX_pin); - } + SERIAL_TX_on; else - { - TELEMETRY_SERIAL_TX_port &= ~_BV(TELEMETRY_SERIAL_TX_pin); - } + SERIAL_TX_off; byte /= 2 ; // Generates shorter code than byte >>= 1 GPIOR0 = byte ; if ( --GPIOR1 == 0 ) @@ -731,13 +726,9 @@ ISR(TIMER0_COMPB_vect) uint8_t byte ; byte = GPIOR2 ; if ( byte & 0x01 ) - { - TELEMETRY_SERIAL_TX_port |= _BV(TELEMETRY_SERIAL_TX_pin); - } + SERIAL_TX_on; else - { - TELEMETRY_SERIAL_TX_port &= ~_BV(TELEMETRY_SERIAL_TX_pin); - } + SERIAL_TX_off; byte /= 2 ; // Generates shorter code than byte >>= 1 GPIOR2 = byte ; if ( --GPIOR1 == 0 ) @@ -786,13 +777,9 @@ ISR(TIMER0_OVF_vect) byte = GPIOR2 ; } if ( byte & 0x01 ) - { - TELEMETRY_SERIAL_TX_port |= _BV(TELEMETRY_SERIAL_TX_pin); - } + SERIAL_TX_on; else - { - TELEMETRY_SERIAL_TX_port &= ~_BV(TELEMETRY_SERIAL_TX_pin); - } + SERIAL_TX_off; byte /= 2 ; // Generates shorter code than byte >>= 1 if ( GPIOR1 > 2 ) { diff --git a/Multiprotocol/_Config.h b/Multiprotocol/_Config.h index d56a781..5dd32a7 100644 --- a/Multiprotocol/_Config.h +++ b/Multiprotocol/_Config.h @@ -152,7 +152,7 @@ const PPM_Parameters PPM_prot[15]= { /* 3 */ {MODE_FRSKYD, 0 , 0 , P_HIGH , NO_AUTOBIND , 40 }, // option=fine freq tuning /* 4 */ {MODE_HISKY , Hisky , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 5 */ {MODE_V2X2 , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, -/* 6 */ {MODE_DSM , DSM2_22 , 0 , P_HIGH , NO_AUTOBIND , 2 }, // option=2=6 channels @ 22ms +/* 6 */ {MODE_DSM , DSM2_22 , 0 , P_HIGH , NO_AUTOBIND , 6 }, // option=6 channels @ 22ms /* 7 */ {MODE_DEVO , 0 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 8 */ {MODE_YD717 , YD717 , 0 , P_HIGH , NO_AUTOBIND , 0 }, /* 9 */ {MODE_KN , WLTOYS , 0 , P_HIGH , NO_AUTOBIND , 0 }, From e4986a6a472dfeeab58c1013d52192ebd4e20405 Mon Sep 17 00:00:00 2001 From: pascallanger Date: Mon, 19 Sep 2016 23:48:14 +0200 Subject: [PATCH 231/293] New documentation --- README.md | 452 ++++-------------- docs/Advanced_ATmega_Serial_Uploader.md | 70 +++ docs/Advanced_Bluetooth_Telemetry.md | 2 + docs/Advanced_Topics.md | 12 + docs/Bind_Timing.md | 10 + docs/Compiling.md | 206 ++++++++ docs/Compiling_STM32.md | 150 ++++++ docs/DIY Multiprotocol Module Overview.png | Bin 0 -> 89344 bytes docs/Documentation_To_Do_List.md | 28 ++ docs/Hardware.md | 19 + docs/Models.md | 19 + docs/Module_BG_4-in-1.md | 47 ++ docs/Module_Build_From_Scratch.md | 17 + docs/Module_Build_yourself_PCB.md | 91 ++++ docs/Module_OrangeRx.md | 3 + docs/PPM_Setup.md | 56 +++ docs/Protocol_Details.md | 447 +++++++++++++++++ docs/README-old.md | 399 ++++++++++++++++ docs/Transmitters.md | 59 +++ docs/Troubleshooting.md | 40 ++ docs/Tx-FlyskyTH9X.md | 37 ++ docs/Tx-NewTrasmitter.md | 43 ++ docs/Tx-Taranis.md | 49 ++ docs/images/4-in-1_Module_BG.jpeg | Bin 0 -> 12323 bytes docs/images/4-in-1_Module_BG.png | Bin 0 -> 532506 bytes .../4-in-1_Module_BG_SerialJumpers.jpeg | Bin 0 -> 328379 bytes docs/images/4-in-1_Module_PPM_Controls.jpg | Bin 0 -> 44565 bytes docs/images/Arduino.png | Bin 0 -> 325818 bytes docs/images/Board_PCB_STM32.jpeg | Bin 0 -> 11205 bytes .../DIY_Mulitprotocol_Module_Schematic.jpeg | Bin 0 -> 243994 bytes .../DIY_Multiprotocol_Module_Overview.png | Bin 0 -> 89344 bytes docs/images/MPTM_PCB_3.2d.png | Bin 0 -> 44685 bytes docs/images/MPTM_with_RF_modules.jpeg | Bin 0 -> 8602 bytes docs/images/Module_perfboard1.jpeg | Bin 0 -> 10422 bytes docs/images/Module_perfboard2.jpeg | Bin 0 -> 10338 bytes docs/images/Multi_4-in-1_RF_module.jpg | Bin 0 -> 137450 bytes docs/images/Multiprotocol_3.2.jpeg | Bin 0 -> 5755 bytes docs/images/OpenTx_Multi_Menu.jpg | Bin 0 -> 9296 bytes docs/images/OrangeRx_Module.jpg | Bin 0 -> 106885 bytes docs/images/V1_Serial_Enable.jpeg | Bin 0 -> 88089 bytes docs/images/V2_Serial_Enable.jpeg | Bin 0 -> 109506 bytes docs/images/er9X_Multi_Menu.jpg | Bin 0 -> 6627 bytes docs/images/test | 1 + 43 files changed, 1887 insertions(+), 370 deletions(-) create mode 100644 docs/Advanced_ATmega_Serial_Uploader.md create mode 100644 docs/Advanced_Bluetooth_Telemetry.md create mode 100644 docs/Advanced_Topics.md create mode 100644 docs/Bind_Timing.md create mode 100644 docs/Compiling.md create mode 100644 docs/Compiling_STM32.md create mode 100644 docs/DIY Multiprotocol Module Overview.png create mode 100644 docs/Documentation_To_Do_List.md create mode 100644 docs/Hardware.md create mode 100644 docs/Models.md create mode 100644 docs/Module_BG_4-in-1.md create mode 100644 docs/Module_Build_From_Scratch.md create mode 100644 docs/Module_Build_yourself_PCB.md create mode 100644 docs/Module_OrangeRx.md create mode 100644 docs/PPM_Setup.md create mode 100644 docs/Protocol_Details.md create mode 100644 docs/README-old.md create mode 100644 docs/Transmitters.md create mode 100644 docs/Troubleshooting.md create mode 100644 docs/Tx-FlyskyTH9X.md create mode 100644 docs/Tx-NewTrasmitter.md create mode 100644 docs/Tx-Taranis.md create mode 100644 docs/images/4-in-1_Module_BG.jpeg create mode 100644 docs/images/4-in-1_Module_BG.png create mode 100644 docs/images/4-in-1_Module_BG_SerialJumpers.jpeg create mode 100644 docs/images/4-in-1_Module_PPM_Controls.jpg create mode 100644 docs/images/Arduino.png create mode 100644 docs/images/Board_PCB_STM32.jpeg create mode 100644 docs/images/DIY_Mulitprotocol_Module_Schematic.jpeg create mode 100644 docs/images/DIY_Multiprotocol_Module_Overview.png create mode 100644 docs/images/MPTM_PCB_3.2d.png create mode 100644 docs/images/MPTM_with_RF_modules.jpeg create mode 100644 docs/images/Module_perfboard1.jpeg create mode 100644 docs/images/Module_perfboard2.jpeg create mode 100644 docs/images/Multi_4-in-1_RF_module.jpg create mode 100644 docs/images/Multiprotocol_3.2.jpeg create mode 100644 docs/images/OpenTx_Multi_Menu.jpg create mode 100644 docs/images/OrangeRx_Module.jpg create mode 100644 docs/images/V1_Serial_Enable.jpeg create mode 100644 docs/images/V2_Serial_Enable.jpeg create mode 100644 docs/images/er9X_Multi_Menu.jpg create mode 100644 docs/images/test diff --git a/README.md b/README.md index 81224bb..3220443 100644 --- a/README.md +++ b/README.md @@ -1,399 +1,111 @@ -# DIY-Multiprotocol-TX-Module +# Overview Multiprotocol is a 2.4GHz transmitter which enables any TX to control lot of different models available on the market. -The source code is partly based on the Deviation TX project, thanks to all the developpers for their great job on protocols. +The source code is partly based on the [Deviation TX project](http://www.deviationtx.com), thanks to all the developers for their great job on protocols. -[Forum link on RCGROUPS](http://www.rcgroups.com/forums/showthread.php?t=2165676) for additional information or requesting a new protocol integration. +## Quicklinks +* [Download latest releases of the firmware](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases) +* [Forum on rcroups](http://www.rcgroups.com/forums/showthread.php?t=2165676) +* [Available Protocols list](docs/Protocol_Details.md) +* [The old documentation](docs/README-old.md) +* [Documentation to-do list](docs/Documentation_To_Do_List.md) -![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7952733-114-thumb-P4100002.JPG?d=1433910155) ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7952734-189-thumb-P4100003.JPG?d=1433910159) +## Outline of the documentation +1. Introduction (this page) +1. [Available protocols](docs/Protocol_Details.md) +1. [Compatible Transmitters](docs/Transmitters.md) +1. [Module Hardware options](docs/Hardware.md) +1. [Compiling and programming the module (ATmega328)](docs/Compiling.md) and [Compiling STM32](Compiling_STM32.md). +1. Transmitter Setup + - [Taranis](docs/Tx-Taranis.md) + - [FlySky TH9X, Turnigy 9X/R](docs/Tx-FlyskyTH9X.md) +1. [How to for popular models](docs/Models.md) +1. [Troubleshooting](docs/Troubleshooting.md) +2. [Advanced Topics (not for the fainthearted!)](docs/Advanced_Topics.md) -**To download the latest compiled version (hex file), click on [Release](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases) on the top menu.** +## Introduction +A functioning DIY Multiprotocol module consists of (see image below): +![Screenshot](docs/images/DIY_Multiprotocol_Module_Overview.png) -##Contents +1. A host RC transmitter -[Compatible TX](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#compatible-tx) +1. DIY Multiprotocol module that connects to a host transmitter. This module is typically comprised of -[Protocols](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#protocols) + * A microprocessor (currently ATMega328P) that interfaces with the Tx, controls the module functions and forwards the RC commands to the RF hardware -[Hardware](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#hardware) + * One or more (but at least one) RF modules that provide the capability to communicate with RC receivers. To communicate with the receiver the RF module in the Tx must match with the RF module type in the receiver. The four most common 2.4GHz RF chips on the market are supported TI CC2500, Nordic NRF24L01, Cypress CYRF6936, and the Amiccom A7105 -[Compilation and programmation](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#compilation-and-programmation) + * DIY Multiprotocol firmware loaded on to the microprocessor. At a high level, this firmware performs a few different functions: + * It interfaces with signals from the host Tx and decodes these for transmission to the model, it manages the activation of the correct hardware RF module for each protocol + * It implements the unique communication protocols for each receiver/model and manages the all-important binding process with a receiver/model + * In the case of some protocols (for example DSMX and FrSky) it receives and decodes the telemetry information and makes this available to the receiver. +1. The physical 2.4GHz antenna (or in some cases multiple antennas) for the modules -[Troubleshooting](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#troubleshooting) -##Compatible TX -###Using standard PPM output (trainer port) -The multiprotocol TX module can be used on any TX with a trainer port. +In constructing a functioning module there are important choices to be made and tradeoffs to be aware of. The most important are: -Channels order is AETR by default but can be changed in the _Config.h. +##**Choice 1:** Which module hardware option -The protocol selection is done via a dip switch, rotary dip switch or scsi ID selector. +There are currently four generic paths to construct your own DIY Multiprotocol module. These are outlined in detail on the [hardware] page. Here they are in order of increasing difficulty: + * You can purchase a ready-made DIY Multiprotocol module from Banggood + * You can purchase a DIY Multiprotocol PCB from [OSHPark] and then buy and solder on your own RF modules + * You can use a Orange Rx transmitter module available from Hobyking + * You can build the module from scratch using an Arduino Pro Mini and a perf board base. +The last option is where it all started and how the pioneers in this project made their boards. However, due to the growing interest in “one module to rule them all” you now have options to purchase a ready-made board (with old firmware that you will need to upgrade). -![Screenshot](http://media.digikey.com/photos/CTS%20Photos/206-4,%20206-4ST_sml.jpg) -![Screenshot](http://media.digikey.com/photos/Grayhill%20Photos/94HBB16T_sml.jpg) -![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8637216-7-thumb-SCSI%20ID%20selector.jpg?d=1453737244) +For more information on these options see the [hardware](docs/Hardware.md) page -You can access to up to 15 different protocols and associated settings. - -Settings per selection are located in _Config.h: - - Protocol and type: many main protocols have variants - - RX Num: number your different RXs and make sure only one model will react to the commands - - Power: High or low, enables to lower the power setting of your TX (indoor for example). - - Option: -127..+127 allowing to set specific protocol options. Like for Hubsan to set the video frequency. - - Autobind: Yes or No. At the model selection (or power applied to the TX) a bind sequence will be initiated - -###Using a serial output -The multiprotocol TX module takes full advantage of being used on a Turnigy 9X, 9XR, 9XR Pro, Taranis, 9Xtreme, AR9X, ... running [er9x](http://openrcforums.com/forum/viewtopic.php?f=5&t=4598) or [ersky9X](http://openrcforums.com/forum/viewtopic.php?f=7&t=4676). An OpenTX version for Taranis is available [here](http://plaisthos.de/opentx/). +##**Choice 2:** Which RF modules to include -This enables full integration using the radio GUI to setup models with all the available protocols options. +This depends on your specific needs. However, recent the availability of the 4-in-1 RF modules from Banggood for less than $35 makes it easy to “have it all”. Most manufacturers of RC systems (Spektrum, FrSky, FlySky) and toys (Syma, Hubsan, Horizon Hobby, etc.) use one of these four RF chips to manage the RF link between the transmitter and the reciever/model. Here is an incomplete list of the RF modules and some of the most popular toys that use them. For the complete list see the [Protocol Details](docs/Protocol_Details.md) page. -![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8520065-194-thumb-IMG_20151217_002215%20%28Medium%29.jpg?d=1450308588) +Manufacturer|RF Chip|Example Protocols +:-----------|-------|:------- +Cyprus Semiconductor| CYRF6936|DSM/DSMX +||Walkera Devo +||J6Pro +Texas Instruments|CC2500|FrSky +||Futaba SFHSS +Amiccom|A7105|FlySky +||Turnigy (most) +||Hubsan +Nordic Semiconductor|NRF24L01|HiSky +||Syma +||ASSAN +||and most other Chinese models -Options are: - - Protocol and type: many main protocols have variants - - RX Num: number your different RXs and make sure only one model will react to the commands - - Power: High or low, enables to lower the power setting of your TX (indoor for example). - - Option: -127..+127 allowing to set specific protocol options. Like for Hubsan to set the video frequency. - - Bind: bind a RX/model - - Autobind: Yes or No. At the model selection (or power applied to the TX) a bind sequence will be initiated - - Range: test range by setting the transmission power to the lowest value +For example, if you have no interest in binding your Tx to an model with and FrSky or Futaba SFHSS receiver you do not need to include the CC2500 RF module in your system. -Notes: - - Using this solution does not need any modification of the TX since it uses the TX module slot PPM pin for serial transfer. - - There are 2 versions of serial protocol either 8 or 16 channels. 16 channels is the latest and only available version going forward. Make sure to use the right version based on your version of er9x/ersky9x. - - Channels order is AETR by default but can be changed in _Config.h. +##**Choice 3:** Which protocols to upload the module -###Telemetry +Of course there always a catch. There is a 32K memory limit on the ATmega328 processor. Due to the amazing work done by devs on this project, the memory required by all the possible protocols exceeds the limit. This means that you will need to make a choice of which protocols you will compile into your firmware. Fortunately, the process of selecting and compiling is not too difficult and it is fully documented on the [Compiling and Programming](docs/Compiling.md) page. +Also, the lead dev Pascal Langer (rcgroups:hpnuts) makes this process even easier for many users by making compiled binaries available for three popular combinations of RF modules. These are always “fresh” (based on the latest stable firmware) and available on the [Releases](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases) page. -There are 4 protocols supporting telemetry: Hubsan, DSM, FrSkyD and FrSkyX. +##**Choice 4:** Choosing the type of interface with your Tx (PPM or Serial) -Hubsan displays the battery voltage and TX RSSI. +The DIY Mulitprotocol module supports industry standard PPM interface that works with all transmitters with either a module bay, and/or a trainer port. Even the older 72MHz FM radios support this standard. -DSM displays TX RSSI and full telemetry. +If you are the owner of a transmitter that supports the er9X/erSky9X or OpenTX firmwares (Frsky Taranis running erSky9x or OpenTx, or any of the FlySky/Turnigy family of Txs running ER9X, ERSky9x or OpenTx) you have the additional option to use a serial protocol to communicate between your Tx and the DIY Mulitprotocol module. (Owners of Walkera Devo transmitters should look at the [Deviation Tx](http://www.deviationtx.com) project for how to achieve the same end goal). This serial protocol does not require any hardware modifications, but will require updating the firmware on your radio. For those willing to do this, there are some nice advantages: + * The model and protocol selection and binding is done from the Model Settings menu on the Tx + * For telemetry capable receivers, the telemetry integration is done seamlessly with the Tx firmware. +See the [Setting up your Tx](docs/TransmitterSetup.md) page for more details. -FrSkyD displays full telemetry (A0, A1, RX RSSI, TX RSSI and Hub). +#How to get started? +1. Browse the [Protocols] page to see which protocols you would like on your module +1. Go to the [Hardware Options] page to decide what Tx module you need and which RF modules you plan to integrate +1. Once you have your module, you should go to [Compiling and Programming](docs/Compiling.md) page to download, compile and program the DIY Multiprotocol module +1. Finally, you should visit the [Setting up your Tx](docs/TransmitterSetup.md) page to configure the last few settings before you can fly to your heart’s content!!!!! -FrSkyX displays full telemetry (A1, A2, RX RSSI, TX RSSI and Hub). +# Troubleshooting +Visit the [Troubleshooting](docs/Troubleshooting.md) page. Please bear in mind that the DIY Multiprotocol module is a complex system of hardware and software and it make take some patience to get it up and running. Also remember that the developers of the system are actual users of the system. This means that at any moment in time the system is working perfectly for them. A corollary to this is that if you are struggling there are likely two scenarios. First, that the problem is with your hardware or with your configuration, second, and much more unlikely but not impossible scenario, is that you are struggling with a new undiscovered bug. (The author of this documentation speaks from experience ;-) Please check the RC Groups forum and search for keywords relating to your problem before posting a reply. When you do post a reply please so humbly and respectfully – you will find many helpful people there. In your reply please include as much relevant information as possible and attach compilation output and _Config.h files as text attachments to keep the forum clean. +# A final word +A very big thanks to all the people who have shared their time so graciously to create this great project. If you come across them on RC Groups, please be kind and show appreciation. In no particular order: +* Pascal Langer (rcgroups: hpnuts) +* Mike Blandford (rcgroups: Mike Blandford) +* (rcgroups: midelic) +* victhz – from Deviation-tx +* Enter the other Deviation people here (###) -### If used in PPM mode - -Telemetry is available as a serial 9600 8 n 1 output on the TX pin of the Atmega328p using the FrSky hub format for Hubsan, FrSkyD, FrSkyX and DSM format for DSM2/X. - -You can connect it to your TX if it is telemetry enabled or use a bluetooth adapter (HC05/HC06) along with an app on your phone/tablet ([app example](https://play.google.com/store/apps/details?id=biz.onomato.frskydash&hl=fr)) to display telemetry information and setup alerts. - -### If used in Serial mode -Telemetry is built in for er9x and ersky9x TXs. - -To enable telemetry on a Turnigy 9X or 9XR you need to modify your TX following one of the Frsky mod like this [one](http://blog.oscarliang.net/turnigy-9x-advance-mod/). - -Note: DSM telemetry is not available on er9x due to a lack of flash space. - -Enabling telemetry on a 9XR PRO and may be other TXs does not require any hardware modifications. The additional required serial pin is already available on the TX back module pins. - -Once the TX is telemetry enabled, it just needs to be configured on the model (see er9x/ersky9x documentation). - -##Protocols - -###TX ID -The multiprotocol TX module is using a 32bits ID generated randomly at first power up. This global ID is used by nearly all protocols. -There are little chances to get a duplicated ID. - -For DSM2/X and Devo the CYRF6936 unique manufacturer ID is used. - -It's possible to generate a new ID using bind button on the Hubsan protocol during power up. - -###Bind -To bind a model in PPM Mode press the physical bind button, apply power and then release. - -In Serial Mode you have 2 options: -- use the GUI, access the model protocol page and long press on Bind. This operation can be done at anytime. -- press the physical bind button, apply power and then release. It will request a bind of the first loaded model protocol. - -Notes: -- the physical bind button is only effective at power up. Pressing the button later has no effects. -- a bind in progress is indicated by the LED fast blinking. Make sure to bind during this period. - -###Protocol selection - -####Using the dial for PPM input -PPM is only allowing access to a subset of existing protocols. -The protocols, subprotocols and all other settings can be personalized by modifying the **_Config.h** file. - -The default association dial position / protocol in every release is listed below. - -Dial|Protocol|Sub_protocol|RX Num|Power|Auto Bind|Option|RF Module -----|--------|------------|------|-----|---------|------|--------- -0|Select serial|||||| -1|FLYSKY|Flysky|0|High|No|0|A7105 -2|HUBSAN|-|0|High|No|0|A7105 -3|FRSKYD|-|0|High|No|40|CC2500 -4|HISKY|Hisky|0|High|No|0|NRF24L01 -5|V2X2|-|0|High|No|0|NRF24L01 -6|DSM|DSM2|0|High|No|6|CYRF6936 -7|DEVO|-|0|High|No|0|CYRF6936 -8|YD717|YD717|0|High|No|0|NRF24L01 -9|KN|WLTOYS|0|High|No|0|NRF24L01 -10|SYMAX|SYMAX|0|High|No|0|NRF24L01 -11|SLT|-|0|High|No|0|NRF24L01 -12|CX10|BLUE|0|High|No|0|NRF24L01 -13|CG023|CG023|0|High|No|0|NRF24L01 -14|BAYANG|-|0|High|No|0|NRF24L01 -15|SYMAX|SYMAX5C|0|High|No|0|NRF24L01 - -Note: -- The dial selection must be done before the power is applied. - -####Using serial input with er9x/ersky9x -Serial is allowing access to all existing protocols & sub_protocols listed below. - -#####A7105 RF module -Protocol|Sub_protocol ---------|------------ -Flysky| - |Flysky - |V9x9 - |V6x6 - |V912 -Hubsan| - -#####CC2500 RF module -Protocol|Sub_protocol ---------|------------ -FrSkyV| -FrSkyD| -FrSkyX| - |CH_16 - |CH_8 -SFHSS| - -#####CYRF6936 RF module -Protocol|Sub_protocol ---------|------------ -DSM| - |DSM2 - |DSMX -Devo| -J6Pro| - -#####NRF24L01 RF module -Protocol|Sub_protocol ---------|------------ -Hisky| - |Hisky - |HK310 -V2x2| -YD717| - |YD717 - |SKYWLKR - |SYMAX4 - |XINXUN - |NIHUI -KN| - |WLTOYS - |FEILUN -SymaX| - |SYMAX - |SYMAX5C -SLT| -CX10| - |GREEN - |BLUE - |DM007 - |Q282 - |JC3015_1 - |JC3015_2 - |MK33041 - |Q242 -CG023| - |CG023 - |YD829 - |H8_3D -Bayang| -ESky| -MT99XX| - |MT - |H7 - |YZ - |LS -MJXQ| - |WLH08 - |X600 - |X800 - |H26D - |E010 -Shenqi| -FY326| -FQ777| -ASSAN| -HONTAI| - |HONTAI - |JJRCX1 - |X5C1 - -Note: -- The dial should be set to 0 for serial. Which means all protocol selection pins should be left unconnected. - -###Protocols details -**Check the [Protocols_Details.md](./Protocols_Details.md) file for a detailed description of every protocols with channels assignements.** - -##Hardware - -###RF modules -Up to 4 RF modules can be installed: -- [A7105](http://www.banggood.com/XL7105-D03-A7105-Modification-Module-Support-Deviation-Galee-Flysky-p-922603.html) for Flysky, Hubsan -- [CC2500](http://www.banggood.com/CC2500-PA-LNA-Romote-Wireless-Module-CC2500-SI4432-NRF24L01-p-922595.html) for FrSkyV, FrSkyD, FrSkyX and SFHSS -- [CYRF6936](http://www.ehirobo.com/walkera-wk-devo-s-mod-devo-8-or-12-to-devo-8s-or-12s-upgrade-module.html) for DSM, DEVO, J6Pro -- [NRF24L01](http://www.banggood.com/2_4G-NRF24L01-PA-LNA-Wireless-Module-1632mm-Without-Antenna-p-922601.html) for Hisky, V2x2, CX-10, SYMAX and plenty other protocols - -RF modules can be installed for protocols need only. Example: if you only need the Hubsan protocol then install only a A7105 on your board. - -You also need some [antennas](http://www.banggood.com/2_4GHz-3dBi-RP-SMA-Connector-Booster-Wireless-Antenna-Modem-Router-p-979407.html) and [cables](http://www.banggood.com/10cm-PCI-UFL-IPX-to-RPSMA-Female-Jack-Pigtail-Cable-p-924933.html). - -###Board -The main program is running on an ATMEGA328p running @16MHz and 3.3V. -An [Arduino pro mini 16Mhz/5V](http://www.banggood.com/Wholesale-New-Ver-Pro-Mini-ATMEGA328-328p-5V-16MHz-Arduino-Compatible-Nano-Size-p-68534.html) powered at 3.3V (yes it works) can be used to build your own Multimodule. An Arduino Mini based on Atmega328p can also be used. - -####Using stripboard: - -![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t8214655-87-thumb-uploadfromtaptalk1405598143749.jpg?d=1441459923) -![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t8214656-102-thumb-uploadfromtaptalk1405598152484.jpg?d=1441459924) - -####Using a [home made PCB](http://www.rcgroups.com/forums/showpost.php?p=32645328&postcount=1621): - -![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8226720-197-thumb-IMG_20150715_230603155.jpg?d=1441816457) -![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8226719-72-thumb-IMG_20150715_230024065.jpg?d=1441816456) - -####Build your own board using [SMD components](http://www.rcgroups.com/forums/showpost.php?p=31064232&postcount=1020) and an [associated PCB v2.3c](https://oshpark.com/shared_projects/MaGYDg0y): - -![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7566755-3-thumb-i.png?d=1423810885) -![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7952726-108-thumb-image-62c29cf2.jpg?d=1433909893) -![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7952733-114-thumb-P4100002.JPG?d=1433910155) ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7952734-189-thumb-P4100003.JPG?d=1433910159) - -If you build this PCB v2.3c and want to enable serial mode for er9x/ersky9x, you have to do [this mod](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8667856-242-multi.jpg). - -**[New PCB v2.3d!](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/tree/master/PCB%20v2.3d) available** - -Repository includes Kicad files of schematic and pcb. This is a variant of the Multipro V2.3c circuit design. It is basicly the same as the 2.3c board as far as component placement goes. What's changed is the added resistors for the serial protocol and also -the addition of solder jumpers on the bottom of the board for the various options to connect the TX, RX, and PPM -lines through them. - -![Screenshot](https://644db4de3505c40a0444-327723bce298e3ff5813fb42baeefbaa.ssl.cf1.rackcdn.com/b637193364a5e228dc8ab6ad90c0ca3c.png) -![Screenshot](https://644db4de3505c40a0444-327723bce298e3ff5813fb42baeefbaa.ssl.cf1.rackcdn.com/97b87a89b75785d70b354e5b033f5209.png) - -[OSH Park link](https://oshpark.com/shared_projects/Ztus1ah8) if you want to order. - -####Buy a ready to use and complete Multi module -![Screenshot](http://img.banggood.com/thumb/view/oaupload/banggood/images/1D/EB/19bb6434-4616-411e-b8fa-a4c21d9dca24.jpg) - -This module can be purchased [here](http://www.banggood.com/2_4G-CC2500-A7105-Flysky-Frsky-Devo-DSM2-Multiprotocol-TX-Module-With-Antenna-p-1048377.html). All the 4 RF modules are already implemented A7105, NRF24L01, CC2500 and CYRF6936. The board is also equiped with an antenna switcher which means only one antenna for all. - -**It is highly recommended to update the firmware** of this board as it is distributed with a really old and bugged one. For this you have to solder a 6 pin header (top left) and use an USBASP like explained [below](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#upload-the-code-using-isp-in-system-programming). - -If you want to enable serial mode for er9x/ersky9x/Taranis/... and depending on your board revision, you have to do one of these modifications: -- 1st revision, add 2 resistors as shown here: ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8895038-170-4in1%20module.jpg) -- 2nd revision, solder pads together as shown: - - - -Note: if you have the 1st board revision (check pictures above), sometime bind occures at power up even without pressing the bind button or not having an autobind protocol. To solve this issue, replacing the BIND led resistor (on the board back) of 1.2K by a 4.7K. - -###Schematic -![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8443844-119-multiprotocol_diagram_rotary_serial_2.jpg) - -Notes: -- Attention: All modules are 3.3V only, never power them with 5V. -- For serial, the dial switch is not needed and the bind button optionnal - -###Radio integration -If you build your own version of the board you can 3D print this case (details [here](http://www.rcgroups.com/forums/showpost.php?p=33294140&postcount=2034)): - -![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8462144-54-thumb-Multi_case_9XR.jpg?d=1448575289) -![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8462145-106-thumb-Multi_case_v1.jpg?d=1448575293) - -If you have the Banggood ready to use board you can 3D print this case (details [here](http://www.rcgroups.com/forums/showpost.php?p=35349049&postcount=3)): - - - - - -##Compilation and programmation - -###Toolchain -Multiprotocol source can be compiled using the Arduino IDE. - -The currently supported Arduino version is [1.6.10](https://www.arduino.cc/download_handler.php?f=/arduino-1.6.10-windows.exe). - -Download the [zip file](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/archive/master.zip) of this repository, unzip it in a folder, navigate to the Multiprotocol directory and then click on Multiprotocol.ino. The Arduino environment will appear and the Multiprotocol project will be loaded. - -**[_Config.h file](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Multiprotocol/_Config.h) must be modified** to select which protocols will be available, change protocols/sub_protocols/settings associated with dial for PPM input, different TX channel orders and timing, Telemetry or not, ... -This is mandatory since all available protocols will not fit in the ATmega328. You need to pick and choose what you want. - -Notes: -- Make sure to select "Arduino Pro or Pro Mini, ATmega328 (5V,16MHz)" before compiling. -- Compilation of the code posted here works. So if it doesn't for you this is a problem with your setup, please double check everything before asking. -- If you want to reduce the code size even further, you can modify the file platform.txt located in "C:\Program Files (x86)\Arduino\hardware\arduino\avr". Set the line "compiler.c.elf.extra_flags=" to "compiler.c.elf.extra_flags=-Wl,--relax". - -###Upload the code using ISP (In System Programming) -It is recommended to use an external programmer like [USBASP](http://www.banggood.com/USBASP-USBISP-3_3-5V-AVR-Downloader-Programmer-With-ATMEGA8-ATMEGA128-p-934425.html) to upload the code in the Atmega328. The programmer should be set to 3.3V or nothing to not supply any over voltage to the multimodule and avoid any damages. - -The dial must be set to 0 before flashing! - -From the Arduino environment, you can use this shortcut to compile and upload to the module: Skecth->Upload Using Programmer (Ctrl+Maj+U) - -To flash the latest provided hex file under [Release](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases), you can use a tool like [AVR Burn-O-Mat](http://avr8-burn-o-mat.aaabbb.de/), set the microcontroller to m328p and flash it. - -###Upload the code using FTDI (USB serial to TTL) -Use this method only for Arduino Pro Mini boards with bootloader. - -Use an external FTDI adapter like [this one](http://www.banggood.com/FT232RL-FTDI-USB-To-TTL-Serial-Converter-Adapter-Module-For-Arduino-p-917226.html). - -The programmer should be set to 3.3V or nothing to not supply any over voltage to the multimodule and avoid any damages. - -From the Arduino environment, you can use Upload button which will compile and upload to the module: Skecth->Upload (Ctrl+U) - -To upload the latest provided hex file under [Release](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases), you can use a tool like [XLoader](http://russemotto.com/xloader/), set the microcontroller to Atmega328 and upload it. - -###Set fuses -Use a tool like [AVR Burn-O-Mat](http://avr8-burn-o-mat.aaabbb.de/) to set the fuses of the Atmega328 to: -- Extended Fuse 0x05 (or 0xFD which is the same) -- High Fuse 0xD2 -- Low Fuse 0xFF - -This will make sure your ATMEGA328 is well configured and the global TX ID is not erased at each updates. - -##Troubleshooting - -###LED status -- off: program not running or a protocol selected with the associated module not installed. -- flash(on=0.1s,off=1s): invalid protocol selected (excluded from compilation or invalid protocol number) -- slow blink(on=0.5s,off=0.5s): serial has been selected but no valid signal has been seen on the RX pin. -- fast blink(on=0.1s,off=0.1s): bind in progress. -- on: normal operation. - -###Protocol selection -####Input Mode - PPM -- The protocol/mode selection must be done before the power is applied. -- Connect 1 to 4 of the selection protocol pins to GND. - -####Input Mode - Serial -- Make sure you have done the mods to the v2.3c PCB by adding the 2.2k and 470 ohm resistors as indicated in the [Board section] (https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#board). -- Leave all 4 selection pins unconnected. - -###Bind -Make sure to follow this procedure: press the bind button, apply power and then release it after 1sec. The LED should be blinking fast indicating a bind status and then fixed on when the bind period is over. It's normal that the LED turns off when you press the bind button, this behavior is not controlled by the Atmega328. -For serial, the preffered method is to bind via the GUI protocol page. - -If your module is always/sometime binding at power up without pressing the button: - - Arduino Pro Mini with an external status LED: to work around this issue connect a 10K resistor between D13 and 3.3V. - - 4in1 module V1 (check 4in1 pictures): to solve this issue, replacing the BIND led resistor (on the board back) of 1.2K by a 4.7K. - -###Report issues -You can report your problem using the [GitHub issue](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/issues) system or go to the [Main thread on RCGROUPS](http://www.rcgroups.com/forums/showthread.php?t=2165676) to ask your question. -Please provide the following information: -- Multiprotocol code version -- TX type -- Using PPM or Serial, if using er9x or ersky9x the version in use -- Different led status (multimodule and model) -- Explanation of the behavior and reproduction steps +Your help would be greatly appreciated. If protocol reverse-engineering and dev is not your thing then any help with testing and contributing to the documentation would be amazing. Given the number of different Tx/module hardware/RF module/protocol/model combinations the process of testing and documenting is a major bottleneck for the developers. Anything you can do to help will free them up to do even greater things. Check out this quick guide {How to help with documentation} for how you can submit changes to the documentation. diff --git a/docs/Advanced_ATmega_Serial_Uploader.md b/docs/Advanced_ATmega_Serial_Uploader.md new file mode 100644 index 0000000..21cb4b8 --- /dev/null +++ b/docs/Advanced_ATmega_Serial_Uploader.md @@ -0,0 +1,70 @@ +#ATmega Serial Uploader + +Mike Blandford adapted the optiboot bootloader for the 4-in-1 module to allow flashing of the module using a standard Arduino USB to serial adapter or FTDI adapter. No need to open the module case. Once set up is very easy to use: + +1. plug the serial wires into the module connector, +2. To activate the bootloader, set the rotary switch to 0 +3. hold the bind button down for 0.5s while connecting the USB end of the serial cable into the computer +4. Press upload on the Arduino IDE or issue an AVRdude command from the terminal. + +It uses a baudrate of 57600, so is the same as a Pro Mini. + +The Serial / FTDI connections on the Tx module are as follows: +- Top Pin: Programmer Tx +- 2nd Pin: +- 3rd Pin: Programmer V+ +- 4th Pin: Programmer Gnd +- 5th Pin: Programmer Rx + +The bootloader starts up, waits half a second, then checks the rotary switch and the bind button. If they aren't as described above, then the normal application runs. + +While the bootloader is running, if it detects a communication problem, it configures the watchdog to reset in 16mS, then waits forever. 16mS later the board should reset, and then restart the bootloader, dropping back to the application half a second later. + +This bootloader is for reading and writing the flash only, the EEPROM is not supported, neither is reading/writing the fuses, but it only uses 512 bytes of flash. + +##Install the bootloader +To get the bootloader onto the ATmega you need to connect an flashing tool (like USBasp) to the 6-pin ISP connector on the board. +Simply flash the .hex file to get the bootloader on the chip, and change the high fuse at the same time. + +The bootloader only uses 512 bytes of flash and is avaialble for download [here](http://www.rcgroups.com/forums/showatt.php?attachmentid=9291360&d=1472324155). The orginal rcgroups post is [here](http://www.rcgroups.com/forums/showpost.php?p=35584619&postcount=4867). + +The HIGH fuse needs to be set to 0xD6. (See the section below on Setting the Fuses with AVRdude.) + +## Setting fuses with AVRdude +###Determining the location of the avrdude program +The Arduino IDE is used to upload firmware and set fuses on the ATMega microprocessor. + +You can install avrdude on your computer, but it is already contained in the Arduino IDE bundle and we suggest that you use the Arduino-bundled version. +1. Unplug any programmer that may be connected to the computer +1. In the Arduino IDE click on Sketch -> Upload Using Programmer +1. After a series of compiling messages you will see an error that a programmer is not found. Scroll up and find the programming command that caused the errors (usually the last white line before the red errors) and copy it into TextEdit or Notepad. +1. This is your programming command and it should look something like this: + +**Mac:** + + +> ``` +> /Applications/Arduino.app/Contents/Java/hardware/tools /avr/bin/avrdude -C/Applications/Arduino.app/Contents/ Java/hardware/tools/avr/etc/avrdude.conf -patmega328p -cusbasp -Pusb -Uflash:w:{this part will be unique to your system} /Multiprotocol.ino.hex:i +> ``` + +**PC:** + + +> ``` +> C:\Program Files (x86)\Arduino\Contents\Java\hardware\tools\ avr\bin\avrdude -CC:\Program Files (x86)\Arduino\Contents\Java\ hardware\tools\avr\etc\avrdude.conf -patmega328p -cusbasp -Pusb -Uflash:w:{this part will be unique on your system}\ Multiprotocol.ino.hex:i +> ``` + + +Select all the text up to the ```-Uflash ``` command, copy it and paste it into a new line and add a “-v” (without the "") at the end of the line. + + This is your “verify” command and it should look something like this: + +> ``` +> /Applications/Arduino.app/Contents/Java/hardware/tools/avr/bin/avrdude -C/Applications/Arduino.app/Contents/Java/hardware/ tools/avr/etc/avrdude.conf -patmega328p -cusbasp -Pusb -v +> ``` + + +We will be using these two commands to program the module. + +1. Verify that the connection is working by pasting the Verify line into a terminal. You should see output that includes the fuse settings. +2. 1. To program the High Fuse copy the “verify” command and paste it into the shell add the following text to the end of the line ```-U hfuse:w:0xD6:m ``` . Press Enter. diff --git a/docs/Advanced_Bluetooth_Telemetry.md b/docs/Advanced_Bluetooth_Telemetry.md new file mode 100644 index 0000000..225171a --- /dev/null +++ b/docs/Advanced_Bluetooth_Telemetry.md @@ -0,0 +1,2 @@ +#Bluetooth Telemetry +{The documentation goes here} diff --git a/docs/Advanced_Topics.md b/docs/Advanced_Topics.md new file mode 100644 index 0000000..de1e767 --- /dev/null +++ b/docs/Advanced_Topics.md @@ -0,0 +1,12 @@ +#Advanced Topics {This page is currently a proof of concept} +Warning: the topics on this page are not for the fainthearted. It is strongly recommended that you have some experience in getting up and runnning with your module before you dive in there. On the other hand what is described on this page are some very useful options that could greatly increase the value and the enjoyment of your Multiprotocol module. +#Serial uploader that works through the transmitter pins +This document describes how you can set up your ATmega-based Mulitprotocol module to allow you to update the firmware by connecting a USB to TTL serial (like a FTDI) adapter to the module's transmitter interface pins. It is great if you exclusively use the Serial interface with your transmitter because the Bind button is used as "bootloader" button. It requires a small custom bootloader to be uploaded and a simple interface cable to be soldered up. See the [Advanced ATmega Serial Uploader](Advanced_ATmega_Serial_Uploader.md) page for more details. +Created and supported by: Mike Blandford + +RCGroups page: {insert page here} +#Bluetooth telemetry board for telemetry in PPM mode +This document describes a simple bluetooth module to stream telemetry information to a mobile device like an Android smartphone or tablet. This is very useful with modules used in the PPM mode with transmitters that do not support telemetry. See the [Advanced Bluetooth Telemetry](Advanced_Bluetooth_Telemetry.md) page for more details. +Created and supported by: Miledic + +RCGroups page: {insert page here} diff --git a/docs/Bind_Timing.md b/docs/Bind_Timing.md new file mode 100644 index 0000000..64cb257 --- /dev/null +++ b/docs/Bind_Timing.md @@ -0,0 +1,10 @@ +#Getting your Bind timing right. +On many consumer models it it important for the Tx to send a bind signal in a narrow window once the model has powered up. + +If the bind signal is not recieved during this window, the bind sequence times out. Try this: + + 1. power the transmitter up with the throttle stick high. This will trigger the warning window on the transmitter and put a hold on the transmitter bind process. + 1. turn on the model + 1. while holding the bind button (if in PPM mode), at the right moment bring the throttle down to instantly bring the transmitter into bind mode. + +If you are using Serial Mode it is best to check the Autobind box in the Model Settings menu. This will automatically initiate a bind sequence as soon as the Tx module powers up (Note: the Tx module only powers up when the transmitter passes the Switch/Throttle Warning page). diff --git a/docs/Compiling.md b/docs/Compiling.md new file mode 100644 index 0000000..02def25 --- /dev/null +++ b/docs/Compiling.md @@ -0,0 +1,206 @@ +# Compiling and Programming (ATmega 328P) + +**If you are Compling for the STM32 version of the Multiprotocol Module please go to the dedicated [Compiling and Programming STM32](Compiling_STM32.md) page.** + +**This page describes the basic Compiling and Programming process. There are some other more advanced processes that have some superior features described under the [Advanced Topics](Advanced_Topics.md) page.** Some options are: + - Using an FTDI cable to upload firmware over the module - Tx pins + + +Multiprotocol source can be compiled using the Arduino IDE. + +##Install the Arduino IDE and the Multiprotocol project +1. Download the Arduino IDE. The currently supported Arduino version is 1.6.10. available for [Windows]( https://www.arduino.cc/download_handler.php?f=/arduino-1.6.10-windows.exe) and [Mac OSX](http://arduino.cc/download_handler.php?f=/arduino-1.6.10-macosx.zip) +1. Download the zip file with the Multiprotocol module source code from [here](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/archive/master.zip) +1. Unzip and copy the source code folder **Multiprotocol** to a folder of your choosing +1. Click on the **Multiprotocol.ino** file in the **Multiprotocol** folder and the Arduino environment should appear and the Multiprotocol project will be loaded. + +##Prepare the Arduino IDE: +The Arduino IDE must be customized to optimally compile the firmware. The following additions to the environment will remove the Arduino bootloader to free up additional memory for protocols. +###Mac OSX: +1. Using finder navigate to ```Applications``` folder +1. Ctl-Click on the Arduino application and select **Show Package Contents**. +1. Browse to ```Contents/Java/hardware/arduino`` and double click on boards.txt +1. Copy and paste the following text into the end of the file and save it: + +``` +############################################################## +## Multi 4-in-1 (3.3V, 16 MHz) w/ ATmega328 +## -------------------------------------------------- +multi.name=Multi 4-in-1 + +multi.upload.tool=avrdude +multi.upload.protocol=arduino + +multi.bootloader.tool=avrdude +multi.bootloader.unlock_bits=0x3F +multi.bootloader.lock_bits=0x0F + +multi.build.board=AVR_PRO +multi.build.core=arduino +multi.build.variant=eightanaloginputs + +multi.menu.cpu.16MHzatmega328=ATmega328 (3.3V, 16 MHz) + +multi.menu.cpu.16MHzatmega328.upload.maximum_size=32768 +multi.menu.cpu.16MHzatmega328.upload.maximum_data_size=2048 +multi.menu.cpu.16MHzatmega328.upload.speed=57600 + +multi.menu.cpu.16MHzatmega328.bootloader.low_fuses=0xFF +multi.menu.cpu.16MHzatmega328.bootloader.high_fuses=0xD3 +multi.menu.cpu.16MHzatmega328.bootloader.extended_fuses=0xFD + +multi.menu.cpu.16MHzatmega328.build.mcu=atmega328p +multi.menu.cpu.16MHzatmega328.build.f_cpu=16000000L +############################################################## +``` +1. Open the file *platform.txt* in the same folder and change the line that reads + +```compiler.c.elf.extra_flags= ``` + +to + +```compiler.c.elf.extra_flags=-Wl,--relax ``` + +paste the following text into the end of the file and save it. + +Close and reopen the Arduino IDE and load the Multiprotocol project. + +### Windows: {customize for windows} +Using File Explorer navigate to + +```C:\Program Files(x86)\Arduino\hardware\arduino\avr ``` + +Open ```boards.txt``` in your favourite text editor (Notepad) + +Copy and paste the "Multi 4-in-1" text listed above into the end of the file and save it. + +Open the file *platform.txt* in the same folder and change the line that reads + +```compiler.c.elf.extra_flags= ``` + +to + +```compiler.c.elf.extra_flags=-Wl,--relax ``` + +Close and reopen the Arduino IDE and load the Multiprotocol project. + +## Common process for OSX and Windows +If you have module with an Arduino Pro-Mini then scroll down to Programming Arduino Pro-Mini Boards + +If you are using one of the DIY Mulitprotocol modules with the ATmega soldered directly to a PCB (like the 3.2d board or the Banggood readymade 4-in-1 module) then follow these instructions. +###Preparing for ATMega328P microcontroller +1. Under the Tools -> Board select the Multi 4-in-1 board +1. Under Tools -> Programmer select your programmer (probably USBASP) + +###Customize the firmware to your hardware and your needs +On all modules with ATMega microprocessors, the memory required for all the protocols exceeds the available 32k of flash memory. You will need to select which protocols you wish to use that will fit into the available memory. + +Before customizing your firmware it would be good to review the protocol on the [Protocol Details](Protocol_Details.md) page and to identify the protocols you would like to support on your module. + +At the same time make a note of RF modules required by your protocols. For example, if you do not wish to use the FlySky or the Husan protocols then you do not need to compile support the the A7105 RF Module into your firmware. Similarly, if you have no need to bind with ASSAN RC receivers then you do not need to compile the ASSAN protocol into your firmware. + +If you plan to use the PPM communication interface with your transmitter, then you need to perform protocol selection with the 16 position switch on your module. This will limit the available protocols you can usefully include on your firmware to 15. You should make a list of your 15 chosen protocols, sub protocols and options like this: + +Switch Position|Protocol|Sub-Protocol|Option|Notes +---------------|--------|------------|------|----- +1.|DSM|DSM2|2|6 channels @ 22ms +2.|DSM|DSMX|6|6 channels @ 11ms +....|...|...|...|... +....|...|...|...|... +15.|FRSKYX|CH_16| |FrSky X receiver 16 chan + + +With the above information (required RF modules, selected protocols and 16 pos switch mapping) you are ready to customize your firmware. + +All customization is done by editing the ```_Config.h ``` file in the Multiprotocol Arduino project. + +In the Arduino IDE and click on the down arrow on the far right of the tab bar to show a list of project files (see the red circle on the screenshot below). Scroll down and select the _Config.h file. + + +Comment out any of the RF modules that you do not need by typing ```// ``` at the begining of the line that reads : +```#define _INSTALLED ``` . The following line shows the CC2500 module removed + +> ```#define A7105_INSTALLED ``` + +> ```#define CYRF6936_INSTALLED ``` + +> **```//#define CC2500_INSTALLED ```** + +> ```#define NFR24L01_INSTALLED ``` + +Scroll down to the available protocols and comment out all the protocols you will not require. The following example shows the DEVO protocol commented out. + +> **```#ifdef CYRF6936_INSTALLED ``` + +> **``` // #define DEVO_CYRF6936_INO ```** + +> ``` #define DSM_CYRF6936_INO ``` + +> ``` #define J6PRO_CYRF6936_INO ``` + +> ``` #endif ```** + +If you have a Taranis Tx and you plan on using Serial mode with telemetry find and uncomment the INVERT_TELEMETRY line below: +> ```//Uncomment to invert the polarity of the telemetry serial signal.``` + +> ```//For ER9X and ERSKY9X it must be commented. For OpenTX it must be uncommented.``` + +> ```#define INVERT_TELEMETRY 1``` + + Scroll down to the bottom of the file and list your switch mapping to your desired **protocol/sub-protocol/options**. You typically only need to change the three relevant columns. On models that require a rebind on every start-up (like Syma quads) you can change the **```NO_AUTOBIND ```** to **```AUTOBIND ```**. + +You can now compile the firmware by clicking on the check mark (Tooltip: Verify) on the menu bar. If everything goes according to plan you should see something like the following line in the lower pane of the window: + +> Sketch uses 32,464 bytes (99%) of program storage space. Maximum is 32,768 bytes. +> Global variables use 1,219 bytes (59%) of dynamic memory, leaving 829 bytes for local variables. Maximum is 2,048 bytes. + +if you see something like the following, your firmware is still too big and you need to deselect additional protocols: +> Sketch uses 34,096 bytes (104%) of program storage space. Maximum is 32,768 bytes. +> Global variables use 1,236 bytes (60%) of dynamic memory, leaving 812 bytes for local variables. Maximum is 2,048 bytes. +> Sketch too big; see http://www.arduino.cc/en/Guide/Troubleshooting#size for tips on reducing it. + +If there is another error carefully read the error to see the approximate line number where you made a typing error. + + +###Connecting the programmer +To complete this step you need an USBASP programmer like the one shown below and a 10-pin to 6-pin programming cable. + +1. Before you connect the programmer make sure that you have selected the 3.3V mode and not the 5V mode. The RF Modules are not 5V tolerant and you will harm with 5V. On most programmers this is done by moving a jumper on the programmer. +1. Please re-read item 1. above before going on. +1. Turn the rotary switch on the DIY Multiprotocol module to the 0 position. If you do not have a switch (if you are using only Serial mode) then it the same as being in the 0 position. The upload will not work if the switch is in any other position. +1. Connect the 6-pin programming connector to the 6-pin ASP IVR connector on the DIY Multiprotocol board. Be sure to match the ground pin of the programmer connector to the ground pin on the board (see the images below for the pin layout and the location of the ground pin on the board) {insert pictures AVR ISP Pinout.png and images of boards with ground pin marked} +1. You are now ready to plug in the USB programmer to the computer +1. You are now ready to flash the firmware. In the Arduino IDE click **Sketch -> Upload Using Programmer**. +2. If you get an error that indicates a valid microprocessor was not found there is something wrong with: + - your connections, + - your programmer, or + - your board + - Google around with the specific error message to get suggestions of how to fix it. The most common cause is problems with the connection setup and in some cases problems with the cheap programmers from Chinese sources. +1. The final step is to flash the fuses of the microprocessor. These correct fuses will do a few things: + - Prevent the EEPROM from being erased each time the firmware is flashed. This will preserve your Tx ID and save you from having to rebind all your models after an update of the firmware + - Configure the clock source of the board - this is very important if you built the board from components. The ATMega328P microprocessor is configured at the factory to use an internal 8Mhz clock. The DIY Multiprotocol boards have a much more accurate 16MHz external crystal and the fuses will tell the MCU to use this clock source. (If you were able to flash the board but after setting the fuses the board no longer responds, it is very likely that you have a problem with your external clock.) + - Set the program counter to point at the right place when the module is powered up. The fuses configure the MCU to use a bootloader or not. If you compiled the firmware without a bootloader then the fuses must be set accordingly. +1. In the Arduino IDE ensure that the **4-in-1 Multi** is selected under **Tools -> Board"** click on **Tools -> Burn Bootloader**. Do not worry if it returns the error that no bootloader was found (in the case of the 4-in-1 board), it has burned the fuses. If you IDE was set to provide verbose compilation and uploading output, you should be able to see the final value of the fuses in the Arduino IDE. + +If the output indicates that the fuses have been successfully written give yourself a pat on the back. Well done, you have successfully programmed your DIY Multiprotocol module and you are ready to go on to the final step [Setting up your Transmitter](TransmitterSetup.md) before you can begin to fly!!!! + +##Programming Arduino Pro-Mini Boards +Use this method only for Arduino Pro Mini boards with bootloader. +1. Use an external FTDI adapter like this one. +1. The programmer should be set to 3.3V or nothing to not supply any over voltage to the multimodule and avoid any damages. +1. Under the Tools -> Board select the Arduino Pro-Mini +1. Under Tools -> Processor select the Atmega328p (5V, 16Mhz) +1. Under Tools -> Port select your the serial port your programmer is connected to (it should appear on the the list) +1. Scroll back to the section [Customize the firmware to your hardware and your needs] above and follow the instructions remembering that you can simply use the Upload button in the Arduino IDE to upload firmware using the Arduino bootloader: + - From the Arduino environment, you can use Upload button which will compile and upload to the module: Sketch->Upload (Ctrl+U) + +To change the fuses you will need to use an external programmer (like USBasp mentioned above) and a flash tool that fits over the MCU and connects to the required pins. Follow the same instructions to set the fuses in the section above. + +If building the board from scratch was your chosen strategy we suspect that you would already know how to do this. If not, Google is your friend, try something like “how to flash fuses on Arduino pro-mini”. + +You may also find a Atmel socket flash tool like this useful + +[](http://www.hobbyking.com/hobbyking/store/__27195__Atmel_Atmega_Socket_Firmware_Flashing_Tool.html) + + +It connects to the USBASP programmer and connects directly to the pins on the microcontroller and it will allow you to program the Pro-Mini like the 4-in-1 boards above, without using the bootloader. diff --git a/docs/Compiling_STM32.md b/docs/Compiling_STM32.md new file mode 100644 index 0000000..66fb9dd --- /dev/null +++ b/docs/Compiling_STM32.md @@ -0,0 +1,150 @@ +# Compliling and Programming (STM32) + +**If you are Compling for the Arduino ATmega328p version of the Multiprotocol Module please go to the dedicated [Compiling and Programming ATmega328](Compiling.md) page.** + +Multiprotocol source can be compiled using the Arduino IDE using STM32 Core (Maple) and Arduino ARM-Cortex-M3 libraries. + +###Install the Arduino IDE and the Multiprotocol project +1. Download the Arduino IDE. The currently supported Arduino version is 1.6.5. available for [Windows]( https://www.arduino.cc/download_handler.php?f=/arduino-1.6.5-windows.exe) and [Mac OSX](http://arduino.cc/download_handler.php?f=/arduino-1.6.5-macosx.zip) +1. Download the [STM32 Core](https://github.com/rogerclarkmelbourne/Arduino_STM32/archive/master.zip) and copy the Arduino_STM32 folder to: + - OSX: ```Arduino.app/Contents/Java/hardware``` (you can open Arduino.app by Ctl Clicking on Arduino.app and selecting "Show Package Contents") + - Windows: ```C:\Program Files (x86)\Arduino\hardware``` +1. Download the zip file with the Multiprotocol module source code from [here](https://github.com/midelic/DIY-Multiprotocol-TX-Module/archive/multi-STM32.zip) +1. Unzip and copy the source code folder ```Multiprotocol``` to a folder of your choosing +1. Click on the ```Multiprotocol.ino file``` in the ```Multiprotocol``` folder and the Arduino environment should appear and the Multiprotocol project will be loaded. + +###Prepare the Arduino IDE: + +1. In order to compile successfully you need also to modify a maple library file. In ```....\hardware\Arduino_STM32\STM32F1\cores\maple\libmaple\usart_f1.c``` comment out the 2 functions as shown below. This is required to have low-level access to the USART interrupt. + + > ```//void __irq_usart2(void) { usart_irq(&usart2_rb, USART2_BASE); } ``` + + > ```//void __irq_usart3(void) { usart_irq(&usart3_rb, USART3_BASE); } ``` +1. Run the IDE, and on the **Tools** menu, select **Board** and then **Boards manager**. Click on the Arduino DUE (32 Bits ARM-Cortex M3) from the list of available boards. You must do this step, it installs the arm-none-eabi-g++ toolchain! +1. Close and reopen the Arduino IDE and load the Multiprotocol project. +1. Click on the **Verify** button to test compile the before you make any changes. If there are errors check the process above and be sure to have the right version of the Arduino IDE. + + +## Common process for OSX and Windows + +###Customize the firmware to your hardware and your needs +On all modules with STM32F103 microcontroller, the program flash memory on the microcontroller is large enough to accommodate all the protocols. You do not have to make choices on which protocols to upload. Also, it is likely that you used the Banggood 4-in-1 RF module and you will therefore have access to all the RF modules. However, you can follow these instructions to select only a subset protocols. + +If you plan to use the PPM mode then you should follow the instructions to customize the protocol selection switch to protocol mapping. + +Before customizing your firmware it would be good to review the protocol on the [Protocol Details](Protocol_Details.md) page and to identify the protocols you would like to support on your module. + +At the same time make a note of RF modules required by your protocols. For example, if you do not wish to use the FlySky or the Husan protocols then you do not need to compile support the the A7105 RF Module into your firmware. Similarly, if you have no need to bind with ASSAN RC receivers then you do not need to compile the ASSAN protocol into your firmware. + +If you plan to use the PPM communication interface with your transmitter, then you need to perform protocol selection with the 16 position switch on your module. This will limit the available protocols you can usefully access in PPM mode on your module to 15 (this limitation does not apply to Serial mode). You should make a list of your 15 chosen protocols, sub protocols and options like this: + +Switch Position|Protocol|Sub-Protocol|Option|Notes +---------------|--------|------------|------|----- +1.|DSM|DSM2|2|6 channels @ 22ms +2.|DSM|DSMX|6|6 channels @ 11ms +....|...|...|...|... +....|...|...|...|... +15.|FRSKYX|CH_16| |FrSky X receiver 16 chan + + +With the above information (required RF modules, selected protocols and 16 pos switch mapping) you are ready to customize your firmware. + +All customization is done by editing the ```_Config.h ``` file in the Multiprotocol Arduino project. + +In the Arduino IDE and click on the down arrow on the far right of the tab bar to show a list of project files (see the red circle on the screenshot below). Scroll down and select the _Config.h file. + + +It is unlikely that you would need to do this, but you can comment out any of the RF modules that you do not need by typing ```// ``` at the begining of the line that reads : +```#define _INSTALLED ``` . The following line shows the CC2500 module removed + +> ```#define A7105_INSTALLED ``` + +> ```#define CYRF6936_INSTALLED ``` + +> **```//#define CC2500_INSTALLED ```** + +> ```#define NFR24L01_INSTALLED ``` + +Again it is unlikely that you would want to do this, but you can scroll down to the available protocols and comment out all the protocols you will not require. The following example shows the DEVO protocol commented out. + +> **```#ifdef CYRF6936_INSTALLED ``` + +> **``` // #define DEVO_CYRF6936_INO ```** + +> ``` #define DSM_CYRF6936_INO ``` + +> ``` #define J6PRO_CYRF6936_INO ``` + +> ``` #endif ```** + +Look for the line containing ```#define INVERT_TELEMETRY``` and make sure that it is uncommented: +> ```#define INVERT_TELEMETRY ``` + + Scroll down to the bottom of the file and list your switch mapping to your desired **protocol/sub-protocol/options**. You typically only need to change the three relevant columns. On models that require a rebind on every start-up (like Syma quads) you can change the **```NO_AUTOBIND ```** to **```AUTOBIND ```**. + +Finally, if you have not already done so, specify the correct board for the compiler. Under **Tools** -> **Board:** select the **Generic STM32F103C series** board. You can now compile the firmware by clicking on the check mark (Tooltip: Verify) on the menu bar. If everything goes according to plan you should see something like the following line in the lower pane of the window: + +> Sketch uses 32,464 bytes (99%) of program storage space. Maximum is 32,768 bytes. +> Global variables use 1,219 bytes (59%) of dynamic memory, leaving 829 bytes for local variables. Maximum is 2,048 bytes. + +If you get an error carefully read the error to see the approximate line number where the error occured and correct it. + +###Preparing for STM32 microcontroller for firmware flashing + +There are two option for flashing the firmware. The first (and strongly recommended) is flashing it while it is plugged into and powered by the transmitter. The second is flashing it out of the transmitter (the power is supplied by the FTDI cable). The second option is very risky because if the 3.3V bridge jumper is not removed after flashing it will fry your RF module - **you have been warned**. + +####Option 1: Flashing with Tx power + +1. Put the module in the Tx +1. Place a jumper over the BOOT0 pins +1. Connect your 3.3V/5V FTDI cable (USB - TTL serial) to Multiprotocol serial port (RX,TX,GND,5V).The multimodule RX pin connected to FTDI TX pin and multi TX pin connected to FTDI RX pin.Connect only TX and RX pins(2 pins),the power will be supplied by TX. +1. In arduino IDE under the **Tools** -> **Board:** check that you have selected the **Generic STM32F103C series** board +1. Under **Tools** -> **Upload Method:** select **Serial** +1. Click "Upload" and the sketch will be uploaded normally.This is valid for all arduino versions. +1. Once the firmware has uploaded, remove the BOOT0 jumper. + + +####Option 2: Flashing without Tx power + +The key difference of this method is that the 3.3V FTDI cable must also provide power to the 5V circuitry during the flashing process. To do this, a jumper must be enabled connecting the 3.3V VCC to the 5V line. + +**If the module is powered through the transmitter and this jumper is enabled, then it will feed 5V throughout the 3.3V circuit and this will fry your RF modules.** + +1. Set BOOT0 jumper +1. Set the 3.3V jumper.This step only for 3.3V USB-serial!!!.Skip this step if using 5V USB-serial. +1. Connect your 3.3V FTDI cable (USB - TTL serial) to Multiprotocol serial port (RX,TX,GND,5V).If set 3.3V jumper ,3.3V supply from USB-serial goes to 5V pin. +1. In arduino IDE under the **Tools** -> **Board:** check that you have selected the **Generic STM32F103C series** board +1. Under **Tools** -> **Upload Method:** select **Serial**. +1. Click "Upload" and the sketch will be uploaded normally. +1. Once the firmware has uploaded: + - Remove the 3.3V jumper!!!! + - Remove the BOOT0 jumper + - Check that you removed the 3.3V jumper + + +###Flashing binary file: +If you want to flash a pre-compiled binary file (like the Release .bin files) you need specialized software and the FTDI cable. +1. Set BOOT0 jumper +1. Connect your 3.3V FTDI cable (USB - TTL serial) to Multiprotocol serial port (RX,TX,GND,5V) +1. The other steps regarding power supply the same as previous recommandation regarding jumpers. +For uploading binaries(.bin files) there is a specialized software you need to install on your computer. + +#### Windows: +Download the ST Flash Loader Demonstrator from here: http://www.st.com/content/st_com/en/products/development-tools/software-development-tools/stm32-software-development-tools/stm32-programmers/flasher-stm32.html + +Run the ST Flash Loader program. There are many tutorials on the web on how to use this program.For example + +[here](http://www.scienceprog.com/flashing-programs-to-stm32-embedded-bootloader) + +#### OSX: +To be checked. + +###Report issues for the STM32 board +You can report your problem using the [GitHub issue](https://github.com/midelic/DIY-Multiprotocol-TX-Module/issues) system or go to the [Main thread on RCGROUPS](http://www.rcgroups.com/forums/showthread.php?t=2165676) to ask your question. +Please provide the following information: +- Multiprotocol code version +- STM32 version +- TX type +- Using PPM or Serial, if using er9x or ersky9x the version in use +- Different led status (multimodule and model) +- Explanation of the behavior and reproduction steps diff --git a/docs/DIY Multiprotocol Module Overview.png b/docs/DIY Multiprotocol Module Overview.png new file mode 100644 index 0000000000000000000000000000000000000000..83b0ab0982b2e6adb925de704950bd4077d92fb7 GIT binary patch literal 89344 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 SIe^L}1_n=8KbLh*2~7aEqyeV@ literal 0 HcmV?d00001 diff --git a/docs/Documentation_To_Do_List.md b/docs/Documentation_To_Do_List.md new file mode 100644 index 0000000..b772db9 --- /dev/null +++ b/docs/Documentation_To_Do_List.md @@ -0,0 +1,28 @@ +#Documentation ToDos +1. Documentation on all the FlySky boards: (MikeB?) + - SKY board erSky9x + - AR9X board erSky9x + - 9Xtreme board erSky9x + - AR9X UNI board +1. Add to the troubleshooting page +1. Document the OrangeRx Transmitter module (Mikeb?) +1. enabling Serial on the DIY PCB page +1. lots of pictures mentioned between the {} markers +2. Add how to wire the antenna switcher in the "solder your own board and use 4-in-1 Rf module (add pictures of the wires from the ATmega pins to PE1 and PE2) +3. Must this be added to the (Compiling for Taranis)Also, if you are using a Taranis, then you need to invert the telemetry as shown: +Code: +//Uncomment to invert the polarity of the telemetry serial signal. +//For ER9X and ERSKY9X it must be commented. For OpenTX it must be uncommented. +#define INVERT_TELEMETRY1 +1. ~~restructure the transmitter setup documentation~~ + - ~~PPM setup all on one page~~ + - ~~Serial setup by Transmitter~~ + +1. PPM Telemetry: added different serial speeds based on protocol for none inverted telemetry: +FrSkyD (Incl Hubsan): 9600bps 8n1 +FrSkyX: 57600bps 8n1 +DSM: 125000bps 8n1 +I've done this if people wants to connect something (arduino, bluetooth,...) behind the module to display telemetry when used in PPM mode. It's using the default speed of the original transmitter. +This is not something supported by er9x or ersky9x which are meant to be used in serial mode. +1. Someone to add the Build the board from scratch if it is still relevant + diff --git a/docs/Hardware.md b/docs/Hardware.md new file mode 100644 index 0000000..9098682 --- /dev/null +++ b/docs/Hardware.md @@ -0,0 +1,19 @@ +# Hardware Options + +The choice of hardware is the single biggest choice you will make. Due to the growing popularity of this project the number of hardware choices is growing almost monthly. + +There are currently four common hardware options. They are: + +1. A ready-made DIY Mulitprotocol module from Banggood.com (see [here](http://www.banggood.com/2_4G-CC2500-A7105-Flysky-Frsky-Devo-DSM2-Multiprotocol-TX-Module-With-Antenna-p-1048377.html)) that integrates the microprocessor with all four supported RF modules and a hardware antenna switcher. +[![Screenshot](images/4-in-1_Module_BG.jpeg?raw=true "4-in-1 MPTM from Banggood.com" =50x50)](Module_BG_4-in-1.md) +1. A host PCB for the DIY Multiprotocol module onto which the MCU and the desired RF modules can be soldered +[![Screenshot](images/Multiprotocol_3.2.jpeg?raw=true =50x50 )](Module_Build_yourself_PCB.md) +1. Orange DSM Transmitter transmitter module that natively supports the CYRF6936 RF module. This module can be improved with Mulitprotocol firmware. +[![Screenshot](images/OrangeRx_Module.jpg)](Module_OrangeRx.md) +1. A module built from scratch using perfboard, an Arduino Pro-Mini and the desired RF modules. +Unless you are handy with a soldering iron and you have access to electronic test equipment (like an oscilloscope) you should consider only Option 1. For a price of about $44 you can get everything you need, neatly assembled + +[![Screenshot](images/Module_perfboard1.jpeg) ![Screenshot](images/Module_perfboard2.jpeg)](Module_Build_From_Scratch.md) + +Click on any of the images above to understand more about each option. + diff --git a/docs/Models.md b/docs/Models.md new file mode 100644 index 0000000..53e2725 --- /dev/null +++ b/docs/Models.md @@ -0,0 +1,19 @@ +#Model Setup +This is the page to document model or receiver specific setup instructions. +The complete list of models the protocols they use are documented [here](https://docs.google.com/spreadsheets/d/1nBHzT3VWF6ShAhOqRB5y0Bcc7aXFuRFFlQkHn1RIM84/edit#gid=0) +#Syma X5C + +##Binding +There are no special binding instructions. The model powers up in Autobind mode and expects the bind sequence from the transmitter within the first 4-5 seconds. +##Tx Setup +{How to setup the transmitter switches for rates, flip, picture and video} + +#Inductrix (Horizon Hobby) + + + +##Binding +{Enter bind instructions here - Which DSM mode works best?} + +##Tx Setup +{How to setup the transmitter optimally for leveling and acro mode} diff --git a/docs/Module_BG_4-in-1.md b/docs/Module_BG_4-in-1.md new file mode 100644 index 0000000..78ecc41 --- /dev/null +++ b/docs/Module_BG_4-in-1.md @@ -0,0 +1,47 @@ + +#4-in-1 Banggood module +Currently the form factor of this module is designed for the JR-style module bay. Many of the popular RC transmitters use the JR-style module bay: FrSky Taranis, FlySky Th9x, Turnigy 9X/R/Pro {other transmitters that come to mind?} +##What you need +1. The ready-made module is available from Banggood.com [here](http://www.banggood.com/2_4G-CC2500-A7105-Flysky-Frsky-Devo-DSM2-Multiprotocol-TX-Module-With-Antenna-p-1048377.html) + +1. A module case that fits your receiver like the one [here](https://www.xtremepowersystems.net/proddetail.php?prod=XPS-J1CASE) + + or you can 3D print your own from a selection on Thingiverse (example [here](http://www.thingiverse.com/thing:1661833)). + +1. 3x2 header pins (to solder onto the board for programming) +1. AVR ISP programmer like the popular USBASP programming dongle that is 3.3V safe - available from many sellers on [ebay.](http://www.ebay.com/sch/i.html?_odkw=usbasp+progammer&_osacat=0&_from=R40&_trksid=p2045573.m570.l1313.TR3.TRC2.A0.H0.Xusbasp+progammer+3.3V.TRS1&_nkw=usbasp+progammer+3.3V&_sacat=0) There are reports that some of the cheap programmers are not safe to use with 3.3V units (like this unit). Look for USBAsp programmers with the “LC Technologies” label. {Pascal to confirm these reports are true} Also, you will need a 10-pin to 6-pin connector to connect the USBASP to the board. + + +##Build instructions +The assembly process is trivial but it does depend on: +- The communication interface between your transmitter and the module, and +- The version of the module you have + +###Common steps + +1. Solder the 3x2 header pins onto the module as shown below {insert picture of module with pins}. These header pins are required to program the microcontroller. +1. Fit the module into the module case. This may require some careful filing or sanding of the module to ensure a nice fit. + +###PPM interface +If you are only planning on using the PPM interface with transmitter you are ready to program the module as described in Compiling and Programming the module. + +###Enabling Serial interface +If you have a transmitter that can support serial communication with the board then you need to wire up the board appropriately. There are two versions of the module and the steps are slightly different. + +Check which module you have and based on the pictures below. If you purchased the module after June 2016 then it is likely that you have V2 module. + +#### **Version 2 (V2) module** + +Solder two bridges over the pads shown in the picture below. + + + + +You are now ready to go over to [Compiling and Programming](Compiling.md). + +#### **Version 1 (V1) module** + +Solder bridges and resistors as illustrated in the picture below. + + +You are now ready to go over to [Compiling and Programming](Compiling.md). diff --git a/docs/Module_Build_From_Scratch.md b/docs/Module_Build_From_Scratch.md new file mode 100644 index 0000000..193444d --- /dev/null +++ b/docs/Module_Build_From_Scratch.md @@ -0,0 +1,17 @@ +#Build from stratch + +If you can help to fully document this page, or just add additional detail please let us know on the rcgroups [forum](http://www.rcgroups.com/forums/showthread.php?t=2165676). + +## Bill of materials +If this is the option you are following, then you must have a pretty good idea of what you are doing. Check the BOM for the DIY PCB version of the hardware as a starting point. You can find the link [here](Module_Build_yourself_PCB.md). + +The Arduino Pro-Mini is available many places online. Check Sparkfun (the original developers of the Pro-Mini) page [here](https://www.sparkfun.com/products/11113) + +You will require a second Arduino or a FTDI (USB to TTL serial) cable to program the Pro-Mini. Like the one [here](https://www.sparkfun.com/products/9717). **Make sure you get only a 3.3V FTDI cable - or you will fry your 3.3V RF modules when you connect it up.** + +##Reference Schematic +Here is the schematic you can use to troubleshoot the module + + +##Compiling and programming +Follow the instruction on the [Compiling and programming page](Compiling.md) diff --git a/docs/Module_Build_yourself_PCB.md b/docs/Module_Build_yourself_PCB.md new file mode 100644 index 0000000..a739ab2 --- /dev/null +++ b/docs/Module_Build_yourself_PCB.md @@ -0,0 +1,91 @@ + +#Build your own by soldering a PCB +Currently the form factor of this module is designed for the JR-style module bay. Many of the popular RC transmitters use the JR-style module bay: FrSky Taranis, FlySky Th9x, Turnigy 9X/R/Pro {other transmitters that come to mind?} +##What you need +First you must choose the PCB onto which to solder all the components. There are two PCB options: + * ATmega (8-bit) powered PCB V2.3d supporting individual RF modules + * STM32 (32-bit) powered PCB supporting the 4-in-1 RF module + +The **ATmega-based board** has been designed to accept individual RF modules. This way you can select just the module or modules you want. The downside is that each module requires its own antenna. It can become cumbersome with 4 antennas protruding from the module. It is possible to soder the 4-in-1 module to the PCB using thin insulated wire. This 4-in-1 module requires only one antenna. Finally, the Atmega board has a 32k flash memory. This is big enough to accommodate more than 15 protocols, but it cannot accommodate all the available protocols. + + + +The **STM32-based** board has been designed to accept the 4-in-1 RF module with the antenna switcher (shown below). This means only one antenna. The STM32F103 processesor also has a much larger flash memory. + + + +###ATmega board V2.3d +1. ATmega (8-bit) powered PCB V2.3d available from OSHPark [here](https://oshpark.com/shared_projects/Ztus1ah8). +2. Individual RF modules The modules are available here: + - [CC2500](http://www.banggood.com/2_4G-500K-CC2500-Long-Range-Wireless-Transceiver-Module-p-1075492.html) for FrSkyV, FrSkyD, FrSkyX and SFHSS + - CYRF6936 {Can someone please give me a source} for DSM, DEVO, J6Pro + - [A7105](http://www.banggood.com/A7105-Wireless-RF-2_4GHz-Transceiver-Module-3_3V-Power-Supply-Module-p-909404.html) for Flysky, Hubsan + - [NRF24L01](http://www.banggood.com/2_4G-NRF24L01-PA-LNA-Wireless-Module-16+32mm-Without-Antenna-p-922601.html?utm_source=tradetracker&utm_medium=tradetracker_SE&utm_campaign=tradetracker&utm_content=227736) for Hisky, V2x2, CX-10, SYMAX and plenty other protocols + - The 4-in-1 RF module (available [here](http://www.banggood.com/DIY-2_4G-CC2500-NRF24L01-A7105-CYRF6936-Multi-RF-4-IN-1-Wireless-Module-p-1046308.html)) can also be connected with solder wires. To enable the antenna switcher the PE1 and PE2 pads must be soldered to ATmega pins, check the [schematic](#V23D_Schematic) +1. Electronics component BOM is downloadable [here](http://www.rcgroups.com/forums/showatt.php?attachmentid=7565057&d=1423770640). This BOM is inclusive, you many not need all the parts depending on your needs. + +The schematic for the board is [here](#V23D_Schematic). Please note that is is the general schematic - there will be some minor differences (like solder jumpers) between this and the board. + +###STM32 powered PCB +1. STM32 (32-bit) powered PCB supporting the 4-in-1 RF module available from OSHPark [here](https://oshpark.com/shared_projects/toBXcpNK). +2. The 4-in-1 RF module is available [here](http://www.banggood.com/DIY-2_4G-CC2500-NRF24L01-A7105-CYRF6936-Multi-RF-4-IN-1-Wireless-Module-p-1046308.html) +1. The BOM for this board is available [here](https://github.com/midelic/DIY-Multiprotocol-TX-Module/blob/multi-STM32/Multiprotocol_STM32.txt). The github project page for the STM32 module is [here](https://github.com/midelic/DIY-Multiprotocol-TX-Module). + +The schematic for the board is [here](#STM32_Schematic) + +###Common parts +1. A module case that fits your receiver like the one [here](https://www.xtremepowersystems.net/proddetail.php?prod=XPS-J1CASE) + + or you can 3D print your own from a selection on Thingiverse (example [here](http://www.thingiverse.com/thing:1661833) or [here](http://www.thingiverse.com/thing:1691786)). + +1. A 2.4GHz antenna and pigtail +1. AVR ISP programmer like the popular USBASP programming dongle that is 3.3V safe - available from many sellers on [ebay.](http://www.ebay.com/sch/i.html?_odkw=usbasp+progammer&_osacat=0&_from=R40&_trksid=p2045573.m570.l1313.TR3.TRC2.A0.H0.Xusbasp+progammer+3.3V.TRS1&_nkw=usbasp+progammer+3.3V&_sacat=0) There are reports that some of the cheap programmers are not safe to use with 3.3V units (like this unit). Look for USBAsp programmers with the “LC Technologies” label. {Pascal to confirm these reports are true} Also, you will need a 10-pin to 6-pin connector to connect the USBASP to the board. + + +##Build instructions +If you got this far you already know what you are doing!! + +###Common steps + +1. Solder all the parts according to the BOM part numbering and the images for your board (see OSHPARK for the images) +1. Fit the module into the module case. This may require some careful filing or sanding of the module to ensure a nice fit. + +###PPM interface +If you are only planning on using the PPM interface with transmitter you are ready to program the module as described in Compiling and Programming the module. + +###Enabling Serial interface +If you have a transmitter that can support serial communication with the board then you need to solder some jumpers. + + +#### **ATmega V2.3d board** + +There are four solder type jumpers on the bottom side of the board near the lower left corner when the bottom of the board is facing towards you. The silkscreen shows which jumper is which. These four jumpers enable the board to be configured in several ways as explaned below. + + (J-1) Use (PPM V/V) if the incoming PPM signal is at a higher voltage level, leave open if ~~5V. + + (J-2) Use (Jumper 2) to connect the incomming PPM signal to the RX pin on the processor + + (J-3) Short (TELEM) only if you have done a telemetry mod to your radio, leave open if not needed. When connected, pin 2 of the two pin header (P3) is also connected. + + (J-4) Use (MOD) only to connect the transmitter pin 2 to pin 1 of the two pin header (P3). + +**It is most likely J-2 will be the only one needing to be shorted for the serial method of sending model protocols.** + +You are now ready to go over to [Compiling and Programming](Compiling.md). + +#### **STM32 board** + +Solder bridges and resistors as illustrated in the picture below. {need to get info from midelic} + + +You are now ready to go over to [Compiling and Programming STM32](Compiling_STM32.md). + +#Reference Schematic +Here is the schematic you can use to troubleshoot the module +## PCB V2.3d Schematic + +## PCB STM32 Schematic + + + + diff --git a/docs/Module_OrangeRx.md b/docs/Module_OrangeRx.md new file mode 100644 index 0000000..cde0932 --- /dev/null +++ b/docs/Module_OrangeRx.md @@ -0,0 +1,3 @@ +#OrangeRx Transmitter module +{need someone to do this if it is important} + diff --git a/docs/PPM_Setup.md b/docs/PPM_Setup.md new file mode 100644 index 0000000..511af7a --- /dev/null +++ b/docs/PPM_Setup.md @@ -0,0 +1,56 @@ +#PPM Setup + +The Multiprotocol Module is compatible with any transmitter that is able to generate a PPM (Pulse Postion Modulation) output. This includes all transmitters with a module bay or a trainer port. It supports up to 16 channels from a PPM frame in the normal or inverted format (sometimes called positive or negative format in some transmitters). +If you want the best performance you can set the number of channels and framerate corresponding to the number of channels of the specific receiver/model. + +##PPM Connections +If you do not have a module bay, there are only three wires you need to connect to get PPM to work. (The pins are numbered from top to bottom) +- PPM on pin 1 +- vbat on pin 3 +- ground on pin 4 +Note: vbat should be between 6V and 13V when using the 4-in-1 and 2.3 PCB boards. If you built a module from scratch it depends on the voltage regulator you chose. + + +##Enabling PPM mode in your transmitter + +1. Enable the default Tx mode to be AETR. If you do not want to change the default channel order on your Tx you must remember to change the channel order for each new model using the module to AETR under the Model Mixer menu. +1. The default PPM settings is 8 channels with a frame period of 22.5 ms (sometimes called the frame rate). If you want to optimize performance you should change the channels to the actual number of channels required by your model. The corresponding frame period should be set to (number of channels + 1) * 2.5 ms. For example: + - A 4 channel model the frame period is (4 + 1)*2.5 = 12.5 ms. + - A 6 channel model the frame period is (6 + 1)*2.5 = 17.5ms. + +## Protocol selection in PPM mode + +To select the protocol simply switch off the transmitter and rotate the protocol selection switch on the module to the desired position. + +*Note that the dial selection must be done before the module receives power - this is not necessarily the same time that the transmitter is powered up. The transmitter often only provides power to the module once it has passed switch checks and throttle position checks. * + +The default mapping of protocols to switch positions can be viewed on the Protocol Details page found [here](Protocol_Details.md#DefaultMapping) + +The mapping of protocols to protocol selection switch positions can be changed in configuration settings as described on the [Compiling and Programming page](Compiling.md). + +##Binding in PPM mode + +In PPM mode follow the standard transmitter - receiver binding process: + 1. Switch off the transmitter + 1. Switch on the receiving device in bind mode (if it is not already autobind). Check the documentation for your device. + 1. Press and hold the bind button on the back of the module as you power up the transmitter. Hold the button down until the transmitter powers up the module. The red LED on the module should be flashing at about 5Hz - indicating bind mode. + 1. Watch the receiver for the completion of the bind process + 1. This is a model supporting autobind (binds every time it powers up) then you should be ready to go + 1. For traditional RC receivers with a bind memory - power down the receiver and the Tx and then power up the Tx and the Rx to confirm bind. + +If you are having trouble binding to a consumer quad check the section below on [Getting your Bind Timing right](Bind_Timing.md). For more details on setting up specific receivers or models, check out the [Protocol Details page](Protocol_Details.md). + +##Telemetry in PPM mode + +Telemetry is available as a serial stream on the TX pin of the Atmega328p in the FrSky HUB format. The serial parameters are based on the protocol selected by the protocol selection dial. + +Protocol|Serial Parameters +--------|----------------- +Hubsan|9600bps 8n1 +FrSkyD|9600bps 8n1 +FrSkyX|57,600bps 8n1 +DSM2/X|125,000bps 8n1 + +The serial stream is also available on pin 5 of the Module connector (pins numbered from top to bottom) on the [4-in-1 module]() and the [V2.3d modules]() provided the Tx jumper has been soldered. See the linked module documentation for what this means. + +You can connect it to your TX if it is telemetry enabled or use a bluetooth adapter (HC05/HC06) along with an app on your phone/tablet [(app example)](https://play.google.com/store/apps/details?id=biz.onomato.frskydash&hl=fr) to display telemetry information and setup alerts. diff --git a/docs/Protocol_Details.md b/docs/Protocol_Details.md new file mode 100644 index 0000000..df4bd99 --- /dev/null +++ b/docs/Protocol_Details.md @@ -0,0 +1,447 @@ +#Protocols details +Here are detailed descriptions of every supported protocols (sorted by RF modules) as well as the available options for each protocol. + + If you want to see a list of models that use these protocols see the [Models](Models.md) page. + +## Default Mapping of Protocols +Here is the default mapping of protocols to the 16-position protocol selection switch on the module. You can customize these when you compile your own firmware as described in [Compiling and Programming.](Compiling.md) + +**Note that the protocol must be selected before the unit is turned on.** + +Dial|Protocol|Sub_protocol|RX Num|Power|Auto Bind|Option|RF Module +----|--------|------------|------|-----|---------|------|--------- +0|Select serial|||||| +1|FLYSKY|Flysky|0|High|No|0|A7105 +2|HUBSAN|-|0|High|No|0|A7105 +3|FRSKYD|-|0|High|No|-41|CC2500 +4|HISKY|Hisky|0|High|No|0|NRF24L01 +5|V2X2|-|0|High|No|0|NRF24L01 +6|DSM|DSM2|0|High|No|6|CYRF6936 +7|DEVO|-|0|High|No|0|CYRF6936 +8|YD717|YD717|0|High|No|0|NRF24L01 +9|KN|WLTOYS|0|High|No|0|NRF24L01 +10|SYMAX|SYMAX|0|High|No|0|NRF24L01 +11|SLT|-|0|High|No|0|NRF24L01 +12|CX10|BLUE|0|High|No|0|NRF24L01 +13|CG023|CG023|0|High|No|0|NRF24L01 +14|BAYANG|-|0|High|No|0|NRF24L01 +15|SYMAX|SYMAX5C|0|High|No|0|NRF24L01 + +## Useful notes and definitions +- **Extended limits supported** - A command range of -125%..+125% will be transmitted. Otherwise the default is -100%..+100% only. +- **Autobind protocol** - The transmitter will automatically initiate a bind sequence on power up. This is for models where the receiver expects to rebind every time it is powered up. In these protocols you do not need to press the bind button at power up to bind, it will be done automatically. +- **Channel Order** - The channel order assumed in all the documentation is AETR and it is highly recommended that you keep it this way. You can change this in the compilation settings. However, please indicate your channel order in all questions and posts on the forum pages. + +*** +#A7105 RF Module + +##FLYSKY +Extended limits supported + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +---|---|---|---|---|---|---|--- +A|E|T|R|CH5|CH6|CH7|CH8 + +Note that the RX ouput will be AETR. + +###Sub_protocol V9X9 +CH5|CH6|CH7|CH8 +---|---|---|--- +FLIP|LIGHT|PICTURE|VIDEO + +###Sub_protocol V6X6 +CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 +---|---|---|---|---|---|---|--- +FLIP|LIGHT|PICTURE|VIDEO|HEADLESS|RTH|XCAL|YCAL + +###Sub_protocol V912 +CH5|CH6 +---|--- +BTMBTN|TOPBTN + +##HUBSAN +Models: Hubsan H102D, H107/L/C/D and Hubsan H107P/C+/D+ + +Autobind protocol + +Telemetry enabled for battery voltage and TX RSSI + +Option=vTX frequency (H107D) 5645 - 5900 MHz + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP|LIGHT|PICTURE|VIDEO|HEADLESS + +*** +#CC2500 RF Module + +##FRSKYV = FrSky 1 way +Models: FrSky receivers V8R4, V8R7 and V8FR. + +Extended limits supported + +Option=fine frequency tuning. This value is different for each board. To determine the option value, find the two limits where the RX loses connection then set the option value to half way between them. If you have a 4in1 V2 board the value is around 40. + +CH1|CH2|CH3|CH4 +---|---|---|--- +CH1|CH2|CH3|CH4 + +##FRSKYD +Models: FrSky receivers D4R and D8R. DIY RX-F801 and RX-F802 receivers. + +Extended limits supported + +Telemetry enabled for A0, A1, RSSI, TSSI and Hub + +Option=fine frequency tuning. This value is different for each board. To determine the option value, find the two limits where the RX loses connection then set the option value to half way between them. If you have a 4in1 V2 board the value is around 40. + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +---|---|---|---|---|---|---|--- +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 + +##FRSKYX +Models: FrSky receivers X4R, X6R and X8R. + +Extended limits supported + +Telemetry enabled for A1 (RxBatt), A2, RSSI, TSSI and Hub + +Option=fine frequency tuning. This value is different for each board. To determine the option value, find the two limits where the RX loses connection then set the option value to half way between them. If you have a 4in1 V2 board the value is around 40. + +###Sub_protocol CH_16 +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16 +---|---|---|---|---|---|---|---|---|----|----|----|----|----|----|---- +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13|CH14|CH15|CH16 + +###Sub_protocol CH_8 +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +---|---|---|---|---|---|---|--- +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 + +##SFHSS +Models: Futaba RXs and XK models. + +Option=fine frequency tuning. This value is different for each board. To determine the option value, find the two limits where the RX loses connection then set the option value to half way between them. If you have a 4in1 V2 board the value is around 40. + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +---|---|---|---|---|---|---|--- +A|E|T|R|CH5|CH6|CH7|CH8 + +*** +#CYRF6936 RF Module + +##DEVO +Extended limits supported + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +---|---|---|---|---|---|---|--- +A|E|T|R|CH5|CH6|CH7|CH8 + +Note that the RX ouput will be EATR. + +Bind procedure using serial: +- With the TX off, put the binding plug in and power on the RX (RX LED slow blink), then power it down and remove the binding plug. Receiver should now be in autobind mode. +- Turn on the TX, set protocol = Devo with option=0, turn off the TX (TX is now in autobind mode). +- Turn on RX (RX LED fast blink). +- Turn on TX (RX LED solid, TX LED fast blink). +- Wait for bind on the TX to complete (TX LED solid). +- Make sure to set the RX_Num value for model match. +- Change option to 1 to use the global ID. +- Do not touch option/RX_Num anymore. + +Bind procedure using PPM: +- With the TX off, put the binding plug in and power on the RX (RX LED slow blink), then power it down and remove the binding plug. Receiver should now be in autobind mode. +- Turn on RX (RX LED fast blink). +- Turn the dial to the model number running protocol DEVO on the module. +- Press the bind button and turn on the TX. TX is now in autobind mode. +- Release bind button after 1 second: RX LED solid, TX LED fast blink. +- Wait for bind on the TX to complete (TX LED solid). +- Press the bind button for 1 second. TX/RX is now in fixed ID mode. +- To verify that the TX is in fixed mode: power cycle the TX, the module LED should be solid ON (no blink). +- Note: Autobind/fixed ID mode is linked to the dial number. Which means that you can have multiple dial numbers set to the same protocol DEVO with different RX_Num and have different bind modes at the same time. It enables PPM users to get model match under DEVO. + +##DSM +###Sub_protocol DSM2 +Extended limits supported + +Telemetry enabled for TSSI and plugins + +option=number of channels and frame rate: + - 0 : 4 channels @22ms + - 1 : 5 channels @22ms + - 2 : 6 channels @22ms + - 3 : 7 channels @22ms + + - 4 : 4 channels @11ms + - 5 : 5 channels @11ms + - 6 : 6 channels @11ms + - 7 : 7 channels @11ms + + - 8 : 8 channels @22ms + - 9 : 9 channels @22ms + - 10 : 10 channels @22ms + - 11 : 11 channels @22ms + - 12 : 12 channels @22ms + +Value 6 is usually giving the best results with most of the RX. + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 +---|---|---|---|---|---|---|---|---|----|----|---- +A|E|T|R|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 + +Note that the RX ouput will be TAER. + +###Sub_protocol DSMX +Same as above + +##J6Pro + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 +---|---|---|---|---|---|---|---|---|----|----|---- +A|E|T|R|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 + +*** +#NRF24L01 RF Module + +##ASSAN +Extended limits supported + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10 +---|---|---|---|---|---|---|---|---|--- +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10 + +The transmitter must be close to the receiver while binding. + +##BAYANG +Models: EAchine H8(C) mini, BayangToys X6/X7/X9, JJRC JJ850, Floureon H101 ... + +Autobind protocol + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10 +---|---|---|---|---|---|---|---|---|---- +A|E|T|R|FLIP|RTH|PICTURE|VIDEO|HEADLESS|INVERTED + +##CG023 +Models: EAchine CG023/CG031/3D X4 + +Autobind protocol + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP|LIGHT|PICTURE|VIDEO|HEADLESS + +###Sub_protocol YD829 +Models: Attop YD-822/YD-829/YD-829C ... + +CH5|CH6|CH7|CH8|CH9 +---|---|---|---|--- +FLIP||PICTURE|VIDEO|HEADLESS + +###Sub_protocol H8_3D +Models: EAchine H8 mini 3D, JJRC H20/H22 + +CH5|CH6|CH7|CH8|CH9 +---|---|---|---|--- +FLIP|LIGTH|OPT1|OPT2|CAL + +JJRC H20: OPT1=Headless, OPT2=RTH + +JJRC H22: OPT1=RTH, OPT2=180/360° flip mode + +H8 3D: OPT1=RTH then press a direction to enter headless mode (like stock TX), OPT2=switch 180/360° flip mode + +CAL: calibrate accelerometers + +##CX10 +Extended limits supported + +Autobind protocol + +CH1|CH2|CH3|CH4|CH5|CH6 +---|---|---|---|---|--- +A|E|T|R|FLIP|RATE + +Rate: -100%=rate 1, 0%=rate 2, +100%=rate 3 + +###Sub_protocol GREEN +Models: Cheerson CX-10 green pcb + +Same channels assignement as above. + +###Sub_protocol BLUE +Models: Cheerson CX-10 blue pcb & some newer red pcb, CX-10A, CX-10C, CX11, CX12, Floureon FX10, JJRC DHD D1 + +CH5|CH6|CH7|CH8 +---|---|---|--- +FLIP|RATE|PICTURE|VIDEO + +Rate: -100%=rate 1, 0%=rate 2, +100%=rate 3 or headless for CX-10A + +###Sub_protocol DM007 + +CH5|CH6|CH7|CH8|CH9 +---|---|---|---|--- +FLIP|MODE|PICTURE|VIDEO|HEADLESS + +###Sub_protocol Q282 and Q242 + +CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12 +---|---|---|---|---|---|---|--- +FLIP|LED|PICTURE|VIDEO|HEADLESS|RTH|XCAL|YCAL + +Model: JXD 509 is using Q282 with CH12=Start/Stop motors + +###Sub_protocol JC3015_1 + +CH5|CH6|CH7|CH8 +---|---|---|--- +FLIP|MODE|PICTURE|VIDEO + +###Sub_protocol JC3015_2 + +CH5|CH6|CH7|CH8 +---|---|---|--- +FLIP|MODE|LED|DFLIP + +###Sub_protocol MK33041 + +CH5|CH6|CH7|CH8|CH9|CH10 +---|---|---|---|---|--- +FLIP|MODE|PICTURE|VIDEO|HEADLESS|RTH + +##ESKY + +CH1|CH2|CH3|CH4|CH5|CH6 +---|---|---|---|---|--- +A|E|T|R|GYRO|PITCH + +##FY326 + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP|RTH|HEADLESS|EXPERT|CALIBRATE + +##FQ777 +Model: FQ777-124 + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +---|---|---|---|---|---|---|--- +A|E|T|R|FLIP|RTH|HEADLESS|EXPERT + +##HISKY +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +---|---|---|---|---|---|---|--- +A|E|T|R|GEAR|PITCH|GYRO|CH8 + +GYRO: -100%=6G, +100%=3G + +###HK310 +Models: RX HK-3000, HK3100 and XY3000 (TX are HK-300, HK-310 and TL-3C) + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8 +---|---|---|---|---|---|---|--- +|||T|R|AUX|T_FSAFE|R_FSAFE|AUX_FSAFE + +##KN +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11 +---|---|---|---|---|---|---|---|---|----|---- +A|E|T|R|DR|THOLD|IDLEUP|GYRO|Ttrim|Atrim|Etrim + +Dual Rate (DR): +100%=full range, Throttle Hold (THOLD): +100%=hold, Idle Up (IDLEUP): +100%=3D, GYRO: -100%=6G, +100%=3G + +###Sub_protocol WLTOYS +###Sub_protocol FEILUN +Same channels assignement as above. + +##MJXQ +Autobind protocol + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11|CH12|CH13 +---|---|---|---|---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP|LED|PICTURE|VIDEO|HEADLESS|RTH|AUTOFLIP|PAN|TILT + +###Sub_protocol WLH08 +###Sub_protocol X600 +Only 3 TX IDs available, change RX_Num value 0..2 to cycle through them +###Sub_protocol X800 +Only 3 TX IDs available, change RX_Num value 0..2 to cycle through them +###Sub_protocol H26D +###Sub_protocol E010 +Only 1 TX ID available + +##MT99XX +Autobind protocol + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP|LED|PICTURE|VIDEO|HEADLESS + +###Sub_protocol MT +Models: MT99xx +###Sub_protocol H7 +Models: Eachine H7, Cheerson CX023 +###Sub_protocol YZ +Model: Yi Zhan i6S +Only one model can be flown at the same time since the ID is hardcoded. +###Sub_protocol LS +Models: LS114, 124, 215 + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP|INVERT|PICTURE|VIDEO|HEADLESS + +##Shenqi +Autobind protocol + +Model: Shenqiwei 1/20 Mini Motorcycle + +CH1|CH2|CH3|CH4 +---|---|---|--- + | |T|R + +Throttle +100%=full forward,0%=stop,-100%=full backward. + +##SLT +Autobind protocol + +CH1|CH2|CH3|CH4|CH5|CH6 +---|---|---|---|---|--- +A|E|T|R|GEAR|PITCH + +##Symax +Autobind protocol + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP|RATES|PICTURE|VIDEO|HEADLESS + +###Sub_protocol SYMAX +Models: Syma X5C-1/X11/X11C/X12 + +###Sub_protocol SYMAX5C +Model: Syma X5C (original) and X2 + +##V2X2 +Models: WLToys V202/252/272, JXD 385/388, JJRC H6C, Yizhan Tarantula X6 ... + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9|CH10|CH11 +---|---|---|---|---|---|---|---|---|----|---- +A|E|T|R|FLIP|LIGHT|PICTURE|VIDEO|HEADLESS|MAG_CAL_X|MAG_CAL_Y + +PICTURE: also automatic Missile Launcher and Hoist in one direction + +VIDEO: also Sprayer, Bubbler, Missile Launcher(1), and Hoist in the other dir + +##YD717 +Autobind protocol + +CH1|CH2|CH3|CH4|CH5|CH6|CH7|CH8|CH9 +---|---|---|---|---|---|---|---|--- +A|E|T|R|FLIP|LIGHT|PICTURE|VIDEO|HEADLESS + +###Sub_protocol YD717 +###Sub_protocol SKYWLKR +###Sub_protocol SYMAX4 +###Sub_protocol XINXUN +###Sub_protocol NIHUI +Same channels assignement as above. diff --git a/docs/README-old.md b/docs/README-old.md new file mode 100644 index 0000000..3d6b7ff --- /dev/null +++ b/docs/README-old.md @@ -0,0 +1,399 @@ +# Legacy Documentation + +Multiprotocol is a 2.4GHz transmitter which enables any TX to control lot of different models available on the market. + +The source code is partly based on the Deviation TX project, thanks to all the developpers for their great job on protocols. + +[Forum link on RCGROUPS](http://www.rcgroups.com/forums/showthread.php?t=2165676) for additional information or requesting a new protocol integration. + +![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7952733-114-thumb-P4100002.JPG?d=1433910155) ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7952734-189-thumb-P4100003.JPG?d=1433910159) + +**To download the latest compiled version (hex file), click on [Release](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases) on the top menu.** + +##Contents + +[Compatible TX](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#compatible-tx) + +[Protocols](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#protocols) + +[Hardware](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#hardware) + +[Compilation and programmation](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#compilation-and-programmation) + +[Troubleshooting](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#troubleshooting) + +##Compatible TX + +###Using standard PPM output (trainer port) +The multiprotocol TX module can be used on any TX with a trainer port. + +Channels order is AETR by default but can be changed in the _Config.h. + +The protocol selection is done via a dip switch, rotary dip switch or scsi ID selector. + +![Screenshot](http://media.digikey.com/photos/CTS%20Photos/206-4,%20206-4ST_sml.jpg) +![Screenshot](http://media.digikey.com/photos/Grayhill%20Photos/94HBB16T_sml.jpg) +![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8637216-7-thumb-SCSI%20ID%20selector.jpg?d=1453737244) + +You can access to up to 15 different protocols and associated settings. + +Settings per selection are located in _Config.h: + - Protocol and type: many main protocols have variants + - RX Num: number your different RXs and make sure only one model will react to the commands + - Power: High or low, enables to lower the power setting of your TX (indoor for example). + - Option: -127..+127 allowing to set specific protocol options. Like for Hubsan to set the video frequency. + - Autobind: Yes or No. At the model selection (or power applied to the TX) a bind sequence will be initiated + +###Using a serial output +The multiprotocol TX module takes full advantage of being used on a Turnigy 9X, 9XR, 9XR Pro, Taranis, 9Xtreme, AR9X, ... running [er9x](http://openrcforums.com/forum/viewtopic.php?f=5&t=4598) or [ersky9X](http://openrcforums.com/forum/viewtopic.php?f=7&t=4676). An OpenTX version for Taranis is available [here](http://plaisthos.de/opentx/). + +This enables full integration using the radio GUI to setup models with all the available protocols options. + +![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8520065-194-thumb-IMG_20151217_002215%20%28Medium%29.jpg?d=1450308588) + +Options are: + - Protocol and type: many main protocols have variants + - RX Num: number your different RXs and make sure only one model will react to the commands + - Power: High or low, enables to lower the power setting of your TX (indoor for example). + - Option: -127..+127 allowing to set specific protocol options. Like for Hubsan to set the video frequency. + - Bind: bind a RX/model + - Autobind: Yes or No. At the model selection (or power applied to the TX) a bind sequence will be initiated + - Range: test range by setting the transmission power to the lowest value + +Notes: + - Using this solution does not need any modification of the TX since it uses the TX module slot PPM pin for serial transfer. + - There are 2 versions of serial protocol either 8 or 16 channels. 16 channels is the latest and only available version going forward. Make sure to use the right version based on your version of er9x/ersky9x. + - Channels order is AETR by default but can be changed in _Config.h. + +###Telemetry + +There are 4 protocols supporting telemetry: Hubsan, DSM, FrSkyD and FrSkyX. + +Hubsan displays the battery voltage and TX RSSI. + +DSM displays TX RSSI and full telemetry. + +FrSkyD displays full telemetry (A0, A1, RX RSSI, TX RSSI and Hub). + +FrSkyX displays full telemetry (A1, A2, RX RSSI, TX RSSI and Hub). + +### If used in PPM mode + +Telemetry is available as a serial 9600 8 n 1 output on the TX pin of the Atmega328p using the FrSky hub format for Hubsan, FrSkyD, FrSkyX and DSM format for DSM2/X. + +You can connect it to your TX if it is telemetry enabled or use a bluetooth adapter (HC05/HC06) along with an app on your phone/tablet ([app example](https://play.google.com/store/apps/details?id=biz.onomato.frskydash&hl=fr)) to display telemetry information and setup alerts. + +### If used in Serial mode +Telemetry is built in for er9x and ersky9x TXs. + +To enable telemetry on a Turnigy 9X or 9XR you need to modify your TX following one of the Frsky mod like this [one](http://blog.oscarliang.net/turnigy-9x-advance-mod/). + +Note: DSM telemetry is not available on er9x due to a lack of flash space. + +Enabling telemetry on a 9XR PRO and may be other TXs does not require any hardware modifications. The additional required serial pin is already available on the TX back module pins. + +Once the TX is telemetry enabled, it just needs to be configured on the model (see er9x/ersky9x documentation). + +##Protocols + +###TX ID +The multiprotocol TX module is using a 32bits ID generated randomly at first power up. This global ID is used by nearly all protocols. +There are little chances to get a duplicated ID. + +For DSM2/X and Devo the CYRF6936 unique manufacturer ID is used. + +It's possible to generate a new ID using bind button on the Hubsan protocol during power up. + +###Bind +To bind a model in PPM Mode press the physical bind button, apply power and then release. + +In Serial Mode you have 2 options: +- use the GUI, access the model protocol page and long press on Bind. This operation can be done at anytime. +- press the physical bind button, apply power and then release. It will request a bind of the first loaded model protocol. + +Notes: +- the physical bind button is only effective at power up. Pressing the button later has no effects. +- a bind in progress is indicated by the LED fast blinking. Make sure to bind during this period. + +###Protocol selection + +####Using the dial for PPM input +PPM is only allowing access to a subset of existing protocols. +The protocols, subprotocols and all other settings can be personalized by modifying the **_Config.h** file. + +The default association dial position / protocol in every release is listed below. + +Dial|Protocol|Sub_protocol|RX Num|Power|Auto Bind|Option|RF Module +----|--------|------------|------|-----|---------|------|--------- +0|Select serial|||||| +1|FLYSKY|Flysky|0|High|No|0|A7105 +2|HUBSAN|-|0|High|No|0|A7105 +3|FRSKYD|-|0|High|No|-41|CC2500 +4|HISKY|Hisky|0|High|No|0|NRF24L01 +5|V2X2|-|0|High|No|0|NRF24L01 +6|DSM|DSM2|0|High|No|6|CYRF6936 +7|DEVO|-|0|High|No|0|CYRF6936 +8|YD717|YD717|0|High|No|0|NRF24L01 +9|KN|WLTOYS|0|High|No|0|NRF24L01 +10|SYMAX|SYMAX|0|High|No|0|NRF24L01 +11|SLT|-|0|High|No|0|NRF24L01 +12|CX10|BLUE|0|High|No|0|NRF24L01 +13|CG023|CG023|0|High|No|0|NRF24L01 +14|BAYANG|-|0|High|No|0|NRF24L01 +15|SYMAX|SYMAX5C|0|High|No|0|NRF24L01 + +Note: +- The dial selection must be done before the power is applied. + +####Using serial input with er9x/ersky9x +Serial is allowing access to all existing protocols & sub_protocols listed below. + +#####A7105 RF module +Protocol|Sub_protocol +--------|------------ +Flysky| + |Flysky + |V9x9 + |V6x6 + |V912 +Hubsan| + +#####CC2500 RF module +Protocol|Sub_protocol +--------|------------ +FrSkyV| +FrSkyD| +FrSkyX| + |CH_16 + |CH_8 +SFHSS| + +#####CYRF6936 RF module +Protocol|Sub_protocol +--------|------------ +DSM| + |DSM2 + |DSMX +Devo| +J6Pro| + +#####NRF24L01 RF module +Protocol|Sub_protocol +--------|------------ +Hisky| + |Hisky + |HK310 +V2x2| +YD717| + |YD717 + |SKYWLKR + |SYMAX4 + |XINXUN + |NIHUI +KN| + |WLTOYS + |FEILUN +SymaX| + |SYMAX + |SYMAX5C +SLT| +CX10| + |GREEN + |BLUE + |DM007 + |Q282 + |JC3015_1 + |JC3015_2 + |MK33041 + |Q242 +CG023| + |CG023 + |YD829 + |H8_3D +Bayang| +ESky| +MT99XX| + |MT + |H7 + |YZ + |LS +MJXQ| + |WLH08 + |X600 + |X800 + |H26D + |E010 +Shenqi| +FY326| +FQ777| +ASSAN| +HONTAI| + |HONTAI + |JJRCX1 + |X5C1 + +Note: +- The dial should be set to 0 for serial. Which means all protocol selection pins should be left unconnected. + +###Protocols details +**Check the [Protocols_Details.md](./Protocols_Details.md) file for a detailed description of every protocols with channels assignements.** + +##Hardware + +###RF modules +Up to 4 RF modules can be installed: +- [A7105](http://www.banggood.com/XL7105-D03-A7105-Modification-Module-Support-Deviation-Galee-Flysky-p-922603.html) for Flysky, Hubsan +- [CC2500](http://www.banggood.com/CC2500-PA-LNA-Romote-Wireless-Module-CC2500-SI4432-NRF24L01-p-922595.html) for FrSkyV, FrSkyD, FrSkyX and SFHSS +- [CYRF6936](http://www.ehirobo.com/walkera-wk-devo-s-mod-devo-8-or-12-to-devo-8s-or-12s-upgrade-module.html) for DSM, DEVO, J6Pro +- [NRF24L01](http://www.banggood.com/2_4G-NRF24L01-PA-LNA-Wireless-Module-1632mm-Without-Antenna-p-922601.html) for Hisky, V2x2, CX-10, SYMAX and plenty other protocols + +RF modules can be installed for protocols need only. Example: if you only need the Hubsan protocol then install only a A7105 on your board. + +You also need some [antennas](http://www.banggood.com/2_4GHz-3dBi-RP-SMA-Connector-Booster-Wireless-Antenna-Modem-Router-p-979407.html) and [cables](http://www.banggood.com/10cm-PCI-UFL-IPX-to-RPSMA-Female-Jack-Pigtail-Cable-p-924933.html). + +###Board +The main program is running on an ATMEGA328p running @16MHz and 3.3V. +An [Arduino pro mini 16Mhz/5V](http://www.banggood.com/Wholesale-New-Ver-Pro-Mini-ATMEGA328-328p-5V-16MHz-Arduino-Compatible-Nano-Size-p-68534.html) powered at 3.3V (yes it works) can be used to build your own Multimodule. An Arduino Mini based on Atmega328p can also be used. + +####Using stripboard: + +![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t8214655-87-thumb-uploadfromtaptalk1405598143749.jpg?d=1441459923) +![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t8214656-102-thumb-uploadfromtaptalk1405598152484.jpg?d=1441459924) + +####Using a [home made PCB](http://www.rcgroups.com/forums/showpost.php?p=32645328&postcount=1621): + +![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8226720-197-thumb-IMG_20150715_230603155.jpg?d=1441816457) +![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8226719-72-thumb-IMG_20150715_230024065.jpg?d=1441816456) + +####Build your own board using [SMD components](http://www.rcgroups.com/forums/showpost.php?p=31064232&postcount=1020) and an [associated PCB v2.3c](https://oshpark.com/shared_projects/MaGYDg0y): + +![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7566755-3-thumb-i.png?d=1423810885) +![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7952726-108-thumb-image-62c29cf2.jpg?d=1433909893) +![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7952733-114-thumb-P4100002.JPG?d=1433910155) ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/t7952734-189-thumb-P4100003.JPG?d=1433910159) + +If you build this PCB v2.3c and want to enable serial mode for er9x/ersky9x, you have to do [this mod](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8667856-242-multi.jpg). + +**[New PCB v2.3d!](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/tree/master/PCB%20v2.3d) available** + +Repository includes Kicad files of schematic and pcb. This is a variant of the Multipro V2.3c circuit design. It is basicly the same as the 2.3c board as far as component placement goes. What's changed is the added resistors for the serial protocol and also +the addition of solder jumpers on the bottom of the board for the various options to connect the TX, RX, and PPM +lines through them. + +![Screenshot](https://644db4de3505c40a0444-327723bce298e3ff5813fb42baeefbaa.ssl.cf1.rackcdn.com/b637193364a5e228dc8ab6ad90c0ca3c.png) +![Screenshot](https://644db4de3505c40a0444-327723bce298e3ff5813fb42baeefbaa.ssl.cf1.rackcdn.com/97b87a89b75785d70b354e5b033f5209.png) + +[OSH Park link](https://oshpark.com/shared_projects/Ztus1ah8) if you want to order. + +####Buy a ready to use and complete Multi module +![Screenshot](http://img.banggood.com/thumb/view/oaupload/banggood/images/1D/EB/19bb6434-4616-411e-b8fa-a4c21d9dca24.jpg) + +This module can be purchased [here](http://www.banggood.com/2_4G-CC2500-A7105-Flysky-Frsky-Devo-DSM2-Multiprotocol-TX-Module-With-Antenna-p-1048377.html). All the 4 RF modules are already implemented A7105, NRF24L01, CC2500 and CYRF6936. The board is also equiped with an antenna switcher which means only one antenna for all. + +**It is highly recommended to update the firmware** of this board as it is distributed with a really old and bugged one. For this you have to solder a 6 pin header (top left) and use an USBASP like explained [below](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#upload-the-code-using-isp-in-system-programming). + +If you want to enable serial mode for er9x/ersky9x/Taranis/... and depending on your board revision, you have to do one of these modifications: +- 1st revision, add 2 resistors as shown here: ![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8895038-170-4in1%20module.jpg) +- 2nd revision, solder pads together as shown: + + + +Note: if you have the 1st board revision (check pictures above), sometime bind occures at power up even without pressing the bind button or not having an autobind protocol. To solve this issue, replacing the BIND led resistor (on the board back) of 1.2K by a 4.7K. + +###Schematic +![Screenshot](http://static.rcgroups.net/forums/attachments/4/0/8/5/8/3/a8443844-119-multiprotocol_diagram_rotary_serial_2.jpg) + +Notes: +- Attention: All modules are 3.3V only, never power them with 5V. +- For serial, the dial switch is not needed and the bind button optionnal + +###Radio integration +If you build your own version of the board you can 3D print this case (details [here](http://www.rcgroups.com/forums/showpost.php?p=33294140&postcount=2034)): + +![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8462144-54-thumb-Multi_case_9XR.jpg?d=1448575289) +![Screenshot](http://static.rcgroups.net/forums/attachments/1/1/5/4/3/7/t8462145-106-thumb-Multi_case_v1.jpg?d=1448575293) + +If you have the Banggood ready to use board you can 3D print this case (details [here](http://www.rcgroups.com/forums/showpost.php?p=35349049&postcount=3)): + + + + + +##Compilation and programmation + +###Toolchain +Multiprotocol source can be compiled using the Arduino IDE. + +The currently supported Arduino version is [1.6.10](https://www.arduino.cc/download_handler.php?f=/arduino-1.6.10-windows.exe). + +Download the [zip file](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/archive/master.zip) of this repository, unzip it in a folder, navigate to the Multiprotocol directory and then click on Multiprotocol.ino. The Arduino environment will appear and the Multiprotocol project will be loaded. + +**[_Config.h file](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/blob/master/Multiprotocol/_Config.h) must be modified** to select which protocols will be available, change protocols/sub_protocols/settings associated with dial for PPM input, different TX channel orders and timing, Telemetry or not, ... +This is mandatory since all available protocols will not fit in the ATmega328. You need to pick and choose what you want. + +Notes: +- Make sure to select "Arduino Pro or Pro Mini, ATmega328 (5V,16MHz)" before compiling. +- Compilation of the code posted here works. So if it doesn't for you this is a problem with your setup, please double check everything before asking. +- If you want to reduce the code size even further, you can modify the file platform.txt located in "C:\Program Files (x86)\Arduino\hardware\arduino\avr". Set the line "compiler.c.elf.extra_flags=" to "compiler.c.elf.extra_flags=-Wl,--relax". + +###Upload the code using ISP (In System Programming) +It is recommended to use an external programmer like [USBASP](http://www.banggood.com/USBASP-USBISP-3_3-5V-AVR-Downloader-Programmer-With-ATMEGA8-ATMEGA128-p-934425.html) to upload the code in the Atmega328. The programmer should be set to 3.3V or nothing to not supply any over voltage to the multimodule and avoid any damages. + +The dial must be set to 0 before flashing! + +From the Arduino environment, you can use this shortcut to compile and upload to the module: Skecth->Upload Using Programmer (Ctrl+Maj+U) + +To flash the latest provided hex file under [Release](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases), you can use a tool like [AVR Burn-O-Mat](http://avr8-burn-o-mat.aaabbb.de/), set the microcontroller to m328p and flash it. + +###Upload the code using FTDI (USB serial to TTL) +Use this method only for Arduino Pro Mini boards with bootloader. + +Use an external FTDI adapter like [this one](http://www.banggood.com/FT232RL-FTDI-USB-To-TTL-Serial-Converter-Adapter-Module-For-Arduino-p-917226.html). + +The programmer should be set to 3.3V or nothing to not supply any over voltage to the multimodule and avoid any damages. + +From the Arduino environment, you can use Upload button which will compile and upload to the module: Skecth->Upload (Ctrl+U) + +To upload the latest provided hex file under [Release](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/releases), you can use a tool like [XLoader](http://russemotto.com/xloader/), set the microcontroller to Atmega328 and upload it. + +###Set fuses +Use a tool like [AVR Burn-O-Mat](http://avr8-burn-o-mat.aaabbb.de/) to set the fuses of the Atmega328 to: +- Extended Fuse 0x05 (or 0xFD which is the same) +- High Fuse 0xD2 +- Low Fuse 0xFF + +This will make sure your ATMEGA328 is well configured and the global TX ID is not erased at each updates. + +##Troubleshooting + +###LED status +- off: program not running or a protocol selected with the associated module not installed. +- flash(on=0.1s,off=1s): invalid protocol selected (excluded from compilation or invalid protocol number) +- slow blink(on=0.5s,off=0.5s): serial has been selected but no valid signal has been seen on the RX pin. +- fast blink(on=0.1s,off=0.1s): bind in progress. +- on: normal operation. + +###Protocol selection +####Input Mode - PPM +- The protocol/mode selection must be done before the power is applied. +- Connect 1 to 4 of the selection protocol pins to GND. + +####Input Mode - Serial +- Make sure you have done the mods to the v2.3c PCB by adding the 2.2k and 470 ohm resistors as indicated in the [Board section] (https://github.com/pascallanger/DIY-Multiprotocol-TX-Module#board). +- Leave all 4 selection pins unconnected. + +###Bind +Make sure to follow this procedure: press the bind button, apply power and then release it after 1sec. The LED should be blinking fast indicating a bind status and then fixed on when the bind period is over. It's normal that the LED turns off when you press the bind button, this behavior is not controlled by the Atmega328. +For serial, the preffered method is to bind via the GUI protocol page. + +If your module is always/sometime binding at power up without pressing the button: + - Arduino Pro Mini with an external status LED: to work around this issue connect a 10K resistor between D13 and 3.3V. + - 4in1 module V1 (check 4in1 pictures): to solve this issue, replacing the BIND led resistor (on the board back) of 1.2K by a 4.7K. + +###Report issues +You can report your problem using the [GitHub issue](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/issues) system or go to the [Main thread on RCGROUPS](http://www.rcgroups.com/forums/showthread.php?t=2165676) to ask your question. +Please provide the following information: +- Multiprotocol code version +- TX type +- Using PPM or Serial, if using er9x or ersky9x the version in use +- Different led status (multimodule and model) +- Explanation of the behavior and reproduction steps diff --git a/docs/Transmitters.md b/docs/Transmitters.md new file mode 100644 index 0000000..a89a48c --- /dev/null +++ b/docs/Transmitters.md @@ -0,0 +1,59 @@ +# Compatible Transmitters + +Any Tx that provides a PPM output (like a trainer port, or a RF module bay) is compatible with the DIY Multiprotocol module. In practice, most of the documentation on this site is focused on building modules that slip into your transmitter’s module bay. +{insert picures of different modules} + +There are two different options for the interface between the Mulitprotocol Module and the transmitter: PPM and Serial. The considerations are different for each. +- **PPM** is more generic, easy to implement and will work with most transmitters. +- **Serial** requires custom firmware on the transmitter but brings added functionality including telemetry and protocol selection through the Tx interface + +##PPM +The DIY Mulitprotocol module supports industry standard PPM interface that works with all transmitters with either a module bay, and/or a trainer port. Even the older 72MHz FM radios support this standard. + +When using the standard PPM Tx output, the protocol selection is achieved through a 16 position rotary switch on the module. This enables 15 protocol/sub-protocol/options combinations to be selected. Binding is achieved by pressing a bind button on the back of the module (see picture below) + + + +Since the module supports literally hundreds of protocol/sub-protocol/options combinations, you must select which of these will map to the 15 positions on the switch. Refer to the [Compiling and Programming](Compiling.md) page for information on how to do his. + +Telemetry is available as a serial 9600 8 n 1 output on the TX pin of the Atmega328p using the FrSky hub format for Hubsan, FrSkyD, FrSkyX and DSM format for DSM2/X. + +You can connect it to your TX if it is telemetry enabled or use a bluetooth adapter (HC05/HC06) along with an app on your phone/tablet ([app example](https://play.google.com/store/apps/details?id=biz.onomato.frskydash&hl=fr)) to display telemetry information and setup alerts. + +For transmitter setup using the PPM protocol go to the [PPM Setup page](PPM_Setup.md) + +##Serial +Transmitters that run er9X, erSky9X or OpenTx firmwares - like the FrSky Taranis and FlySky TH9X/Turnigy 9X/R family of transmitters - have the option of using a fast, two-way serial, communication protocol between the Tx and the DIY Multiprotocol module. Using this serial communication protocol has some significant advantages: + +1. selecting the specific radio protocol (e.g. DSM) and the sub protocol (e.g. DSMX) directly in the menu system of the Tx (see the picture below) +1. binding through the menu on the Tx +1. range checking through the menu on the Tx +1. enabling two-way telemetry for telemetry capable receivers and protocols. + + + + +This serial protocol does not require any hardware modifications, but **will** require updating the firmware on your radio. + +Transmitters and firmware combinations that support the Serial protocol are: + +{Can someone check the transmitters click through to the right pages? How should the "erSky9x" boards be handled? A separate Tx- page or a link to the Taranis page?} + +Transmitter|Firmware Options +:----------|:------- +[FrSky Taranis/Plus/9XE](Tx-Taranis.md)| [erSky9x](http://www.er9x.com), [OpenTx 2.1.8 Multi](http://plaisthos.de/opentx/) +[Turnigy 9X/9xR](Tx-FlyskyTH9X.md)|[er9x](http://www.er9x.com) +[Turnigy 9XR-Pro](Tx-Taranis.md)|[erSky9x](http://www.er9x.com) +[FrSky TH9x](Tx-FlyskyTH9X.md)|[er9x](http://www.er9x.com) +SKY board|[erSky9x](http://www.er9x.com) +AR9X board|[erSky9x](http://www.er9x.com) +9Xtreme board|[erSky9x](http://www.er9x.com) +AR9X UNI board|[erSky9x](http://www.er9x.com) + +Click on your transmitter above to view specific setup instructions. + +Other Notes: +- er9X and erSky9X firmware already supports Multiprotocol Module as a standard feature. At time of writing it looks like that the next major release of OpenTx - OpenTx 2.2 - will have DIY Mulitprotocol support as a standard feature. + +- Owners of Walkera Devo transmitters should look at the [Deviation-Tx](http://www.deviationtx.com) project for how to achieve the same end goal with your transmitters. + diff --git a/docs/Troubleshooting.md b/docs/Troubleshooting.md new file mode 100644 index 0000000..85e3508 --- /dev/null +++ b/docs/Troubleshooting.md @@ -0,0 +1,40 @@ +# Troubleshooting + +##LED status +###Green LED +- Off: no power to the module +- On: module is powered up + +###Red LED (bind LED) +- Off: program not running or a protocol selected with the associated module not installed +- Flash(on=0.1s,off=1s): invalid protocol selected (excluded from compilation or invalid protocol number) +- Fast blink(on=0.1s,off=0.1s): bind in progress +- Slow blink(on=0.5s,off=0.5s): serial has been selected but no valid signal has been seen on the RX pin. +- On: Module is in normal operation mode (transmitting control signals). + +##Protocol selection +###Input Mode - PPM +- The protocol/mode selection must be done before the power is applied +- Check the Green LED to see when power is applied. Often power is not applied to the module until the transmitter has performed safety checks (like switch and throttle position settings) +- Check that at least one of the protocal selection to GND. + +###Input Mode - Serial +- Make sure you have done the mods to the v2.3c PCB by adding the 2.2k and 470 ohm resistors as indicated in the [hardware page for your board] (Hardware.md). +- Protocol selection dial must be in the 0 position or leave all 4 selection pins unconnected. + +##Bind +Make sure to follow this procedure: press the bind button, apply power and then release after the red LED starts flashing. The LED should be blinking fast indicating a bind status and then fixed on when the bind period is over. It's normal that the LED turns off when you press the bind button, this behavior is not controlled by the Atmega328. +For serial, the preffered method is to bind via the GUI protocol page. + +If your module is always/sometime binding at power up without pressing the button: + - Arduino Pro Mini with an external status LED: to work around this issue connect a 10K resistor between D13 and 3.3V. + - 4in1 module V1 (check 4in1 pictures): to solve this issue, replacing the BIND led resistor (on the board back) of 1.2K by a 4.7K. + +##Report issues +You can report your problem using the [GitHub issue](https://github.com/pascallanger/DIY-Multiprotocol-TX-Module/issues) system or go to the [Main thread on RCGROUPS](http://www.rcgroups.com/forums/showthread.php?t=2165676) to ask your question. +Please provide the following information: +- Multiprotocol code version +- TX type +- Using PPM or Serial, if using er9x or ersky9x the version in use +- Different led status (multimodule and model) +- Explanation of the behavior and reproduction steps diff --git a/docs/Tx-FlyskyTH9X.md b/docs/Tx-FlyskyTH9X.md new file mode 100644 index 0000000..1d7e7a5 --- /dev/null +++ b/docs/Tx-FlyskyTH9X.md @@ -0,0 +1,37 @@ +#Flysky TH9X family of transmitters +This page is relevant to the following transmitters: +* FlySky TH9X +* Turnigy 9X, Turnigy 9XR +* EURGLE + + +## Features +The DIY Multiprotocol module can be used in the Flysky family of transmitters in either PPM mode or in Serial mode. To operate in Serial mode, a version of er9X supporting the DIY Multiprotocol must be installed on the Tx. If your transmitter is running an earlier firmware that is not Serial enabled, and if you wish to run in Serial mode jump down to the section [Enabling Serial Mode] + +## PPM Mode +Please refer to the [PPM Setup](PPM_Setup.md) page. + + +## Serial Mode +Serial mode is only supported by the er9X firmware. Loading this firmware is beyond the scope of this document but it is well covered in tutorial and video tutorials online. +###Enabling Serial Mode +1. Confirm that the DIY Multiprotocol module has the required physical connections between the pins on the back of the Tx and the ATMega328 microprocessor. This may require some soldering and depends on which version of the DIY Multiprotocol module you have. Check out your module’s hardware page under the section [Enabling your module for Serial](### insert link) for details. +1. Plug in your DIY Multiprotocol module into the transmitter module bay. If you have a rotary protocol selection switch, turn the switch to position 0 to put the unit into Serial mode. +1. Ensure throttle is down and all switches are in the start position and power up the Tx. The red LED on the DIY Multiprotocol module should be flashing with a period of about 1 second indicating that it has not established a valid serial link with the Tx. This is expected as we have not set up the Tx yet. +1. {er9x expert to review this} Create a new model +1. In the Model Settings menu scroll down to change the RF settings to {pascal mikeb! }. Your transmitter settings should look like this: {mikeb insert picture of er9X screen showing RF settings} +1. The red LED on the DIY Multiprotocol module should briefly flash and then go off. This confirms that the DIY Multiprotocol module has established serial communication with the Tx. If the red LED on the module continues to flash at a period of about 1 seconds then it signals that serial communication has not been established. Check your settings under the model menu as described above and check that the protocol selection switch on the module is at 0 (enable Serial mode). If there is still no communication, power down and power up the Tx. Finally check that you have correctly enabled your module for serial as described on the hardware page for your module under the heading [Enabling your module for Serial](### insert link) + +###Protocol Selection in Serial mode +To select the protocol: + 1. In the Model Setting menu, scroll through the available options under the MULTI option {mikeb to confirm}. + 1. Depending on which protocol you have selected you may be required to select a sup-protocol and options. For example, the DSM protocol has two sub-protocols DSM2 and DSMX. Each of these sub-protocols have options that specify the number of channels and the packet frame rate. The following picture shows DSM – DSMX – Option 6 (6 channels and 11ms frame rate). Check out the [Protocol Details](###) page for detailed information and suggestions regarding the sub-protocols and options. {insert picture mentioned above} + +###Binding in Serial mode +1. Switch on the model or put the receiver into bind mode +1. On the transmitter go to the Model Settings menu and scroll down to the [Bind] menu option and press Enter. +1. Press Enter again to exit Bind mode + +For many consumer models consider checking the Autobind option. This will initiate the bind sequence as soon as the module is powered up by the transmitter. + +If you are struggling to get a bind please see the [Getting the bind timing right page](Bind_Timing.md) diff --git a/docs/Tx-NewTrasmitter.md b/docs/Tx-NewTrasmitter.md new file mode 100644 index 0000000..10d7fa8 --- /dev/null +++ b/docs/Tx-NewTrasmitter.md @@ -0,0 +1,43 @@ +# Transmitter Setup +Describe the transmitters this applies to. + +Describe the firmware required for the transmitters. The transmitters covered here are: +1. [tx1](###) +1. [tx2](###) + +Does it work in PPM and/or Serial mode? + +## PPM Mode +Please refer to the [PPM Setup](PPM_Setup.md) page. + + +##Serial mode +###Enabling Serial Mode +To operate in serial mode, you need one of these firmwares: +1. OpenTx supporting the DIY Multiprotocol mdule (2.18 Multi or 2.2) +1. erSky9x + +Check and upload a supported firmware. The latest available version at time of writing are: +- OpenTx 2.1.8 Multi and the hex files are available [here](http://plaisthos.de/opentx/) +- erSky9x Revision 218 and the hex files are available [here](http://www.er9x.com). + +Tutorials for uploading new firmware using the SD Card are available [here](http://www.dronetrest.com/t/how-to-upgrade-firmware-for-frsky-taranis-x9d/959) or the CompanionTx software (recommended) are available [here](http://open-txu.org/home/undergraduate-courses/fund-of-opentx/part-2-flashing-opentx/). + +**Note: in the tutorials substitute the shown firmwares with the fimware donwloaded from the links above.** + +First confirm that the DIY Multiprotocol module has the required physical connections between the pins on the back of the Tx and the ATMega328 microprocessor. This may require some soldering and depends on which version of the DIY Multiprotocol module you have. Check out this [Enabling Your Module for Serial] page for details. + +Plug in your DIY Multiprotocol module into the Taranis module bay. If you have a rotary protocol selection switch, turn the switch to position 0 to put the unit into Serial mode. Ensure throttle is down and all switches are in the start position and power up the Taranis. The red LED on the DIY Multiprotocol module should be flashing with a period of about 1s indicating that it has not established a valid serial link with the Tx. This is expected as we have not set up the Tx yet. + +Create a new model (make sure channel order is AETR) and on the first Model Settings page scroll down to disable the internal RF and enable the external RF by selecting MULTI as the external RF. Your Taranis settings should look like this: {insert picture of Taranis screen showing external RF settings} + +The Red LED on the DIY Multiprotocol module should briefly flash and then go off. This confirms that the DIY Multiprotocol module has established serial communication with the Tx. If the red LED on the module continues to flash at a period of about 1s then it signals that serial communication has not been established. Check your settings under the model menu as described above and check that the protocol selection switch on the module is at 0 (zero). If there is still no communication, power down and power up the Tx. Finally check that you have correctly enabled your module for serial as described here [Enabling Your Module for Serial] +###Protocol Selection in Serial mode +To select the protocol, scroll through the available options under the Model Settings menu. Depending on which protocol you have selected you may be required to select a sup-protocol and options. For example, the DSM protocol has two sub-protocols DSM2 and DSMX. Each of these sub-protocols have options that specify the number of channels and the packet frame rate. + +The following picture shows DSM – DSMX – Option 6 (6 channels and 11ms frame rate). Check out the [Available Protocols] page for detailed information and suggestions regarding the sub-protocols and options. +###Binding in Serial mode +1. Switch on the model or put the receiver into bind mode +1. On the transmitter go to the Model Settings menu and scroll down to the [Bind] menu option. + + diff --git a/docs/Tx-Taranis.md b/docs/Tx-Taranis.md new file mode 100644 index 0000000..4562576 --- /dev/null +++ b/docs/Tx-Taranis.md @@ -0,0 +1,49 @@ +# FrSky Taranis Setup +This page contains setup instructions for the FrSky Taranis family of transmitters. These include the Trananis X9D, Taranis X9D Plus and Taranis X9E. It may also be relevant to the following transmitters: Turnigy 9XR Pro, Sky board-based, AR9X board-based, 9Xtreme board-based and AR9X Uni board-based. + + + + +The instructions below are relevant to the following firmwares: + 1. Taranis with erSky9X available [here](http://www.er9x.com) + 1. Taranis with OpenTx available [here](http://plaisthos.de/opentx/) + + +The DIY Multiprotocol module can be used with all transmitters and firmwares in PPM mode. Taranis transmitters running erSky9X or OpenTX (Version 2.1.8 Multi or Version 2.2) fully support Serial mode. +## PPM Mode +Please refer to the [PPM Setup](PPM_Setup.md) page. + +##Serial mode +###Enabling Serial Mode +To operate in serial mode, you need one of these firmwares: + 1. erSky9x + 1. OpenTx supporting the DIY Multiprotocol Module (Version 2.18 Multi or Version 2.2) + +Check and upload a supported firmware. The latest available version at time of writing are: + - erSky9x Revision 218 and the hex files are available [here](http://www.er9x.com). + - OpenTx 2.1.8 Multi and the hex files are available [here](http://plaisthos.de/opentx/) + +Tutorials for uploading new firmware using the SD Card are available [here](http://www.dronetrest.com/t/how-to-upgrade-firmware-for-frsky-taranis-x9d/959) or the CompanionTx or eepe software (recommended) are available [here](http://open-txu.org/home/undergraduate-courses/fund-of-opentx/part-2-flashing-opentx/). + +**Note: In these tutorials, substitute the firmwares from the links to the supported firmwares above.** + +First, confirm that the DIY Multiprotocol module has the required physical connections between the pins on the back of the Tx and the ATMega328 microprocessor. This may require some soldering and depends on which version of the DIY Multiprotocol module you have. Check out the specific pages for your module hardware (under the section "Enabling Serial") linked [here](Hardware.md) for details. + + 1. Plug in your DIY Multiprotocol module into the Taranis module bay. + 2. If you have a rotary protocol selection switch, turn the switch to position 0 to put the unit into Serial mode. + 2. Ensure throttle is down and all switches are in the start position and power up the Taranis. The red LED on the DIY Multiprotocol module should be flashing with a period of about 1s indicating that it has not established a valid serial link with the Tx. This is expected as we have not set up the Tx yet. + 3. Create a new model (make sure channel order is AETR) and on the first Model Settings page scroll down to disable the internal RF and enable the external RF by selecting MULTI as the external RF. Your Taranis settings should look like this: {insert picture of Taranis screen showing external RF settings} The Red LED on the DIY Multiprotocol module should briefly flash and then go off. This confirms that the DIY Multiprotocol module has established serial communication with the Tx. + 4. If the red LED on the module continues to flash at a period of about 1s then it signals that serial communication has not been established. Check your settings under the model menu as described above and check that the protocol selection switch on the module is at 0 (zero). If there is still no communication, power down and power up the Tx. Finally check that you have correctly enabled your module for serial as described in specific pages for your module hardware (under the section "Enabling Serial") linked [here](Hardware.md) + +###Protocol Selection in Serial mode +To select the protocol, scroll through the available options under the Model Settings menu. Depending on which protocol you have selected you may be required to select a sup-protocol and options. For example, the DSM protocol has two sub-protocols DSM2 and DSMX. Each of these sub-protocols have options that specify the number of channels and the packet frame rate. + +The following picture shows DSM – DSMX – Option 6 (6 channels and 11ms frame rate). Check out the [Protocol Details](Protocol_Details.md) page for detailed information and suggestions regarding the sub-protocols and options. +###Binding in Serial mode +1. Switch on the model or put the receiver into bind mode +1. On the transmitter go to the Model Settings menu and scroll down to the [Bind] menu option and press Enter. +1. Press Enter again to exit Bind mode + +For many consumer models consider checking the Autobind option. This will initiate the bind sequence as soon as the module is powered up by the transmitter. + +If you are struggling to get a bind please see the [Getting the bind timing right page](Bind_Timing.md) diff --git a/docs/images/4-in-1_Module_BG.jpeg b/docs/images/4-in-1_Module_BG.jpeg new file mode 100644 index 0000000000000000000000000000000000000000..7e05cdbe88db04505fdcf6ea6b61789484e43d6f GIT binary patch literal 12323 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 z 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%0D4oazcG-wU%TpI$lbd0(0IV0UK(!Cq&>HP=y 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�krTBbffxPkz|^hkyUqY%y~m+)>j_Kf#3k(@#Eb{@dUE zZS(#IA7CYM*etKEH1B=ydzhhLPa8<%T^H(BHYZ1ixvDwE90TvaPqIE-9N*r?IT*t4 z66UsA(2Pc9TO}umLT~Md6uL~p6oFEFR-i7HKumHlnImp`l#7BtwZ(&G?qT3bTVdBp zF`Ae1vxOCF(f9WdN-49J7S_XXxWLvrgkvJiwWA85W5S9m7c3^O+s#|K9zaj~_o_{3*(Z@O{u~!yYl~xr3K-HLNFC z3+Z6V{7qlHtjjpEuAOv4FWdAhZQ*ftyyhC138=5RLTAZ+^BO2)nq(!zSuT>9LV!%y zZ&!!J!*vFFB9tl2EHi;6ED{w7huXdz-g6@};?=k^y$YyRxOI&}(qYt2T+&gXRlA|{ zni2Ohdxha}mJK}-=~TEXG4om4THuD5hR8X~Ox`VQnyOhq84F>p#MrSqkxjKEko0q( zPY(7Zp8xiq_c;h}xLQlXkPsz!@|ff^NuxsFCXxCsb#4JntEOj&l3uA_VINw4Ogl|i zV$zMXp8|*BzwM)z$9%lEE^|`Xsn_Yc<-1`fr*U2au%u@g(@UytsCJM{z4@Is0~aRw zk&o-XvV{gr+#F2a7-8r9`~)GTY}vBFfI25r7RC%56GoU~Fry5*3a6T(qN#^PMiZ$} zC({Owu5307Yn-gVL`TzHjNBg-vsTyI4cD8~(L%G2DepYnw{+JOkPv>C)|ePs0bkMj z6KBMJjRPFEoFn`kF-U8!d_KbIQioaN4km|aM9(aF$fSgVF0+JkW) zu;!I+ka}afhHsbv0`sNXnv}%;Ww{g#;eNA5nG(X}k}O-_kSAIbYy%M_b@`9^?#Ws6 zfScS2nzN3LdfU#Y3@XkJIPp~_dlAA{9 z6^7HCG~3kh%4bc%u3g*Cdek$tZ-e1QvpQsNO|()@jVl3FCLHbTKdxe@j{sVyO$m>g4E@{esWW_J}vY zao5e}um0lSHUIv9`JbA<{vZFcdGr3ZV5dGV(41e#>6q(FxA89RTJ1F)G=2XEKVVCq z>k-byJGI0;!fLi&gw&H}jU^>iZ_}F}vc1K1y2=}I7&gbG)&+g@jJ|ww!q^itVQEcE zZzzLfO6UmnrHSmN4NDza2hybgC_+&l58FJ#X|1}{3GcxD5rStAs|6=Yx|rB^GbyAE z1fG}2dh?yqXi|@AurekxxkPrR)aFB8!ZCFKP5$h6fh~CBm`70H^b9hPhFj5y2c}uV zimxxGHtawgVEngk{K>c7#y6%Mym&-Q5VQI&gDKuzF07^Y*=$ zj|#)f?`O|{SPfjYz#o>*EcUDhUPBE?Y-E0>2vkP4N`&|jGF8Gz6kIpz44I6Sf~JSe zle7JGY%2q~13DDU#5uf|2)S6^cn*kVotQ*V0RtwM_X@ER!ZA#ST7@xMBf~k9=9U5F zdoeLKj>B=7hc*v2HKCZLP$9k{b~1Z>@!q@(;Y~>1a)cTeI1BL;cK`E}I5I3%NHUE! zijhhhhUWdN&PiHr$dZTo*0|I|`|ah6aGPc=2XaTA9W1H`y_e&>>e)12bxdG+)koe< zm&YKJX9`uBxG=?*-R}nCC~!}OH~+xkwGG2H<*x62?F;d+rp7n(sTz85P4m66o_E0= z*NQ!OaF;0J3G3O;j+9kKLz@>0LBk3Od}}(uRu`0!;~5;{ijGSGI&0_R?)4LR@v-+h4qUb zI>OTY8KPswkT|sz`b9nSZ#LGAbWm^AS+k`e<@((Io6Sg!s zH^fMrmuB|2;3h8(PrT{l|uUDeYj@M8FGXeEARN^d&*Ixr6O(8I$Mj=#?1TvEFNQVlMP*7Bh>NQLV zLCSz8wYoYc1f?Y`GBgU8Wu_meNUDW6%)zkPLyzxjSbMFeRKeGow=oQkCV=zv?48JW z*D{#5LdQIWF#;+H6{e}c5fdx{w7}fx z5W>i4wMR{c0AC85xaMXck|6ubSz3BvdrafD%E<+7rz_0hD*Hiz2s{JczOVfX9U#tO&dR2BpLL!+_3fF z1*YF<$~M_!6c!Sp2Xi>KTG`uWP`p6UgdtTU>cCi-dvYKRg$3g)?7@m6@W24#lXNfguBfN-?(JZP#?V;Vg z$d)XoClhMTs0mTf($w4aZ}b5eSgY<*;e{Gt)m;Sj0co7#G4ue3EXQXErU(E*~+GiQ;QMWE(OwM_NH{pnR&FIn)14?)pd+3G8_EK zGlx$Hz?hQSC(@L*p-jE&+z_5H3tnbl%XuahqDds&r9!pq;?#HrCxFp*&waThDas|D zIKh>zWn6CxJyCejeAIPMH*el#-P7IXgO5IpgDJmt@xrVSA1$THl1UX%r9%p+<~7kG z6?98px#e^1cY&z_(*kIE748UKfwLr1-g|FhJWJ$seQzr~&^2kBxb0-q25U8!5P&pK zRcQ6SM<(qMIIO#*c9kUM)8WukCJ!S#3AZO973>tBB1Dl^L?3X;a#^P>R0&_+7TEmY zHq^1?oC%=;CiG5p4*OU{0NXM3d33zX+TK0t`m$MF2To1A=_^Z2D%m$Y=lG^WG5eb9 zwt}scj??| z*DJiS-kofqKhtWEJm4Tbo~Sio+J_amT6!?bvD9riqYqx4G43zurBK|RC_Upi9wxRQS1EeqW$w8g&DVrz?!_4!Y| z{{NWZp9!dcOs(;qheh(!9ukL|;RHC=pnHG}*4^<|b}a{4eiWo;S^15CN*VV-j^2F}*YYbCkjP3TlIua4&?ie(GtwHh~F|tly@tM3}^}a;;(WxpHa|0NNkF zIV6!)qmLgQHUqqh4o=tEe-TX&Y<`bH_Wk!i$Mk%N zqiveE<4 z#Hckyn8tMX=wyg1{~o4Pm@cw5cEolx%P{oocpvWKC3Jws_6YBw_+dhTRf|hqYG$Rz zM%6LUD43}2)U;Pq!#>*rba|e~{CN?9_X4f6>7rVtnSql(aj@d8CfH*fFu4Va<(VTN z8Gf06wXj6YpWsj9Zt$cuGhh6M2{rBLo}gRX+h_}yV`1T*p>=D6`}gm$u5ddu@_p*w zW0~!8oES@A0bkVCn%FWLM}-#GDn@`XFU|@>DMNh@_K3m>R4y$B^U|0X&U>%KIGjbyKi*Bb4|=a-OCwZO|!LaTHaw zug0?u75xCsCC8G6F$|_u>5g-ecdBKlQwrBRW1`k4R2(HjC{Z(7<1cS__ z>&lGb+Fyl#Ve;9xo?&pkdYFde0h2?Qn5+-jI;qz`&i0~hG9dJ>HFmx^I$Z?c+rqa&zh%ZinS!=#e8?_A` zj7x98~-mQIBC zDvj`%#=+2P-qmjjF#CCJH82xUUt3kq5_-Kg;BYuS7;#^xXWNW2=7l)Ppp^59U@>en z0LD|OOf-tfz2~T>GwwAmVf(HYTa1f?wS)Fa;K5J1Ku$_f-5QnaXv2zOx z&EH07f(kR_fL}DR=3)5a$(Q^gd=XrEUrh4ITc(F+fhe=jmB@NEKkLFekU)Cz*(e3- zTJF5$$FIhDA+7o`-;+oZi(?BTl%z^z!$u&p9olc?mDz6KFJ^P4juf(@8RC6~$0*tdR$Et-kg3yDK?0O8)@iMZQg+$mdUwU*%B(wJGC1+0 zwk}L7-Yw_QV(5^>@l11Aw_|X?>m%^#wbwluWjgr^P7#eXY-81b^Mqf}L05zJ6wPNg z4Iiz4?t?cwiMLj4fufTiff+ zCg(isa6?N;!?l`y*0JsG9yE`i?%;6gI9l^AX7?j-?gBiwtu^~rAbj@hY4eZ2{DhtF4kaegCscx^d!In=0yjVYe{Fr{hUae|$+=7ZdNlmNQQ!9)m2Jng-I-KgW zPTYwhC{6k_7#(I@*lEQGsIJ-8wAbpJ(=x#LE+I%d^gWpOF{Zp~P~E?o4nyS@n&dJA zfCF}}IC5g~9TUDz*so4y_T`VI2GaVreXywDLV-=J;s|0D{0J|?KpNZ;9~pa$ zA$~f6>BNUyh&gfSgyGuidM1OU*C1B}RIggO=p^Y7M`zg&l{BPbm7gQX3;0-ZPH<+& zw^IW%0rlId*IBB6Pz@BupWi|dCTZ2tE_7w`)I8Td+lDe5wP%q)zxU zeP03!aSBzgNMc*A7he9GXUjNz{Be4M9Li|#BiGsIT1lB{=n7UWt&h8V0Q*aSe+^l^?YpPaN^Gx9#tNkR8OSXvV z0mH%m2vb?j2v@=FEi8-O@6a{{E*NuEz%a0^heJTchXhPHxGw){@xk?C+Dp0-l-hp8 zHwDHK%&R87uKU!pvD?nLcdA-c*P-?h!Zoh!P&adEKUdIZ-qfkk^{sfmRYP>J{~RH8 z7Y5@HL18gkO4E4sc&|A=)o_>;C>NDaYf*ogKsOzPE6kR=m^pWbFc!22_R9h+!lWh3 znmyo6U!z6%tVjZppsr=o31?Hc#{|#XKG$Bt{D>`~4G5g3f69cxlP6E2O?~6dH?zIa zP4?fr{(Pr-+)Q5v08+J0;CePdj&nIK{|M-96DP}BMaa9?v;ng^{5>4Oi)r+W1~BD`TV zO~;)6=!A8n&mvSle!PP)zTDh<@K$sE#;xH0b0&u@vksH?@B;k7hwnFk|M!2}eEiXG z(U$H~$7pES+T}hTtN-V}{wuUP3(arde;?1(kLhPn3i~b-ON*H0&&{pS_RHigO|aS> zXNu!KiPW3|rV}?A7rLry3|(Xe)OAm;eTnFLaLtA?83jF~>a_UCxzrlWUQiw^Oj zUZ^X(gcED@GkP+(O5Wt}xK}I>tUo7Q?23+GU?eor=R)TdYR$*o#YcWQH9aN)(oUgr zg;XSNB6B-CzJoO&qD&q3?}E4G@H)`esyUSxs{D+2UGJxg zFuVN&YJirV9kUwv%*X2K<*HpQwPUh-6V_Yn;KjrD=3EZ1<|VAwV-?PFPyWK`VP1xN`93dx&!3c&IQ3f7OnHQR>a?tu zxxVA3#9H)2zev)4-WYJbEU$VXu&%0wBBaL8C=kcVu1d~dZ2);+n z8DYnlI7|r+!n^{*fUROQiB*`}U?AS!zK(#pNrnq}1ZBU&Bb>8nM$kbMiC5X9qcQzu zfc9?*)5LX{bN5I^le&d@BHB$o=yniN@m~~XG6E`~rrdC?3O3~^Lbr|Y`a(5i1Fi!# zui!j7B<^Jt8XO@Z#Gzfn3OX9rE`sU+p<2(mmzrY1SZp92bTJcNLwnm}yAB23_4WDY z!NWHY77%V&!#Y%8AUw5?Z({nX^^8`_zBb1sk=j%DY`nz0IgB=+f*V$~aMFrmwymHC zR3cGEgc<}A9lT8Aaqu9xV9O^uqJ4V(lNFCmd$Ouu3x{_Y;CMH7u2;5z^-jy%eq?WCMr?V1V;Nn$szewSfmfq zNyCmvQzmhdWfH=W{cnwg#;!|V)?v~Rr(2*4#qn)>_@2kqhGlQV)l5^abSzEm*@IYQ z=SJSOgY!i<@2;F5p_#)F2bO_&&#R$CbHY+UhzIL6xPPu>d_;Z}Ae9*l4@LqEr z$0M6 zzW5lcha#LxOK!p_-+k}^FUg(ezyI==;09YR;q=0=NM17zC=?RTI?p&{4}gv!6Bhv-0kjJp&_r0L zZDXxJOxJ!woM=pGdj->IV9Br2+rU3hXTuk~JdUVeTV#@X{9Rs%Bu^$)AR zS?t$X1B_!C@JzCrk`?mAi=%Gxf877UmJWE^3ThNgJVxMhYP z!X$ypcM~SOYZfGCGB>7E*8Dh2EFDAR0plf;Gtale^cK=7c*Y3>M@r7Pn~v`%%zPNK zwnQXI&ZHrHoBPb=QGg&06+jqL_t*Px;C`{7^up(N5nL>pbbT?TG=C?5> zxgEAnnPc){85~pVATxW(dNM6vHCgQ}AhO9&s;xtijdL#7gCXYH#?j;}1R&rgPDWca zI%-4^+B#?;3zLd~3EnSiiaECtt;rhqH#aw$8(W*rwXJKEzuW8`oHaYo51VHQuwzVz zyUUsZck%Lz=Uz@!I}^vFf#DV$ZOWFS);t947%o-nr&VJ zqXM|5y8Hk#CcV^}UPyZg+I>xfDdq*5TTdM}9kamn{G4?8)`dBCJ)Zb92UFa;IBYi8 zSTBnwQw4<$oDHpE{(I;4R`d2dn=t+jdrt1*X%TbeQv_R7%I@nLlTY$ibF8=Ed9~Tp z78Ol7ywC;_=IslfY6~^d2RQniJ+T~RB1^n3xL4j6CZr9LiwFaD1cjJbAaC2jI6B#o zM%=o6o9#w04`mJKEoSX^c6Sh9*k`ug;y_xWdGG>GaOTm1DWn^}Uz&CEb z|K7XJJMX@Opo!Tx8t!=_kIYN+-Rhm}1 zW+{WcE{T-FaBunAGLm+(^4V}SPwItR8B*`v!`6v_V$Q91c7oZTxrt|I>U{`OX!-}D zgZpA%(MrzQpXZq1+1RH1Z!|p|8~xL7-p8V0zIpGR?=`n?-f1>54_sm$+Zt=0=g@S% zi*V}RphxUQ{NYERupjFG-8_2q6w3%reb2$!9oAg$G&_5z)D@=oi|f=4PRr2L-nsuy z^P?aAEV%v;|NS@3=U=c#YJZ0|p})_88%z)_VD7813G}6m)PYr#6WKEp8cq&cPTmg@ zDpPhQ%(4v?ld)P2&?Ph87%_DP8aN>n&%lg9PO1Si!ZMD?=zp5tj}eeB&gj$Z1I|DR z{F?j9)H@!w{l;s1`o@X5v>)|d|HO%_qy5ecC+%!dK+iS7@^BS;cK02tf!h8RXSmu! z%TYgy|Gtx^ae>~u=e6UaruWi%zh@E#TJN*{Ux#+mHJv4W`0*#0)St)VVjh|x9X81$ z93|~w@#0$4Q=Ijwb)6_P%!)wuEHKS}zs(weB+ZUl4g9gx00byBh#v{T*91$3aBFKT z+6oDZ%wL$#HhwgG5HK01+%up{yv!==qhMepI&PLO01A`}iwbu#=L(U0j^fR(1pi)ew?F)LhvL0!h&_=JJ}guZbG!_0t>SJR>E zb!1L0IoBboRW+0{yOv8l9D&R3i#voN#=w~w>Up-1>2RWPLbG*v?0$0yX{-~Kxu+`; zPgCUs7y|Avk3Is9wY3ejrYp@RTBJ*aoHfE9r7Y|jiRrWZxem!oD+J3v#*9%#k&`@h zLNuzSuh^Rrp;F)0c`!hRm^Pq#DIZXyy^59z_~X%3W}kMhxD{MW+ws#L#jN@2Sz$~E z9MYg?&z`aV7lDM+G-Pfzm^9c%19`%JuL^8xDs{-=M3+LGlM=QsAc`iF12Cx|@$>5R zl{hDJ_Hvi1;S5vadRGJzmo-Scq=AMTA&|K4)(N=k7-<1#bHaLqvTUO*9MSeYOjQ?f zmh|@9Z#Un2?>%sYHOnx3%#|eVQm5nwFv27J=9O(`s2B56_?7;36%+|%9GWX(#h*lM z0k*49vYe(T1GgQQP+XC3%Y1m9<(guME!VeV5V+s(38T45S|P9HXcn)wdpm$6O$ zw1u!TPrwApdh_6ot>$=tzj^u5$jBU-TeJ8{-5R<>rxk&utY#AJnNk`=Lo}>;O)ZV7C@{~A||mAhF4Z@HCxv( z1;>iv#`SlpdmJh4q0vOMTPhg5aH1vj#}ZI4ZFQ+IE|Z!C{E9n{E7fU~d;PlZ-2Q33 zI$>&c7BVDGDVPHrb*V|PTVgFP>)>i3=IQQ%s?d7Qrm=nYAiiXOCweyt+4mf`=tQ;y zXBAkB&`A*f($Z-@?+Hem)IXl`=hXo&p>s7ZCv7p^c9wp2{M)Yq+de4M7S(&-mE)x+ zA0-mv6{ooGgs>X^;u8b<5yU42@JUB>Ig=O zP3WOCJp3BjiI*?qW__OFYuik(@iG%oUt?v?lKPjdfh$rL29a$YZlkr>U?IH3M#f9R zk--{5nu&iRx)hbEBK~>TDDxMYY+Gi5tM|Qdm&bNgg_$n z${e%|paN=f-JgIVnx^R?O%1^VzPkO4#7(CiGO+Pr%5xP``YcO_K$O&G)FOZhRF!kmZ9pyo? z0$=L23|S}m#$Ne~vsq&?*R46$@>e9;WR z;U2;(yN_ngrfWz$ony3|z2?E4)#j&ceX)uKuUbXTa8b$tB|;bD?SL11FuI2bgFE{; zePAn$^AVm&%@0_Hm;nz5cr!#m+c_Fxo_L9~792^iCUqIcdLAt=#<&QuXg*n!=(<|> zZ*&_AapO`PWv%NaX2|X-YJCncEp#7Mh3paA?2O5$hrq~kS+u5XFLQjx>~s%76s;8w zV6LriVp5D2P7wq~_Z;nM4}k&azRf-i@!ald;9A@0G~16@qxZ=zgopX&@h;nXARW!I zhBJFIvSo~U*>_~L#liGZ@dP0NNceL?pfJ3CBlX~{{I&H_y!|4)(FO`}yx>DQD$dns z8Y`dezv7GSzk(+8op;_rIDJ0Z=v`A^X~F`U)n#B+=#v?e)*Pd48*qO{KGLNnG}j){ zY?*2j_9BkuQ|j2~95C_)#1>8oMEgnF=41V?;47?_D>R1$q$|ZTM31o0Kk8k9!}Z8_ z?%W9-b(8vwQ_W@j&2=>L@4fe4^ZoCCFJ3UyPp_&dnJM(-6+hBn_ouF2eC@@abwvG0vt9SC;COU|BQn-xfB(JjH|N_YI5v8UBc%Q2KmV8i+I;x_C(WDpA2ts# z6TFL7yhk7Z=%bHWTlz^%dmlY|);!x`jVbHT7nUzbx8$wXG`O`|DkC1h0Q7IyIoCZ) z4NY~W%tkAC#Y72oN3EzhxPfW^^0E^pm_p)#e2e{F=jS$?)n&YI)1MERRLMH|AeVF& z8o^omm1#N-K--jo(I^Kl36d2pZtx-#vszvFXWI%)JuO^q$`q96_DCDohuQTzSp(wA zg#M)lUP2P_nm%3}RpNY&i5cmsV}iKIN5+$-nE2kkcQ^D&p5cPYqdBcuoQWZa6FlYb z?d`@hw`RU>7v_=;$8eHJ9@5WBOTUwi@h@2DnSlB)SlP3z{<#{El5m8gl>3k&e)5V> z<+(C$5+4cAVi-V8>0I-r>727)&f2S?kYSPuk*GxIWaQT~Vi+1V8ZzEyz#_moOax_o z%t`a#tha$O`90ohVLGmaREFgM#NZ17a{zY0H4kq!{Ytu|6|IA#w;}iz0vCb`mz?s+ zs*^wP=(s}xSNIj8g>yon37hmu%lC!Z;Foabop-$VxcZ*Q$&XNe^-&GUpsi_dq$RFs{?yJW0ntusIlJPU;Srk5 zqr<%?SO%1EqU1BcJaDT;u1JU&5>JX0Am;J)5g|z^VU0WHruRy9S%;j)y58j=NVeXi%SH2_a>#z=H@S& zB^)B{9pecV!M5qFAl#8In%l90aVr4WUY;62xc;u3-21-Pw}J>#RA$y;*a=kHEK!-j zf}zpLhOL_xp5R21CY1P6`kptzao&2YqqTnTz3(;8F%A3WFMpMFO#95hDkh;iouIBb@Xh(P${r32oy=5%q1Xc7lOB%TbDJ9KT&1rQiCV@Q=k%<3`g|9MNnEL~WBQt&tQWwqMaO&B-2eu119*G<6mL|KZ2g<1-wh!rUtBYZc@*gN1@af#*cjS zk}*m;Wvxj7@$w%~k=Ok!Vf#!tbsASLglHS~Mwkxr8C zpvYLo-$M97cr5uWc}T74E-*V%Fx8Xq2@{F(VIBn+%e6kgjB|#0`CTHm%T@Wj;w!!JtLe#Dpz3Ev63dM zVo#e*m{8ZsiCaf#LywNS2o4zQUUcys+cb~9c;3AK;m6G(o(bLOQ`mZFlFrHZ9ESKD zlfiS=fR510jCCG_xuL;id(T-PyLZ5vQ^FjbjGH?*yO`JF&<29og7+W&qqBD>q)qefX(hW2&vRPLUtc@u8xt;@T}X1A$Q&4_Vu;qt+(E8 ze)hAUHMj8E>mHC_eEtbqr}vxV^FD%nsfP~2r)G`{xhRwo($&^Dal?8|CXp1jI@G7@ zhZNX^CBmqcWY*?0)8guhfn?zS7LcjLWy_(pnA=|>g3 z%wltMtNFnXe!#5zezWyo|AsY)kE11ZOBvUcudS_zCS5s3Di$6`Y)^7_TC}O|qq-=q zqTDVOP?#%yhpTwpf>irK=nCj#aYMh9KKM`EHiF;MKY+o>1t;8uUz1)P38^_13)H%) z?R0w__X%`8?4w7YH#<)sXC0OTc1)3huU2c)g?2LI0Guz@mF?mFqf3~MXN|2wqU8cE zog{^Bp>5Be()6KNYzQj_h!B-FrCohCY1+pyp>O=!)akRl^J*p3y7Do75=&A+<3(B~RE@i9O_?$(f)wqvMjNU{U0Pm?P@QK?BN92h<4C2 zBWtvkP$g#R8`cf|3@W2QyS}-G6S4>7N4tOVS#xsK!<6{}Yrt_r1|z=;KG<)_nDl59 z+E5|Zb?FM3;$ke7NRu2=PRl?BoFa!U30xwIW%ISahIgEVY-H;hf~22PSGK8V+L!RA zQh(cryqW#{8>;~uS_JVZjh@@`%HMKVKLtO)BXKE{XZ8svp2SsxO7nC=7qedk)N5?} zrB-wU59L}lB^~ft42=aFnr4gYe#Gg{Uy7q~S9>dI+;&^1Z#9p|HlgWBbm!C`^f=+oW5#%5&J9_RG|V z8dz|IVd{)IA>U;l{d3deEGMDK5Qg)A0bLBVB?R&$kotD{+#@YD5 zlQ8+6Jhtyj8rEr;VS-ww=_93)ne>lvphPq-$T$RcAmp791P=fT8x6DOqybEygOq)@0T>|W0V1rs~KKmp4h|8b&suO zK11Vp+SzWfnr)784DLf&gf1GGLCm9Q7f2rS$qp(4}Zg||4N>0{z6YrH0&(e5WW zUea@K2O%AWGeW>3X(31>oSGkE5dCwhd2s(u^VXYqQoOy{Yy;EE;$2Khd-U0-)Egd7 z)fbP>5IosphZ=AX)eeGnbD_ziB8Bzgy=`OT5r{UiZFJ@X0DLdPEH^v@C1t*pseoBm zI0-W^L!b8aqL9iG0KRK_=#l<{02VyS8?b_EGCSKXky~clw!U`#2ExicJVf5Z+07%E z8#SYQv@?!z5LOhFWNx+*gq%1##0iIHzD}eK@a$`fB7vIcYL+S^RJEm|`{bGT(MB2v zh(Z(E{-C+C?_M-{2d_xm{t>4*<_iqsy;?v8XX&P1E;V!RF;VdR>2ua051Q|N@6Vba z|M{P@R`Lb_kajA8T99$0zO8aA#q8VLXeO8Oz^v(WmQ~n?Ji!(BueJWd_mRI$WoWHM zA&k9FA;;A086|P9R!}nV#uU7IkOsGE-{wd!{RliPdm*C5q|TkR>Eo?S+HV^6Ik(3e zD^S9`>Sel5pYAY@beM1%P`^7zXKc;Hx=RGi<@Igqu9)1O;)Qp7c-E}qc(|K&~<53q#JIS982E1<7q7$XFb0&O-?z7sV52$Un zkUC9sB2~#v(|#bP?iD80^bf#Q`**5GT&NXK`E4HsVNJHPCfn@j9GL`21(q77rbyq2 z)+1>nAiFMnYx7pDC03WO#ZlAH$spiykK>W!A9*8wH)qf(miv;IeFkBi#RyuISVr+m znC560>$*#r5HRj-W5M(g2JbU|h!D~}HO3T;=`2qE#4-N-uSaf8W9nV~HoN`_*MRN$ zRqYz2@gqkN{>A1mU%(yuh?Z-aNU+?*)^9epI662cKfZf4A7P6ilvG;U1cibI2A*nS6=6{3i*ur#GaZ1A z(8Ill45f@y3CFYR=6H^F0k~^A#vyP9e8>4Y2Yq3YJ`%nV%2IDKwU$Q#4EjqNnzt2` z;gV;`Tj-0XCZLowgvpZBAT1FV4)b??rPl(BmlDwY-J&1|uL4hb`qFQW^Q8~GFtu7% zlAJmM)#O>mNAIkL5jM4pF~_k!{G-ejh9u(;r>RV|*TlE3eOLby*LtNvOEG2Mbo?Uj zk(YuW1E7E66T6zAGzBlrPZL+zHye2lE#e|uwTO#DOn&DvqeDgwL#*(S^^NH;Nn=5cf1pKF{vGaP(9wAQx_LVt#0x%k5j15rfI8+DP|{WeBu|k6rrWl# zpVOaoD5IuNTo|ZnWHwz~wC`73lt%d7xboEEUJ27d1G&+>`|f+}h5EGl^{;=;dZtqt z{_SWiv(^b%G&9@W(6jH&lu>Vyn%lY^LJwGmXoZErJUzvqtJ7>LrR5@TfvU8_K5lu% zd1v>}(Q+%qn1+XNO1HGkP>X6`@mqChHlc{!~gcb zHV@x?n6%?{nzZJ?hw7M!ZUkVdl7Kab-T6A^+j=opn<0z>tdOd(2zDd*(UvfN_8Z$E zG7M>ykiG*xV&$YvrTz_IMouD@iNsjFAdFdNwbic9xbz1+aniv_fhDwm*6oP=7Jz5y zjFUnhYrI1%Q zTm;l2n2zJ!n>6Ti3z*+_hnNeq=Gv`_#HUMW#v;y*=y4e@tR#g!tH|xIGG;~_Npa0S zjJt2Ru4z}C#+>hh<5w{aF;tMv^w#m zXKp8qx>z4r*NU>qh!-uK6yz%K^qu_(Sju4@?d|OHuTulBs(+g&C{b=igTf;SVjlSA51bFZ zp|894RP1!QhhF7RSf=9i@#ey{Xiwi_pXyIO`2^GbkMRh9+H~-?t_6jYiPF+Nwu;)> z-D6T#hh~`Jw+gBAU%gKv~7 zW%ZhP)>A5@M6!m2J!$xgGqq+JUOJP2VMr)(M7UaAFmz>qOxuI^G;A1W>eV$<=EAT= znyeqj1MdP1Wd{Lu4sW~5tm{))TSG`aK|(vb z?p=%45Le->qwvXj+&^nRMT2vUCieDi%zPO{FBPm1Qpa6{0=9>kM|--lI%*!?S#REW zfLBtsYT3MjAiIKAX$|Kr7n{r+pJTFnL3(WQf)HFZs|*R40WY)8bslC}=CZ3+5--3q zk^`9OK7wHnEiD_R!1Dqd0_X*BxyDZ>wCfsCgiB*g2c_BSWA+z!Um2?YC1naH4QFfrn#XlC4? zn?>W;U`w1I{<|NA27U0shs^Bv!W#yk^z8!*?JhCsv({bA;{E_Z0pVAYJRJ(7CW6-q=sWlacKm|1$fsGJ&=*I+N&8=q`t4yZ-RCMDb18#XB~Dai z!qc{)2+}l9w||l@@G-3xcmp!9r)@1AIK&5WLHN~zQ3&F-C*i;9AOykqr5>z``s@4h zoR?qmW2kz3y%;t0?E3m^V7fI-y|kZi3w_JG+DtVt*Mdicmo`FkVr>Jy%d1Ea2aFH% z&_hG6GA2KKaKCwgv!u^H`xI*;CVQA5bYf783vqmJ_kc;8=ivWwtS_9%6MtPEVH#c5 zm)jr9K|b78o~C{IwJx;?2Cl{WS`oh^fo1~gcch{JREimfMS{a=r?1C!=P&nNgwylp z(@#Hb{^1|~q51jGf6iv;zhphz7jZx$Q8Jt}=tWpFO~{z13=yXTH{3_U6#u0JD8^bkh9xHy_eRVb;O-TQ?r!l;>gaQ$cVA?XJS}66T>>*YRkIW_E86 z=T7JL4~1SV0u)4LU}1RY6x=Y0RWmijT(W~kY%UAhU_=NPMqMER&3-m*r;XH@4JfA` zT|)zGR?@XhGW-Jt73%)%?1Z{KM07S;~yP83MbXlLpt(<#8_wll5)t`j14 z^1>@kL%2%wp(NIuF&+PCSMj7yz-CJwafEUyzlv$^D2!<6Utl>uhQpHL07txT&=nzcX=Qk2OS9{DJaOpYK3*a@w3 zqRyCIa9T?P$E*Q3Deg*x><7lxQsOTDO77mh)2v|8ayUB3k_Sj&1XPKN{sbOF3*9zs zfB!+Yo3SsQ!E>6uX}P|>rWtxX0m_?Nn)~Z@!b}Jer6(G&T*U zewRbc{5Z#hBfcZ3!2qsM|C-sM&qNC{#=LjAxqEXH=6BG1goVN0347AO5O3Z^(Fn1ZBk{(V68ACb)icsOOf511 zfIxr04W`04PC^^x`krOVZTqRAIX!{Fzc_6U_RkpbF-?T=UqTx-z^reX+31Z8(i$TC zf>&#s>zD!GfHB9J5bGgbBVv)2k4yhvZ`nz1K!oIPhXBSq^p zR;%btI?oDRCOX+ql1GIh1@Z_a2qmM@Ch;wMNl$akf}`RK?{X9zSVR!HbLSRjzHc|* z|G|3*Fi)aEJ;V{zB|>oz0X0hiD5Le~p)fLL?V)Q1MKQg$x_+{NFD;Q~m7)l&-6`~{ zqN9<@KjEA-DDahy=Y@+jq)EW46@@q&fdyQ%y`9_<<4$qbqz6m)Z`D!K4}bW><|jY- zN%nTFr3}C|vpiS_-n8&?mntWM@}loUGYrHBg>K6tzK(U+V_-WfR~>~>Yz}@1U+6{= zbfhqT@|rgWNl@b^c;FC2hE6YNOMOxlKQYYq0jF>`>;9P|D5&IkDKB7 zLG}&S6wrCRQ6IX9g~DP4Pucj;b4{l4S=W-Kv=|VK9|37U6m}3G ziG_=~NwQW;vU=L%vHRup+dlK*YKgj(#2oz!BxKkazKOJbi^p`nx@c8h<58Dra_`~+2AN`2cu3PM- zS&k&YL8FKDX&Rk5^}UaArd78STe*gyBaUBHmXJ0{BPFt2Lp&$_UM>euNkt;o z9FvbOOv1kRfirnnCI?ce2loVdB|L@j*?3&3fJ>|_F3&> zq&@elDkZfl1x2YbUaP(ZgLn$z(O)HkJ82Ez%1hNbmEX%`c(aI6ACv+V=X{zO=hd-%H~8h>zIAvWgVOeJmSD7|x!*SdvZD3YBP^rjkX^OI6Kq4u(=g zKhvuBsn#iROY$1`$q_b|1gYVa>aI~wg=vIH++0GXmGBapt^kuLkudNg6NdWj3~I(G zxVEPc?sFFDlXm>f37A=q!Qq&gO;npU*qbv6QGDvuahQ=gB)v0``Kb0iT0}|<;k-_L zH%&*CThe5Y?Kl=##RbgaBC(|$Fw)k33NHG{{8T&l(s8WXzShp3J_k{Lh<>?_)bw`y z_>&u)8Htrp_Bf6s#@*S0(WbcWqdR??J*Y@v*EiSO-27~N>FfehsIhkM_Pw_BWR;b0 zm{ee<3RWzghB=fOq5d-Ez$!Q@ql1ggOkb`@CZWtp0hs4JSH4{|8izTN*)=)Ud^N5n z6Suy$!Xm>Wl0(k&0p_Z#N}Oza&@5?ZFDl_9aii{zFJ9u2u>9sXzYa*Y+V{Wz{dUu_ z2?^UKiw;>Nf-#T*vAjwy>7t}ZaHYby$)HMWy>hkv$N%`hw(tDAZ?mv+%4%f{k%5b( z6CBeJ7mZj_I^dD6LYeue9G1}+WAeg><4TN~Sux#gC1GZnsaNW&j}d{74I(Ua>+XBf zq%t@T;dFKJvi6VDpJ+3Q%4rz7jN-stY3cX?qe;p?4TCBU?v82PNU1t?MOr_D zYVa7+!EO4-)5j0my_=uFcrJ4e@g!&X&bOB^@^x%(tUbPi1?tts_VKUYZ#U82d3gU` z_J>ZfSTX57Pw-Q%b8L#S_tiGH@G^rKRC=(}e)#?W0&{zTb4T5meFvNe=kQyne?FQXnoCLut#9Hh0>VFY~US?xDX0 zunhcAC-Jo}rj}%Cm|N@|0h$R8>DKG$W0YSq%})<;@caXSz^Fxi*&A4@X5w|m7RDEz znFGW{`wD)exP*3rEK+{_PM%z7r?KX%aX4ut7xt#;Gj7SzNRn23A0b8c_S|Z1257Iu z@g!O}FtoLx0^X*7iG|{Ge)E3t^SeW!DEZ$#or4q(An-yUAd%(e#MR&XGm{y94iL*Q zqptR=;(PPv&8YiIm`$Uyp%u*R`y#A^mW*Fk*oL%+QN(QaE(ewjfIO=Rdw%_m_C!a+5w-TIr(5H95&-ji%k({#OwXI-o85Gw;gQ4DGkPC};>(}_cP!}aSo z>Nj|Fce5<$4j!b}>swU@Mods7n@i@Ph+deIz^B@$$4=dJAKg~jFnjejtjVQyhIFf? z2$hV;Z}_9~gmgs~;?Z|+(lfRXX+n(xIf=&D0>aKIRE_*z#Sn?d%xJD&M%Z>4M;%uw zj*L={-f&eGYB_4EN;M&9CEmC2k5mXEcY?ijC=8M}Y^P_HZmv=!m{8JV?nFIToRq;u z-FN~C<=PX@WZdP4vn=l=Z?3RUpWPndZHag zk_t~2ywO7J;X}vhn@<4;`%__(H(-9BK3$HgbT;37^EDX0r)YWH;V2-OeT?g@ zcx=J8R$YtPRcc*zp;*?1WUN>E3`OMw-V^MLJKv+r{JeNlhb&ka#yS9pj7c!+u{Ldb z68T*A)$FCpmy0UwCC1o}OvY1GkKKRy_B-#iZ+-h)?Q38AT6_JqtJy=TbklJ|_?Ka_ z8c&6uU4V=OXN#P%&oWswe{=&rp1JE;t=U^hh13!dM?372fH8!n?L%H(z3%qGx(s7Z zW^6iM{3cEPs?X>x)1y%)7Z+?p>njcjC&$1Lv&6OzVZeBil|_-h&5)#0m1W?v{^Svs zq}SWY`I+|G<%{jg%P+N;Upj*UtXZ<=jNiu`<8&G$W2;!%=FHz|_G`}{J1rl!=}YwAxnG1Egq~E5m3hTD29>d znHOiE88b#PHn?DDnlh}*EKX^}ZV_hHz5C+0M(&L7mWN%p0l>66-lhrmAwM`JCXLwVZ^~i z!o&&Dk;t@UZhX(kV<4`c2XFDpcX>VYYpl8|ei*q-><*cv$j|Ur$&+uNkW+?XY%`4E zt0=xDxMN}JQ@(Nj?LR}=4Pbe_%)^yGrKd`VOfCBfLmc+9)!=T}J@^!%TV*6+>p_|l zBf?bmuTTa=6zjs-dO_;jc|D-fc zBD9F!{qgtSA#5pQzNV$d-OP}*dAKlkBfka4&^80ao%i50g6+ zCU%EoG;Un~BvQeRb?^ZR-WUY#ECzrsUAffGU&P1?5}6Nv^{e*bFF%R|boTH9k|p-+ zXtDPYggy0JS=ntjZ{J5+v(+wNImfCt$IifeYwh?Z%<JM ze+gM6xMAS@QUc35v2X5@rVJILw2g)OaYhVi*x5dY0AO z#S#0?!-rT?CM<<$Z@m6``%nMre{0|V_IKLFixI{glk{58~hm7Z>~SaE9M zXnXsO%k3}z{hzjX-@3{-dx|-}Nmcu&sBqu9b))_47e8y?`@6rxO7_Ec^3+MB&u80( zmoK!JFvxNqi^%gwG%B`}us{64_gTES9Sg&%{-(ScWpcGtK^VkA_jJ!$lDn%`^ZNE4&(LBDBo9 zd)Sqrimx)K_Js-3cY#Cv&cYe-T?jVqahPubp1s{^3!BHB`$eIwX70jg-^J^G>luca zw$e?5d^x&CgGt8YvVH5t$o2ZnFL4g8&n5(HIa~K%Zo%&RY)D5HrKYvOSagVExS>Qx z`-tBPH_XBDSGC<^$Br{+&NDYLUJ}spa!0KLa9_GY^9&@dran4X(M8w2D}p8fHC*I7bWNrCiJ%1R2ER0$x7WjIqw;9;!o z=_J3@FIA|JDVHgbvwm^?l%Mzw3E~~evB7YPBmt%=upxya8cECg^#q4H^}6k)WFm&G zG>J@-5br4$lY+!^%4S}MvyAoJ-v++x*WFBY|5ffiS27#QmG<+KHt`*>a+SYrB#~@= z;@=|;37f=_OyVY59F1=&y;9n|`J+@8FI+7PHA_8ZO64465O9|$4`Dupk^33$9i$Co zsH|$1e)ce{v+U<{Vtj;Ez^ABCsyRmtSUI>U=asA7I5*Y12uLoH({{tQ}VJI)`x_j=?y7X0}~={S<1wEC|gk zwwb$QZ5bm?%UJweUR}YUDdFaj7$G^`*+DV~qx<0Tz4rM26IQF0bRMVN$f%g)#m_aE zxrdw|IeTQPojkqW4j%zDbl)e~o4Iy#v0cBl*cMk&zrq01%+#?koT_0eqz?3if#)}Z zgWEDjfgy&aAiB3X{$@u*88E1}4tESEX<&&BcEZ_q*7~bF6yWBjA4?cR z%uCP*FZhN9By4w=oaf39kKl#O!y(#!zMVL68fo(7b`J}w54hcno5dZ*ET85>(~+L} z6@DuL^jrL@Wb0Qqo&AX_`Y2Pg-wP8B2|oLt*<#-8d-f5-)@}YuPSSSzWMbpwXc2aYwZoB zsE0`xY@tn8+R@{)ZFU|w&_{M*)SfOb(sz!tANg#1`PEn3g$oy8P|wpR*<(#PZr{2N z6M8fTmbO`(TK7Cu_N?!YJtf>2>b_fy8*`MOMFbFXiE+b)qut%rEE*Ji9d!!|8FSOV z)CD-j$9|?iAQ3-=jPAmJTw`{$hXnSRN4o%OrJv3dcB6D9$5!IdFwrz{ToZxHV)Bq8 z-!ABk#&rr-El{}`Jy#0M8_)V1+=oYv@uX>_h}+O$&bvGT=SQ-*Vh*S(W| z4|VYTLx4bUTI(V{|Hh@`fGdv1(qH0Cv;n|PFTCw28G{`69KXeN$Gwv$7BFsiJX^+! zc?IR|2h61|zIZBxwobI@Zdn|@99PVv=%|kWX2gAPy-)}oFsLsSoCk^hE)WPYL;^l* zVyeNSr@4PnZ~$>{rAIf&cqwI(0Ey}aBZ&i%;WN>Z-t#M5`XvvZUWV&oRAV!KR7gjI z9Ar%hFv9XQR?0K@*Uapsia&(xuEzxQFigCTU6NbL*TBPIX7+tz&VZNnbWHU6p=^81 zsS&yT@5I_DIQ30FI#9m^BQEj#DqqSBoP^bW$#K=F;6AFC2~ZyEBf%S^GLhntrgh?0 zMKtM~aSDZ>f8_aTmuc_6J~iC4K}NyL*}D1fSN)P%+GH$y@q~4Su>{_R?3XbrCN33h z^c3{f=7ts@jBVW^_GnmK;x3eB5+cz`ePA@>Pk8>d#_Cy;YimfRP!ZaM;9bGk4}uVq zE2Aw2+=YqLNRpDJaio3Is9;YZ#gQ=e_=Zj3yN*hdmVa5>B??jvn1T(sxE%<~EtuO4 zq^O(h3H40J8Q`!Bkvw=3aw|Vu2_^?t$pzEZu{vkuC-hDS5POMZLeIp z+Rj}(g#jh3{9eD=e#D+`SCPN^)$dRaI9ev-Lq`rlFi&%i>fv_vjp=p*<4Wf)zS-_R zScjS1K??e${qn;PDa&emxOl(KBkeuQnXAI<{@r^dfw7ehEP|pkyN+dE8D{IaHIB7h zn527HH6DBalXm^~ahQo2(p+gDA>DntM7C<@002M$Nkl{V=Mmh<%{$;VWC>D8Wcxz z+qc2m;LPliQ|+BEe7#+|@>W}6f7=og8jmBoqssl{5%6P~_H!@zSR^|W6N}{MUQf!( zGvl^(6%Al`U3>^mfEP+sGxMYofeVlXr1WE9M|-AC0MG#EEOrcIx{aPO54H9c)ECu~ z8KVyFh0VeTYgKT4RUP**J z^4Iesy9z&yz?LOLulbn)?s)(w-?@7F1Kk?8`bmK*yn`tD_B#3O@e&qqzmvw`S7Gqj zmw#8EGmbu07vWK`sm!{&u&UeepLX>!7%o>;X%tj<^AzqHv!Re7xFpIgfU2^(6$Ms= zuR;;HXRB*LxQTB%gwrWm7|pkQ;23vYh?}G{=}0WWq~zYuq>3X>iPo)fq4tuRCkz2Z z?y7rK8di1*=^32sETG6>dW4Ehs>YF&N{Cu@LzVqzs%d)8A!#e+2+{A-Ellc; zOe#`5B|=&W-I;)pCC@EXYS$?EG7_0Z_N5+gNIqdcCXmF)7+=5N+5?RE{``Y$?Zc1Q z_x5y$$(cQJsvvXb=-SpY%pwftV~)Ta`gY!*8OtV-3GrP$iU-(ue$F^ZHxiYBIDC=wP z&y=|%{YX(&`^B;`%!_J|zK0MZzPRav*&+5Cs!Bge-qTZuv7UUiEgV0E>NI;6AG?o< zwx;c~;DHraC73e9x(Da7FjhoTWaw<{m;7CW|oyoNAm%{apHtk z4dW!UXx%A+cdxHSN}YY#yUIzJ_$U0p6!3&@M0=pN%K}YQx9yY83%!#A7bU@2{0SZb z9~jMb`cjT=;;HeVLoCi*x_Sxg%qQvfL?_PPAGkoARr-!h=(&q8!L-v!0HDmD=dwmc zcZGgMM-*o~!e;U53XJJ;)V^K3c*>sdM`#l)FVl~eQVTC?zRto(ExHb47cfg3(vE3c z%3^(laTY3uc~5J+O1O6&yXe2Q51IZ!d8!>$hh#rHi(Eh|Znj0WJ5dMtNAgZRYzHsl zvx!AvE%=IS1#^lZ0`pb3A?xb#{Hk{H$(#Q}`&;;`E&Yh{2QNnH8B=@;BKYBFetLR- zCe36PPXioWe+UrhjV!JN1$4+ua7e^-4$!sZmDMiBvF2vcBJ%_<;;gtWo#zo^XV08& zr%s;8c;k3%Uz>Enin-Iis`T{M&0FcG3PFaIo(M2)y`$LCfsw($ z4#`bHv>Mj(8rBJoP)vlV?LmA_3eQL+3}cxr7;X@bN*Qy*Ac5f21q(=Kgv296oRVGk zT54T)o1fJxfr2#q_pAGGT?AGVLL-)nata^wp~$84g; zDnq((aw^QltCuddMTq2kw;r~;w;#3@j<9+76eB^?SS%e!{}$EtWf)SlLMh)S3>XYI zTWFUyX4{EVCy+QjK$?07;(eo?I&rF9edS#H;ulbF#P8|Tzi(^w&10v}BDFe=)bvSP z!-&upgtW);NEnQ<`EOzhAdJJ@9mRTVU;sl7OjcG3p6-pC!jfu9_6n{N-R_sP+mE4o zDZ#x1Y_x!!k$`sDgfQ7et$x%i3 zHdci-c;srk_VNA_dec5!ZnPG8VL~}XV`yr z^~&Y;=YRgcv~PUl8yH7=3+uxtLzoE@i{Ki<24%Z-=XU$akN&Cs=m$S+KVa|jof|jF zdb}+xoN8CDzR})z^R4#Q+wZiOuUu*;Ic8_>*gWZw0RO@#^`TtpvwSP%aM-Kz*-IS7 zthbD-#HRg97u|bBed0};q_kIez6q32{<>#7YNx!rrjxz*vsk_+f9tLhu1Sg1q{a_$ zQR>Jl4EW-^3@mXiC-Z}eCoEZ7Qlf${u(b5YF^m{#oNJ5ys>|#VT?Aha&&?BnJ^w7= zs7dhzo%%=K;DLL69WU?Sd(eLRQ(^yMinX@A&i-lpKnJER(0-R1h5wmM1B#{Yt(Qqag3Sc?e4l_pjY@C&m{#gpxS?OT7^%jK=N&s%dpc6v5Ibr@b_F&j5gvlT|nR;k%*Bzot6JuS{wo zcJLi0E#ueZM*zk$!*n9VCoV~gm%JxlCc{1>4(0OEolLvG=Vb`v`^eqb{!vf!PA+-Y z1Y8VHF;Vf4pXqTsAanc3cSYvabmBPrt$jHL@aky~`4e==GSMn#g-rU!ka)DbMj4`| z2z*v{#2O-Y?@>6TkwK5&>pA2QzqG;N(BGdAw?Dk^&-)iRY;Vb>x+Kg@Z_Le^!&T+5 zP=xAbOE|+6Q5@+k6*Dz5s;c0vN?W8jJc|kD34xaS8ID{3;1K!B7V#AzmDGyTnT}-v zzdU12hRe&m5?^=VEz4>Oww=rtydUwHU?D8^m+&Mj_`|SXNdxwQazUI@CMAHTuQYCX z1qmNi^e+1;Hx@ClfmJJ85PGV_Sp)1XmBL1f|vbuSg2K9aeQnU zBS(+gnd4{Lr|H(60vMK{uK2&2PD#g8L3JA3X-dzC$hp09V5 zvs{lLoj$Q}61X85CJ)onlJ5o*G8qb)kTDq56|59*;vb2Wos9PYH%#i#+;QODI`xa7 zl-i#>^%62l!b&<>%$mW)H}~l)A{+1je{ha zeUYEsxYmC9&p&Q||99VOKjOUU_kZ?__5ihQ2LmOjE^s{Jeu7%+la;0R_V{~k0;%OV zhP*6WjcedFjHCU+bi<%pD6WhFl-DbLD?LV{PX{E9JkpLl_o|)>8=zc$aNCQ7oqN+= zycCRDbywZlw4DRo4?YPlcjXhe=u7!x@G) z?j*#RGr{7Kds>%~gzn-#Hja8QZG9WH-J7@Wu?oQ7Fo=&HJ%9;a&smK*$2&|Ui&OLo>*FmRtzk(_##pJTSAKgc8QZz~)S|_Lt|YfqR;$wJy|DP`lyL!$<9*$IYN2G&Vk;ur4%39o;@en$cV#o6rmgI4Hzl$aTP=z7Q}T zB=RC4-~i%;=am&|MvOkF=#Cq78@`|{sVj0rd7Ym~jK>Xq`6SJJ`LlvCzJ+zZ|F%_=-ZcZkTL zj0t6ZsJB*Bg+tV-q3+XOq?HwUm?hyVjXBg{FN5da0;A{M{I;O}SU&Qy2wuI7d^avd zz`Jtsccku2-2A1yNz5qET&b2YgV2&#gUrV$f){J$Z;EkaJ5LOzP^&c>DO*ciM5(i?5u21p`M73F1OKyfD=+T%Bl-VQBB7 zZoI@ftGlQ=Gu3B5km|h~FxKud-Q2+F5(bXO?e7o+^G9nhoVcYlbjv-Vgq=W*cLGC6 zp4%u};}Jdd@?z|L(i{>k?w6+0xyK;hwTLXkpBn@a#xkiuQH@FRhgIhGcodD)eE6$h zw;v)w{4f9YzqSuQ_!UxL8C23>teHbvwt%sXOP5}S*?X_O_10UQ1N%D0H;z&7^XxON zqpwz1R$*>$(Dt?ZZl93|^4i>FPcDs=b2D9FNUQ2&zuS9OzbQ-*BZH?D-lzRD+9O8r zn>ufjrhZ!RK7w@b+_`h@_19l-U-`;cqSAZy>eUztkzp?B0*IHiTGZSA_HX~TefN8R z14H#s?KYBArT$0ej{v6{J8!{wEpg869gK-Q;+)+%>O6<4ug9yHPWCiX&OTlYMbnEE z>awm;*-x=`wH5j$EUa5Wq}MzN5XAI!)7NKId4ZpMHs#UmhxR=sB&J~e<7)FrYiAe6yB<^qbOA_>B$rF|sRHE=4LY z^ZNLaNB$h5pTb5K8-V?VV%*Ct_7-Lt$aF43+NpXWF@ANiCMe9#ko0Jf$~TkJFhJEn#Kf2Z$bpSfVi?e5x-wz!OCyB* z;Gc<;Fg-1U)#@z+8p*^kgk;o^SHhD|XG+b>fvVy`#PApC1!0_MlWvcjQ2aQqCeJFS z(XCtR0fDKisszKRzC-zXS(Ct!X6i~AMvRt)&V^6XEn=$DB4gr72xM^WVF|ZCZDn+$ z%P4+0^AkRgeEV4$n0Ee#tP4g}{`eU#!H3BsUwc2JdK!j%$f*J(>X7j8r~>I-@HIb) z(lE`yT(}1pdYfi!#LbNlvdZegBUH!H!sgF#cY3UNjdPHJl!16J0!U;k5 zl7?E6dK|8lRVGP75r5kudtzWjs~m*o-8=0>ISpfa%93Jfl*v&7(Kc6YSyfe;RPlNo zW(`qK)EuFKA);a8FwQgqBY9{Vrh>hZPRb#4$F%f|W#8Ft7$%5L;v*Dgb(k~a;GHMO zJ;p|NcxV_@3Gxm1WWrA=XPP1}1dJF#dV=8`_OCAMr=;o#PZ;D!8@QwLd-HrdvoMK- z5e9M>bwi4XVPS~*hty%2Z>$fq-!^-GsGDqp#*hMA#hbjVzNI?(xMwxulR_v#l^R9L z2K0a@Q zJ9onPy025FFh{&l4%Nrju;#jpwAj+3|4=JvnaB>xF6R?Yc{P20#!{E>r+#a9V4{sx=#4Vz1^I zFx{rXZHo$w!Cb1cc!={=J$qRqTW<|aotAKC@%QG98{qXy;(OeT`6w}V0i+g{Ssn`R zRS{AS!eq>|&Lr6J((>nDWU~S^jqPNA)!n#hb4y`C_z8C4zJI>Z=ivIof`Bbumxxg4 zP~U#w1`dpZ=wa{*Iz0LCpRkz|je|o}-oe{M=SNjwy;Nn_itob0LaDVg-pimKfpL{# zHN4~YZMLr1r?t#IqWMB=(C?hn#ZdA0;Ci7DIABm;C^!!i`&}U5prV8{42FXU9bdx2 zTfZVyR4>8^4f}Rn!R>JjlR=1qLZ(DZmB!cKNx7$yZ_~;oUW8yz!-37bOPW}NT$l(d zCF7IPka9^t%Ov!HaPX;oA&!(5qzt#46ZvTqGF}1ql%7EEdrjrp~*0nR~J$++TxvKt#u~3OC0cY8a$K7G+-d(Ma zDk&+#$+}dVnN}Dq;NIg^srG)82cOS8DSjP~(Zf|a`d5FNe%c9GhXA9k{f_aF5M+CB zF9x;h*I{5fq?{k&)UUm~jZb~JM-pQV5(PJ8R`sJT{LbwwxQ3fhsEN_^Wfo+1l<2T$ z3<;;kU~+zE;+ZClmT9>V;xB}njEnKAyyAnCAH*|GQ^vH1>(75iInJ-ADL8*QF5Q72)5-4DABLpVm6wUnz>RcUk}3@kh@ z2aX$wsp#k>F}{gr%q9-r@C)t|++>YtQ}GUpxN z)Pw@3kMZpo7qwyWgMQ%mERycir%uIE@9Qw9s`I|~+UxD&g$uOf!l0=FzL=djNL;t( z%5-=J;71?*8ixFO@LXa}wYZr`gzfietH9{3fG77+gL{A_TKCpIWpDAq`a&3}J|fva z><9KoGwWkevdvgn?r8vOHge*n>T7%0yZpB9{1gOu*ni?k6&xF2P*K6oo-v$-gSTT> zNtumX5{z`O1~{ z-n;KcqJ8`J-S*di{awZYwS?ST?jn}`NvstoEPscM?Jo0ey}$$-4b%u+)TEeTKlhkh z3aFP1sz!~*ry$B%Au_nS`57DOWYcImXeeeDJYB$R3>C4HK%ifO}Ehrg4}3;ZgGizg3qo{OamjyTJm@4YXg>j4?+U+|Zcdzn9x5 zT-fQ%Ya9=LerE_AFsQ#X2oDl?Q4r{Zis?C^^h@_XuyjIA#=v*oB_t$39IuKY83r!m z8Q04}Ea?x4I>7a`jAMEP$OId5XBhm-Eulw@D}fWYkDfj4gf(6Nh;OXD%W_m%$}OQ% zu6$P(LtI@de$pVCF^g&0pQ<_gU3D{-pF@@NX^8I7W13c<_$_CLr4jbGfqp~AA!<6) zDI*Y~k7ud54tZE-({mz#$TnTur(dJC*jK>r*2DaZPl^+`4*3*;Wqv(hp0uTl4;9Yv z`{D#vJqMv+^$6dc;$T|5gej2mG=5EP#VD}wftyxycek|;YW@bVFv=dRUhvf{NI;2B zq!{=WD^M_kVozC_>5}IT$D?c`0Uc8;qu9^$bS;boxCOx&(l}yH|B#Oo4ao=_R>^^z zGI47uSS~JY2lJrRbYd6Dro^hSF{+Co)1-oA$-Qm%v_%XbZE`=pi;ChW_uD-jR`i&L zIVBt$_u4vXVCJQ*Q=~AbWcUao{ISPvAfGXuOss@6(>Hq($6-jJ3eV7rqCrP$^C)*bHc9i(s=o_g~1e*5U-_uIAW zzY5+T#yHMl3`E%v#@Vm5y8@Ap`tB1Ly2nrMwu?8;V9}VpgaCBra1k!EoDF;O^znA( zwO3Hv)Pf||WqD4rpB5e#H;gC2+)uCo;UVxjr?cZR&oFp}%&FW++BDQthR+2f87ljx zcsYwy>?8)NE?#^Ywcgj-n{U3^-hTV-I+IiD&9s-O?j=l;@bD0S+&1y}@uNscWlmL> zt^Pbf*E}KOCRm)<2qVVPN-P>~pc);5(2nukRc!;TQ@4Rh#4#bsGyRq?tD4L9;V<}% zL%!t1ywXQ2tm(?38P2}8!Gea&lVetCE70<$C9{|Oj6f9o19+q~atxw#O9?vpyO1;m z6L|=Af)(KKvtRsz?AV`1dQV~2PM(<0B8W%t$jr%@|MLA0+fV-a!}h_4AGJmHpL#yA zM!jsC3C`u6A+233e7k@%4P!Yya|HaDZ$}`EPn|i(B8?ghbKsTCzt)~*Fc~pmBHdqZ zwS&?0Lz&lF7zAf5GCqL^^|1V5AjMD0>vxVCqK{<(lFGTn@I((=H^$ySLffj2Cr(%L`!JfP_NOP zU^3j|!YIYW9VKAsXL2&!!S&gNfGs;}Yu<;J-d7=9><9_8-`Bp)4UUR1rNQQct_wq0 zfTu625mUH@KlG*VZhdh7w~Kgg$+*h`r2DH!TXk5RbsV|LesP&p7rrc%Jg51nl?@91>YxzK@6#2Ow?*FO!{vjAh_aZVrwT z3`GnX*fLoLJP0E}L704!FMbK*M9TX!cZT0eCyb5*9s_5HQQk-OHZFCEik#_Lwv;a= zqyYX8`S`GiDNFgM2tzqS?$5vbol=_~SJlV&N+*u|^z;mtka){v>_CVm?ft=r_YNB)D1p+s zvJp!4k@Vsi7yM-k#6`o37rq<5+&3Y}w?Hp^fdb$8J)#E+f2f87oAiYQft05&W1RcBh$3R9*Ys4 zR>;Yu#+~wkh@LnhP8m}Mmq@T-+wCz%A3pqOg-ID^21bsdy}5FI;g4E+ODqblCQ6TJLQP7j3~P!lZg{vS-($ zr`&@yH#ZZ8QhY-On_Fq_F8-xj3G9$;8-E+g5~C9(2WBv(ufD3}@(5OsJ%;B9gg+82 z7}b@PIaEN8AerTf!J)-Pj-i3s69;9uRHdvsD-pzUFzsR=)Xj1@{y8SbYAsSu_r0pN z_R@uy+NDdEqS|{2Y1moL{hNb1HEu~2gn@8m!63{G)f7+2BYm8AA+8&b#MuBo8!V!X zvtTkcy#>)meIs=o#s=EdRK!cu?!=p8hvSQG$s4@yV+yS{^f}rt`H|yLE+I_AXUxtb z9qx`h`2(-*b2#O8(MEz&248n28^Xr0UK$>fsdk92dQx|A&U1uSmLFFdFMP2Sy~BR$ zwbfb9edUbcdz}Be%mT#2`|Tgkoo%O731k7ley)U7!&x_Oab_ZWa-U%NdX+t^)?^x7 zR#jGJRO`5^sXJb7q313``WWqlM;KyRbH6i~65}o`@qv&gd!;$nU3Gp9C^>$qX)xxB4r;vB=FEctL8f`}=_AtEg-|~cMs-aC zOw>=jTf?xJixbvEhJ0OoG&^yR`im!~_so^{$Pdng9|d*%O@VQ$_5-)9hV`HwthZyl zX^SJyQHf4?-uAwq$?V|c4*>#ViT!)PmeKQ>x>ca`^^tpz0ERg9blefA91k7KL{Ayd zFs4C3#uISMttA?>J9YA8wq)q$aceFTI#$WRI=A1lZ(qM2!*S+oDee0i&&r|j8QdN9 z1v}=bYzBJv(%b7_308qVr@ss{2iE}ve*YlQi6cwqgw?N_Sc`b-6JtGbV-yO*Gz=aR zkC{Zn^kq6MCeKN4Uz*7SBEYGh`EhT688UTn%b?>+FNyF|xaRy9@ClW{Pd(wTJ_Hzg|ulaQ>-`hvT-Z^7)rQnDYEFc6HY8;Y4S zxz>LSe?r2@DLKUtRX+DtYM=$KHI{#wrpeFSvPs@UfDJqA_?yp0l!VKSbAc)-;y#z&l`_ZB_aa3&YL5M$Am68-?e8*5D-hn|K z+tDDDXEl#^kw9a+|2PuEUfeAPU3nu^^k=lePy^BGVRMQ+Au(Dj-R=Jxs-# z2oFJLTc{!!3%rKqRxWEpWg!Iz)qE{WU=7}6@rY;Q@+&TTo4hQQM$yK#ti)bFFDwB$$F@!&5m=Nb6;Qd3gtU9G}#&E}y3}t8GVGId7PnlYRQ4cIbQt!jF?BVoy z9+=XpX+1V!Sm$8!HegVfV^#SHR&h0y<33dxUZs-~Od+snXBj97FNq`jiG5O|I;!&? zMU~q9uri^ikP2M5aG|~Y^2<@xJbn5!drp!3*`DB9_1%tx0282gBR74_l>re}hL!2_ zh!tDGzA*+adz6aj#fF)%I>0hFWs)(i)Q83z(lIR($tBE9Uq;06df6CRkc%5I#Vz}C zttX86HhFBQJ;1nbY@4qVp?#y`tE#k%1+)!uy5zT~=>nSt3r-|5HG+|Ifk{cexE1wp zq=ZL~a*h&x?#Uz02xhPC)`#q^WuU8 z|6(wVm}cRk<`(63e|Fju_kurZ_O{529?xBtk4%GALwOy)wZiQsX4&^^tS4};!olH# z$KamFkmsJ~!P{pT0)++tN(B<=(?Wtr^aGK!3lJP5OT$iq1!IPDZ!Y_Y3p*P8o8?$E zYzDCCq|jq$cbTzvlkr+D-|39Ik5SpbfA4-R9Kz@pJx~jTE`}E43;MGN^*pxz%e4`S zKdmnRa;(pb?*W7Qd1>j-a6O%DJHcc%oYy|}qMz5qS5sI`*hSioCN(2EfN}Rp&}RrS zh_S4Qk>AKalOY3;gaEf$cP1``1YsRs@EXP$3&Cwb^Wd@nD&mbe#*^ZJEHQ2mmlbIo zc34f8fT}!rnpV>7A&EM?j$mULZrxKiGakz2V{~;l(ktT|k_7~HaObV3VRj*OaPJZo z%ZDRb2t$Y_DJ`zl6nDs`5KC3RUeCQ}0vkScGuM5WNe}s(c9;pi!%RbH^?ErOtaDU{ zQcQ`Yo>s53d3#wV(;HnKhDpfGge!F+yrE=7b6GFl^p`Ou?;PU*5j%l2VjRLeI3V$E zG6PYa94$BTEQ>0ev$J!k@o72tFa+!dQkJ_&S5TjWLklP&BHeo|Y&tfrQ3dnqyvW4(=uNnkvSp#M=Mv58ci4C{~59rt=lGCZfNIPL(nb?=vqF6Jt>x%V7y*{45K1`b$~}cnwTv>Mr3;*m^fCaRBhR5@c@sAvus9 zmwW9D%bz(+0*`6q?;s6UawKeQAY({Wlg}nZ$~g5`;updg@5+lbkRne*oV!PKns<_d z5%Ro8E%wT=5+5n+8rF(;*_-NKLidhkwhu&^1Cw!cJbhnjm>3orbt_(MTVJ0 z8oRi32?k(0M;hGbND_@QEg{`joyROsd}t_|2lGt6Hdqa9k0Gg$)k*7arn&t*{IM<>3(`g|xhUbqE%+s4 zD6Y{T7#zfL!R%O-am+djzmCHm1dplf~ie08k6E#pwy3UcuK z8xS~PP=5m?2M)iF5csqS$icy@p7rkF6yjGu?)VMidc6{I@at*R#4FJ@5Vg$Okg!AA zL(D!w@=SR~0}wAVCMMk7bn0ardEjUo5FW;NLN9BLL!>+^?Y_ESS?b}PlJo2r-@R_B z5AJbF&O@L|J24ZcVA7+dIQ(RlU257ei76z9Kg*iCk`!iHIj?}DdKS}WNy!txiqqp( zIfg>zVLE~1e#hZm=CoGlZBG-^gLmL8VJwpxMvJHE*lzu@PKiLYUYn6$UPy;OgNZ9) zQhR{-l%G!0T&69-+==e-NYSVlo;|C2sbYrcg8}qOo`mO(Ww-<7B; z0XPSP>bZVOP(6s=+jkk-FmpmvG!VD=>-|HwFpIqSZX0N=_x$olr?Jhs-VI^ZeqYnskOBfFKptfJnuNzTl`P6(~Y)Z zK4G~~Uk1i3MC>9$ImUUQN9M(E7Gs`Zx%wf;%Fs^RFlSRN%8a|%z#_o;a~ImYs=gRm zd4zfET_i9XCdyu7ag=o&=M&4Y1x~EH-~?XCu&%)9s@lFwThgHW$|(+0PJrPeUG)v> zN+OOI(HNl?)=3;J!+_*LK8`&u#EhYd5vC7+4Ty~ourjSIU?n;wgK=Gl@qS1QADsQX79ApQ#5gHihpz z>#}VrW#&qdLBM$@ALCW@V!mzRBr(K2czkXl5Hu;=5eCIPI)-P^3Rpz3!auR5q@*V} zCd`FAkDa-9|55srOsZpRZ5v=~3gfR<*za-V%wfh`nOW1dubH0snsk%uvp*ee2dsV8 z^Wf{ZLg0Ww{jH!m@c4a(KpzNv_V<+60m{j1aChSD{tiri8gsyiyDwZ4juKH0GMNaO z^7Jp_QsQSXokTF4vnm%pnILQMDQ8pdw_$pyN}hNju7rWs-sxBg5dgO18u?}2&uOj1>d)DwcL$G0TaW;Rg~FYY7sPeR66gyT=-xiFC)}Y5A0ArPxJ$>$0j09HLlD>wFCdXNo@6iDup zp%SfROc}J!s|8P{TuEW-B2!0tJXO)PnB%CUPCy_}D?uVX8ACM#s2OEfY6a6n8mb6y z!C-E~M9Bp2vcGgCA4!NrDo97DBMf!wusgtCtC5ig317Kd9o9~%X&vRVls!-`&UgfZ464ja41w@H3qv^%LwXnqn8uO}bun?V{GbiG&>W?KXY9&2b#ekzPN!ky$57*)=B(Lm+IUS#J22W*+DTrM07?tohfo`K3|(Uks7|8#JemjgFUDi{ z$ksxF{no_}+oLR|=S*PwrqbDr*;GR-*6Id0mTa+a)Vhl0X;W}gNvXJ|mIJ^_|6ouF z-iUzqd`BIbesOo1Hr`|b?a&-}i_x|f;&{twPf>0cRiZYJW#SDOaBgrS z&w3a_|2W}SlVUMdI_uX5Hwi^2?*t!`sfd+Ue(_A6d{nBsmWw_TO5G(d`+xS8EqN2Z z%1)r3uFrUyng!Ia{F9V^xy&gchVOc>IQ$Oj)Uybg?4byQLK>8%O4^^sta!phGTw|+ zln|1HGY*lAk@q153ox1#hSGGm)McOB-fO|icoHdOnJbL(P!1i6h@-tJL((FAEQ1mO zfndQV)Q|~wJmoggx1TlD8)#9`PLaX{)=D_)xMX5*~`W{!Kn(k zifW*+Q~Gd7gDDW!>uV&!WmvDmF9=c?Dw(P>_G6mni?mI3yGTgg2dD%OoTLC6huX3r zFbj~fq^I#5PXv|ZR8>)FC+WaUg-$gu^9Zx6g795t(>+AOaYHQB_Z-0pXD2)NvuS>*E0KJmArB8=`J@b z8Kgx?VIHGCKY*~B#1Dzye#>ympmHO@B(tH7z!$5>_qY-?%C&`><~qiviZLM^@Y%I; z0RRQ8Y}A$*&F&e(oG`z|IDSd z(tVy+Uwebah?BG#(r3lSwlWO4X$7u8&Pyg%sk7%wiceF#&&agHPj(u`L116%RtEnJ)@<*Dz&ka3{^!2wEb}}KrH*S_wJXGcF z3t#vGOx8NgAue_4@A4AA} z@WBUIw|$&`Flm|~SN6GsPcCvfP6=|$XM5U53jch^kA()$`E}vJb3-*Iwg%(5DWe(u zw74+KFn^o0_vR``q^u!jUYco-AE1i&X;0^>5`{?Uz{Mj)XRcS9g^+!JXz{N`ldBy z`%yMATEk{)8VHBdGQh!5Hl!Z;Q?<~qh^VKHcF|1!|?S9k2s z=lu`9I|LkS4z2?TeC8nFK=AyXQO7>-s_}FFnYbA(`g5m)tI@j1$a(7$o@?7CN; z{lmeO7zx7%f$Ff>#-3aJJYO&!%fAX_ z@F9Yaawof?jzhW?s=zqBCmKHz*6u}7QhI212IhL5gL*G+aqrWHyn;P<9k}Atu=` zDiJHWNj&Sqf7A&l=qIE~`oL1Af$*^`OjspqO2`cBQ8ZKRIg~V&p!a)+iGGJYf->T& zJMJKX+8$dZ@Du9wI1J+!$E@sb&5|T4lUVL$>t@@a06vvCj>DKva!+t83B{3ghqg$W zDR-W@TT_|b)LKT>vQi=2m}eMN-X*m`1j@udqOHdOi2c5}%XGP~c8a#x;kHdQA8LMD zTArXjhM7k4sJf%=wumaH4CA?T=i2}L=YNs+zu_#@k3YH=CL>G~alFKpW5-Uk?|kRa z+Q0kGcQ8tH1?!MU$p?R`HbvX{HH|=ASojaDBIT1{pI0qdtEw_B zqz5A-A@9|tO$kr?SP#Pp64u6 z`fmH#Pyf07{oj1AU8DXIZ>LV5Z(sQ0m+|{jd-Lsg+eOX?J$7=TeRAt&`>VhDZ|!@3 z^;hkqk3PaG@e+GS+1HFj(tYETFnTho?m&FY4G5X)7_2hR z(&P3J|4(R(8`rLJhT^04$+cg#2e_@lpwiMvRZ-)fI>H`cj4gq?j~+f@fdfWbymVnF zxVlU^meNnvGEma0^w~uKrSIbS7R+!|o@qSigBlxcCmRd`8CZe{xZD5f`?fU%vwPiz zwP6gq1D?59G{zzp0fP&|gCz4|ShXl(gehZ!GoH9Bt`=_jE)-yIWkq5_B(IzpUFzw%t-anyBZVi(}#sgrGGJX2AdHT&y;VNPL+q=N;y^p-> z`+R-&1^HaQ9x$k%%Vz)mue1Zr-X!#FdG+gen3vHv;nM5%?}Jqh19twJ)FIs2?*ITm z07*naRG%9r977m9GKevl5i4HVQNMDx$t|zQtn8DYOZ%BuJ&Zp%W_Zk?DPbmKSp#uRT5dE%&Fj<)^t-0VHHhKb5HbVMvmWrIYv~e<>Q< zzxII0rg5eG1sChlArLt5Gk~xHRPyys)E>rU;+61~f@Mvfy2%)MS;v&4UK2;+5$Tg^ zmWN<=wBoCZ;EF17+lx$W8orUObOMD)4_slMBn)Bv=20n{=D7;fx4y9i5$MF~B!{{r z#5W{01>hYf%E}ns(rRc4(w29QL-C29dqI_Kww+Z%pu9+Nl`gB^Dl4}Q)94wg6Fbvk z`(ywcM~HaK9B(k$Zkmo0ZPZth&TfJ`TQblDvwhf4s-$Iodx`WOoyD^%9q?oU8r;zbqb?uuZ(Ij-4YK)kh@N}YS##R~c-u#P zN`_AWDwjur{L+^>uH!uJs!dWD z?q_hFZ=HcEPjD32P+i`^d&eL=WY8*vZQmJE)TF7aY1w~u|818b@u~+sVPD_^sXjv> z{Pge16*!Sv!g!rKdzRyHj-u}T5=W~b6$XA6&R?M3o9)cmm)e)V@^#L3eKY${X-3Wf z{jmM$pMTo^`+xsId;f#?1EZuZ4wIu>48|ipRoYLp$#65?x`-kJraHQdD>7!gFmc-) z`QX0h%~d4agg5MwS((0**&nvBa6IGLDo4QVAUU5T-iaea;g5Vs`mW!JemgUZIS%9mXVlpF7O=E*mI}?&RpGv5$0^) z6G+Q1U%+6>0!$jXz4o*n<>;ifd2sOLarXbtwPTd;_=)4~1UI&`+x@!>?f(7SFt!|9 zvqE3lSpuCOAo;xyJZM+c<0l8p&`MY5I6rsx2>pkq5+=bX;G{$w-FnK-SQ6Mdj|H1Z z#c={yF}{RIr>s#qxArc62uKprB6GD3Zn(Qd#Xz1oj!*WYEZpi|{|+ky+BmiXQO94> z2_}I<14a>ui#U5%MKq*;-K%2m#frf6TivH~ff%s2XfBNq%yvDJdCReuxkcQf-#Cvsy-j07!Q*Ds8qqqpc;vPN zk6Ds|Rn^zNcK6=hcI)=7?8z1x9s9*c$4Zgb?LDSz8Ppi^X+^s?{k*pPXQ19;$SCKhbz1%QGpD^ePIz|oJaKf;`i+Z0pij&`B??{b@@YIJ zgz?8s^Y=afgq6_J-GQVJCT7T$L66Bg1oPlVNXMtq5EWHB2T1Sd#-jRs&XIIXz1L&( z9{1s^d!`VUV<^iI(=u3Q2U_=As2=EX4H7vrmQ_C!Nk~)KyG$!mmMTMxHx0hVlb|TI zED4+au&F@34fhhPx61Q**Zv)V3ATXP$;Q>slJxN8UAKaab(Kk#>5;jqNP7l1Op8ft zaR2o3kdpoh_PngDz$|gh$prgQCuOuyZykq0^*9=t zxGBw@H`PK>g9Hff3f$tUQI>JlY>6|rA-QOEiyd5uPJwe9CWa zQvNNNVE_ksT$Pu)8v&wxyt#Ft5uO+E?agU{KSR1F>OXnRF$j?ym*K zVK#x+A?_&*+K?X_wAu42E2}hkg8h6^$D+L{0qxbtk7 z1I&hTZ@*e4p$q=BhE}URQ?(u0ZI>@!hB-Wvb3e5@e0X-Az16Rf##Fm=|6cpqFMrv- z`w!o1zxeQd)T1B5#BN~08Z~EBW~XVF9PdKwn!gJXS_$5P2%PZP2HI(oHg}A&toCi0 zzV-E$wz~KjgH=yy$LV$&hWU-lueR6UcmpZ*EA1TTy1E#&gJgCa72nmxM{V)pT~xI1 zwxyM&_Ol=VsNF(c``(?KFu9y#d*nDRP3|m02y7)FN>jClyMrWf83R>Q907Fn(0rRe zJ>AyX7d(yMoohGRDf;qz6PM5C(aTg^h*w3T1qi z`|{;W?Zj!$7G$HR6qLl`|W$*`|I}0U;MP)y>lI_;1Ap8%56$T7#4cm`#N)Y zlKr|!@6VsYQt)hBWc*k~b$Anmah#nya=0Ci)omDj+Dlb&`;agV)eZb;n1VUasOz%` zw(U42-hc<*HHrq2NJV&5J0%RxF0g4$ISU3LwBxLcCpCV_@QQB|XCUA^kz_ zeLS|sg7rc8J*?M#|7D4dvln9TZGX7W$LW#XJf(`${<;Mk}MSL`x;%^T?V>n7yPsa;z|&604J()hW|Cp+pqM4@12ivl1C3 zj1ReoL4`@(g0Ms)J3h7wgGYFt4M~nn#Ewj*Oe4iqB8sAEp1b6+1v6|q*py|WCh>8k zUAyeJMRFOb4&@m`I@`E|^Wz$!K`I6ltfWlll#ECl_}VHQ0pt0h9#dmK5^i=AJp3W3 zu;PYEbt%a&65{5KG?a~L@MVm>vQwyZx}YHgGEJQ|u`>m?J4tyhvnstY%p~v#M=J)G z(E^1C2T!n0`}FBb``OPvfJi@tHQQI(+c4!bFbikTUW7maDge~gc~xOwef9Nr=FA1+ zqF#FYA%24eS8%~9MBOXJt?|KbkmFon&PoHI*nN@Ky}Yj6%gA{JN=ERuzQg6)sE_EL zAmVBTt-ezA($lc!B_UOL8qPjki%gc$Z(%QSrg5rCEiUtv@!8ej6E}#L@xtR}R$%&; zuv+`^C)e9ge*UxecR%<(M-kl$6NRR27Q~b!yVEhowrEh*HU+!ta~U^*kgbkwl(omo8t1IejzI>Q`TV6)EO)gFgjlX*X71mN<{}!R_nq zV^oW8-nri%aE!|$hLz?Cw6@Ly4QloqEKH1J1j6k7eaq_Ha|5OBXO;HU6+I9A0hjzrT+39T;yuN`IO|0(<(@JTNET z@e^Tk-TQr$I+vgsMmwvKL`kkNE`_uX>g z*o$P@^dD|Qj4p$R;R``-6b8Etc*HRc%VB)3`pxU;+xS%nh)xO?1~PT4x)c)$u_zJZ zq%VcVe~M)J`AB^sCv!>LBz_I-#!IIgd3%$FF4o1iolz13 zR&6N_di1D0xd#KV3h~L_vPmST<1n3L?Dv#G)rzd_k1DvGL1lG?w2%*y^dyX)(pDK& zt?O=*)h1yzs-(PBYrPsM3Zn{BFphfg=9p4ckBLE*7D7?x#Qm<3oWO8S>>?3EEx7T% z4THM{LEOe5=9$pPP>I|@jd_b>I)v^xVT6Zad4VZ`;ULU}=_?7f4Ea;?LV?LgRb(JV z+snvV7u(7_{D+An9m|yPqJsG1pG|Mw(O;f`nVJO9N=fCL-QOtjF1$l{`>aoxr9c8N z%1c|S5}5@Y7!uPp*I$41ar@8z`G3zDqgSuK22pZ6`;jD2Bw##}=Gyh^Fha}0MU81Z zq5UOVrh$tLnmDA&*b@60Jyu5e2-BP;$twLi659>bNjI<_yNMNA8AS2gEBHrW^U9cG zorgP)qaVv__=;n^e(T=jjGl(o!|?tM@r3=Rj1bsmyLlT9u!Acu1E5R})9$%J9+?6N zu;l7-DV*2JF*r0*B+v$*gaM4vCKIO}v#*l&*#-~Ac_o*^I}8>$utD8D&SnF6jDwRd zF1+%}h4!T{eWAVf`s?kbmo9R)>uDAR=83=HI1j*VC%9Ss)! z^4Hg*mGFaqe!qQu<38tlKE^8ViKyVR#1bjvAw=$~9Om@{e5pq~5Y z)i>Ig-hI2he(4o><~8=?{-nMCi=Vd--v1@#IMlxW^{=(dmoK+3zV}Dj%jP+^ckkb6 zfBW74TW}zK|2BrUUV+%fs`u%I_RX(-rJY?sLVEfr^=1DneRZ8SKaHOYhck!gspr{t z@s-QCmlfS*VEZ)qLth1MwnH)b;>U&>gOK= z*bo*s<}7hDTMIOfW>S3HXLR@7^Je`MN4q6!LJfK0qyG@57}x%7D8m`Fp1ymDm+lGn zGyM?Be6(|bM>kSOq*2(s_@mR{K5{#F`CLMv<5nsUPDryb;bhz&Fb71_H$NgBZ}uN> z8az9WRc;L>&2!w0S|BdWX&+z?3+XQGd26ul?wz}+>feWvWg(OWS|zLc`R(G7`F8x@ z-w@)s2)iF$M`ccts+9ZVe4gJA7}U>m>;E3s-A-Md_|pqlehetX_>w_@IDIgX&>Y3r zJp<5?mhZZKO460y{=s7i)dTk@aSdx8<~1hA;XBVrJoJ1%U-R1+e=qyWZ%8oC)+0=k zY2>cC*XZ6wDjM&(tLK}1_!;8&=l-;MS&U+emRmyI9Ap5a(wjiSs>-2zm_!F&-YdQG zf376)>u#gA=ngz}GyeXoic)RYnf*NRFl?lhDFYJ@Zc2B|-S@yRFO_0X*%f*s`;Tws zX>g?lQno&=>%OQJ-aw|k@2I$; z5z%2*AT4tdPwTki(3VUj3|iDzks@tupw_r@59!oO+gK(%X|E$)oIrXyL0HcsRrS_Z zlYtmV;=-Y&WI`S?gj`BZJw!r@9Au<|(lDtq2cf@_{zZyuB1kkP%av|vHFlg84hidm zokXZ26zT>cT}Rothm)0KSEV@`WDCh^@@g`t)LDp22ve@?jg`AW!a5F{4r9rD-KNSj$>!j!=nLePFLtr);3#la64bAGCeDX9bS@lR;U(C@Lq zC?->Hsh0_0XMQri((PJv%_0JDc!D+9Yu7$%zxve&?bfYZFb?d+WbcvwTGgFG8n+7b zAYrmbdoM39he4HK@vJ;8Fk1&zUOmfHwK3r;euqItin=aiL|PkI%-w_mis2dJd$}-D zD!9g}{#wR!3bzv|KUGirMYUbt0-Fj`;d|e$D2}&4CY-x{#QgLTUf_g_21=}P1Y3eH z697o#JGL7}Y4PV9HP=a`|I_T5R0Va5g%6X-qSlC+sygEuVsH}J9D>oD;M`O*-9&{h z$1j0@leF0}q!TZlIoaNM<7)fn*T3GbzV!lDqW zzA}oJE??y+pP6>!sp1G23A=A z7C&=*6zyfNsIk(qkc;}tpxR?-FtI??F87StEWpqwGft8BHse?{8yt^~MEq(s-3!Jw zwmJT$HTUvy>?Cbfj%6yHKTNAGdq460sDhPqesRdZ9^&i1AjFs9P01~g<+4nD+_wxB zEr};C@EB4Uc_o{JpU))(#Fqi{Qh(_NRyTrYVHykh=qGvyLwVHr=R)Gb@dXx%PGynl z@ZA|uuyE42GO%8b?;1<;UO?KayJNcJeHPo8ioH^ldd+WPyRW{9<u55;d-byE)qeKFH6`@enf?b)CE{R3MG z9or~`cnU0)OVQ0^2u&fvNJIFRG?%uwJ!LLz%YBJjUT7)YY1jDI_u$A!{u8ItPhesh zllqdbcQMG4Z{(!yebsRO^ItLd<6=^Sm-Q+Pg z2_Zj;vhNgBILw88qtf&RPQvn1Zkf{-Ce}TsKneJ1Z`k%QhgfsvSr@q3(~5({x9RoU zQc9fj4GfiH?*Pv!jNQcIF(ARoYJ_-JCECwoP?6RFlUQmb8TaANATh3^H!wm2Gmr%+ zfT0D^8B{gh_xtOQKR})JBT_NhYV)W?f}^@PhS;}M@%7T$w8XtQ?RlLN^BHGwlhJT> z-fx+1;U!xbxZy7@iCZ#!+20MmIo71_SasV@Cfs~&!`^Dd*?;+2VPW62I-~QrXx64=GZCBpD(SH21Puov_@hi3s zdfHZ@txi#9SlfE)gkzGa~urW7cLJM0ZC9h`YEJA10V z{q{#pQ@#|7`3lxiM@L-$JdMIUgCeU(Ux!pIx89F4T{>-%db3ZHA0S5hAZjl)2(6t# zlgS72h4r8MhF^fMB~=gIa+?EBdH|0@CFlo>6|c}z(p%UrseIQ+JLrR$o;Kuu%+{p? zESr?q*#cT~t>=L?!;U-_zsfW@`gM5h7jO*s(?-l?f;Rk>Z-h+f(P4c9sETy_`=(JK z+z}ob_(WFW**;I+>Q;FB%dpPyBcCY?xwPgS%Lp#BuKfaoP7fbEKpAz5xax2U)&w(V z))}n4MccjJ-h1yxruo_qt1qQJ(GK*^F7K!9ajC{&TgXFU(D}K7j(@*~0(9rc$1w$d zcPU_}@J}7}0kzv9E*(Jc1n8X%Nr3%A|KNE&_^WU`mlD+d=-asrfQAm`bsR=<_>7P4 zi95pAk7xu4uS05(5ue1dTt4)7L!Jezg6ox-*3qAb$I-=7l2s1THg)08?GRp}ydi=D zadoJOGr^%Cdt2wBMCNWe2r^cIH%u5M_(zb3ex=+iA|0e3(ZjTboTwbRPe27$_z+Lr zgjP5sXbG9HQX0KSaYXRS)&uH59398tSwW-U(5XsLVTU6p&z?&BhkGuj>x$|Dg^V+3 zKNW*#!z!*;Gj*%b2&5GZ5fAwg7QA>;Cc5mFL~A?DO?0Z z6isYG#6w9%0!6pu74?~HU3ZFA4-1V`YsEL7QTe!zvyLgnB@gcO z)@!^;V41o$tl4YpTB4n{nyJpyZH9VMshU7Ba2uYq6%>LQ6cL5-4V?C9-OK<~>P!WZ zd_XjVDnWFpPx+JmZVk$I8N|sf1nI;(%chcQyNS{m8p`p82aqI9+&B-aHx`vUX$}2{ zQGK_@F@HfMT4L3YZLklpWI#uSm$XLgf|UbQ;sTINx77)c47|3EU7W36VnGOP5E;m4 z8%I8&Hy&@taHK;7$PT>#3wUrY1$6?t>v`8HbSmRok*7#={=&I-{@V4naN$yWff@Gk zv*&G{sdGCxFFJwO+Dok2{P4YZ+V{WrN&Dyq@n&V(Oh}*(SWit|tPy{45r-uxcDq<# zoeq2&3+}m7^YO+xgF-om^1Fb-J9q7Lo8@_Yj(ujaq^c0Fv!|+4iFJPBz3YqTZ~~=* z93>9L>&4^}G@glaI)$fCx1YFs{~_mnESsy3TUlm?#L7#qY-h2K2W%|oYa2LGTUpFBZ|ioPeBDcT84K#O z#YZ?-TMggK6V{h}>snbLW##j*mB)0UFq{9IQpQyULHD+e17c-?3sM_Z zIZCRXiDCIW48S~i=ErOD9Da=zD~aKpB&TZ}APlf7zVA(caGJLA8?MGjun?!5c{Xgo z*Z3ythZzzgd^5JQt++fYG>#$<=?6FhF-@j!A$S%}h&iMYR8GsF(86_G8Vz~oHJ!X+ zBRuW&5m@%IHkp6wqvQD6HRU}(EN{g{R4W+R!t)uJ)=N5l^Fs+KtEnFw1$&hwh1aUL z0YG31Kp6Eiy5y$gaP(?i6ZNwa2gX2@65qtFh?Hk&WSrm*j^p60jkI`ztM7>J{+F3b z&AnU6_?6sX+Zm@BW{*y+Z8~Pr3C#q`*96we$w{2;@LYQr;vh+7(6y+%FAGU>2Drkh z%Bfwt7F_6qfH;9t=CoM|iQ)zQyeEIxa@IOfEq$tMhT#B-cgnB3tmRC3QZ_#7;WO8w zx;D{MWy`6aD$ej3V0A8}-YBeO0uIrH)re7Q$M6nZ4w$r}ma<6=);+?oe`pWD1Bp z@R73n6w{UWDOXqERD$JY6+xY7IAzyE;obBK=qi7%HI)uqC|mNBf{^KozswpqgeloG2Q0jDI=K>4$;XKrO6Vs020NeJq8j~ zUM=GmZ9wNq_3Z%>kO^Orhy4VZgxBP={MiRtj1+~R;VO;NZmet$`+XJh3?A_^!oDwz z$XOWHue_Xa-ya{p7ZeCv{FWt=HSFJG^@Jxf^F)54jo63#z1o3?cNw$|kMd*Nae!r# zSr-cn^YP+)iX{T>jcS|9>^OMQ!(|)}$hg$wK7&;2_F2ppan0&BZ9?aW_Qm$Y_W#N# zH6Uc_>hE(MxYtn28U8hf1voxN6gXB;N2EBu`CX?#Z^U*i-uKbfky2J)x)fv7=G3w?ejYaOG4!0=%nG6Wo8@?+8*c0h+u0~M|h zVZ?3WAU++pB<6?Q5_iaANLO$3#x(ZOdBZg@d>Rl)P`x)KC;4a3E^+JeOp?R6mFwa7 z=}1k-+oD?u@?$ClrVtiqzt7EUKPg)eBWj+LiD?m-c!!;U7v!U`LRk`yAY39$A`^@E zL%DL5>M6HZk`u$zpIp5kj>GRPjS!9HU!EyLWHnwGHy=N4{9LJGc~v+sj4DzL2f00< zf$6HeybvG)q4ngRq+0aMcvpJz@nrZl%0@o2OeCJ2M7 z2^ku8kJJo0@CaOo7>p;D6Q=PWMd$$gWS@Abc!YBpXE+4{7@ier!6%kiN(}y0^0H7W z+aUD7UD<*W+3H6P)Z^|YpvZyNDl;g2TfTV#-i~^%Tk3hfTN{Z z7=kw{m*5L1rv50u(GFT^ZIJjGK;kZ#0WW>Ayv4m!s-?MWti^2$Wn&FG>!jx_TeMuh z^j2GCitdwVIG4gIx`#ufsfAfQ_Rh5{O#i)zC1ZhSaopV6Ymc8i!K?DG+TFYN+6x?r zJw`#*TkrFyPK94@vnZUG&Yx~~uU>8s*#76nM<2BhKmMd$yn40GojQX;I>A;kt-bfo zmG-B9_&o-N#@jD{Jq?We?a7npZG|mfPAuS=a}Mk7S)8Kas7R+mwrADwX$Fr@VO6#+MHowo3no~&A{W;N02UcNf|7(r#zSXPPVxR zB6SFVa8+Nnp8Ydz^#|0s$qA8j4qA>}Vmo(`gHX^II;gsmPygc$d6j}XMkm>MS<6&m z;spR^dVKueQQ%)vt+JCxzaG6W&a!_C?w5tmA4e!~te_qt$MM7ODg{coKftb!t~$c1px6bu{vpe=g3*wqK8V$07{^1HIrC(g z9hR_6rSM&c9SYx6@B zEH{`r6u=#wG@V$~6hZG0N)Tv`Yo7fYa2DXTqt|P{rf!I*;4W$rbnM&hyb~adfjWeh z<(ph{&nvFIj7c(jHu(T!ptx}ICteCnRI;~>GnirSCn;Z*p|Y2w6z-M5H3S${PEl!4 zu?!sX50*uLZbd7HmK+F&fJYqYH;Ls?@{u1+Eptvk+`+4>${RK;ct#+@ zbV>ID4WFvkk!>uLyhFEvOZh3wnnhNnttoY&7(7sn`H;$cDHX_S88PM_PMGwbt72vu z{4v@-UTB~;MWnQ3SQbCqo)+F}gVH_9oEU|k)?v{viXqc_RlZbolQ-qbM?86mn6!l& zJcoh^)UI_@iB(b1$|K)dNUb&^mZ{UAUa7r`A8A+*%dD$5&3=+vgSM!!v^5l~Ni1Sh zly{mk&ah4q5gXGK$|08NZNlV#{Y*`wn5LcE)-5!L{YojF(n@}@tkf3*iM$&=wmi_v zGFU!;#M5_0e3HZx*I)9QycbV3^3x92~HH+cafqlU4Hda%@w^1x(!4`&j z!B|co-_;>krf&O2LZ+?yWXv5nQptW1Aj9>u)Bfc3XjcDzo!up&$1Vx zj*b)95;={cr!Z{o?=odA5#mitiRqsXTX>raM6!xX1L|&pw?1Y(SI0 zZ9n>lAGJ@u_r3O?{*S+If5;%k6|AeXQ)fbtbEl`;AETho-ePQXhazK>;e{Riv?`wSs;yZzB0{UP3YZ!n#AKD3wqX;s{y zZ?~nFYwh+Ow&203(l37gllF_B{j}Y`cbjR+FTtB>{Lt_6Ti4oO{MBEyi>$MKzWAbj zcI#$aVY{A{HJm58$UAF%nRcAIf&R2NXOw8g)sni;;FJSL>TdFeZA|4k)F#Ze!wPy@ zV)ypeN*Jd;9CXOqQfehj3v_Iyvo)DE{kMs#4((Gw6)QM#wW2$C1n<|hZg_~cV%x8N zf%LXbl27{0psl4}2Lr#4L-zpB7=uHiaip)8KS=H&pM_85uP~YKIN{G6q#JR3Pc*zb zzI=NrFtEdKRe*tIl15g@3>X>K7Vm|2VSnwBKD)k}KIOe^>3iFg`yyYybTQ|xn>QH< z+Q3q}p6UBe*SF7H#d)Dq{Jn1AAZeEGxN?I1y1cJ~S_6&rk1U(9?S{d{h0}{!=Z9<9 z_n3zz$dTh%K|Ml_ix3Uq}--26cKT!LbCItreC%+epx>hlpJZV3u@5cB|k3)2z! z#0`-nOq$4(AdiCKT_RUFfb3An*%#^H?BoK6=OKsmKT#Sw%zib^p|c)Hoj{-t9aB)q z50TA_^eOw0uc5vkeUuIGsnE)Og80b?eTZ$CS#-MeI0dbKEsb}A3SCGrLd83uJ?We+ zdsnb~EOD?-_Oa}B1yyC%G=Uc!3S!}QfJMJE@4zFC`30HWC$TRpoJ%LI%0iTyPOH(i z%F*MQAor%_JbIWbq5P|)`hjs;qG8HvqTo*ygv3Bl=PFAjRw6(_g*p@|C(p&2NgQ95 zwW?rPb}f8-zIe+!q{1zhtnCkyk8Qt3PLbbYIb z0|#Q5^|OJeph{Mv#hVfeh!1q>DGkBgY$_j|p_sQneafzDT$9`i^F47VupH?j(HYPY zWC;UXjeE&eY*gTt=O@|9V|pH;9FIBfDg?!#+k=Z|aR@JiZS=hl<=DzYYv!e~4maspF= z@C1xXW4gm_#jH%5_$d_k!C))y6(vRMM56{7FE3wx;`Oe2o z^SzuY-kF9Az1&Vpqx>q4n^aJrEiSkF?8*B0>5KLXYmDBnCt1(x)O&rJox)P{4i?mF z@4nwoJzs3g8@p}#mp38L8gNgy?m8+ z4^Gxi*k~ zZ+jf6^#MTo&E81tG;`P=6|d#HMt@`fUi~S37=5_yKnHp5TYQNr`+E46!8^Vu0%1p{n*%vQ(%5q*J*s)IBc^`pIoUqPoZ5})6;v~O1Y zV+Hlis_);M(xy|fa5%jL4==P z0U{A0sqRPV2rf*-Z#boY(j5NjA$6@Zyw8p4DsC>q@r4S47Cr=B>r=tbs{)ZE2@V52 zgI|T_twOvXJ)Jh`o!8GG0Yar1C6=kE`mE5ULa8#G=|Hh65=N2_7vQmma>qS5^+X5`&^iJo0%{a^tu3SzB^6(-kg=Gm zAaICN=)p~RLTi`;E)NqZ2$o4N#PWldn^-^*!ZTuw5;wtm#V9@0!w$5QRtnR?t^GWq zB^fxqYT7k*l*8>82QBK+4Z1W`1Hc7WzKM? zM^B-(yA{YOEO1kdYU|`;7vK+$C;*OO&1R%@Dpzv z&&igv24pN*9i8{Yvj)fHZOcO4hyDsa)UOsN$}aDCN@vqX@P?jRH0288WeTLlUwSv$^`b57YjK20Ty^Oh9*p(-o&D* zWlo1iv3_D{6lcBWirggAY2m!^NgOo6qx%j9Xvs&>u|D!6LooQ{apDFH?WvR0S; zHsJyJLt!q;CcJhQkGgK#;(3lO9CXHe@7`kjfB*LXX@B!K|5v+v?{*wj&CRmy3cNf; z9@e7+Gv;mEbsyPRtIO>nQ-J^Pzxf-iv>R;!2T8N6eLa2dGHECisLU`MV4n4@XHLv! zYVb*{peIhbj&vSHl6{DASR@aw(gy$M|NL9_CSGoT`p4g8@6yZd^k4oPiZOxnBP_uv zk9z1`N2y;~-NM-s?GZX{;7nzWnGq_iGxMkL_WKSFpiZ`RaC7g|7tbHJ`*&|qKXcG) z0l^q$be64&7S1qb{1g@&rW>Ea(=m%@9h^x!40mX$!D7soR(ke!U2qLRN#5R9Sxu!d zrmkt~8MvZ6ne`$Qa5!}2);If(FxVallRv{~D!79}SyS<&+761a3|jmr57l8hg5i5_ zYSv4IIa