Naze32 clone with Frysky receiver
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

rx.c 14KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477
  1. /*
  2. * FrSky RX 2-way protocol
  3. */
  4. #include <stdint.h>
  5. #include <avr/io.h>
  6. #include <avr/interrupt.h>
  7. #include <avr/eeprom.h>
  8. #include <avr/wdt.h>
  9. #include "cc2500.h"
  10. #include "cppm.h"
  11. #include "spi.h"
  12. #include "timer.h"
  13. #include "rx.h"
  14. #include "main.h"
  15. #define CHANNELS 8
  16. #define PPM_MIN 1000
  17. #define PPM_MAX 2000
  18. #define HOP_DATA_LENGTH 60
  19. #define EEPROM_BASE_ADDRESS 100
  20. #define MISSING_PACKET_DELAY 9
  21. #define SEEK_CHANNEL_SKIP 13
  22. #define MAX_MISSING_PACKET 20
  23. #define FAILSAFE_MISSING_PACKET 170
  24. #define RSSI_OVER_PPM 7
  25. #define RSSI_OFFSET 71
  26. #define RSSI_MIN -103
  27. #define RSSI_MAX -96
  28. #define PPM_SCALE 0.67
  29. uint8_t ccData[27];
  30. uint8_t ccLen;
  31. uint8_t packet = 0;
  32. uint8_t channr = 0;
  33. uint8_t missingPackets = 0;
  34. uint8_t hopData[HOP_DATA_LENGTH];
  35. uint8_t listLength;
  36. uint8_t txid[2];
  37. uint8_t counter = 0;
  38. uint8_t failed = 0;
  39. uint8_t frequencyOffsetHack = 0;
  40. uint16_t c[8];
  41. int rssi;
  42. // original 0x5C 0x76 0x27
  43. uint8_t freq2 = 0x5C, freq1 = 0x70, freq0 = 0x00;
  44. static uint16_t ppmBuffer[CHANNELS];
  45. static long map(long x, long in_min, long in_max, long out_min, long out_max);
  46. static long constrain(long x, long min, long max);
  47. static void initialize(uint8_t bind);
  48. static void binding(void);
  49. static void tuning(void);
  50. static void performBind(void);
  51. static void nextChannel(uint8_t skip);
  52. static void readBindingData(void);
  53. static void writeBindingData(void);
  54. void rxInit(void) {
  55. GDO_dir;
  56. debugWrite("CC2500: initializing\n");
  57. initialize(1); // binding
  58. debugWrite("CC2500: binding\n");
  59. binding();
  60. debugWrite("CC2500: receiving\n");
  61. initialize(0); // data
  62. cc2500WriteReg(CC2500_0A_CHANNR, hopData[channr]);// 0A - hop
  63. cc2500WriteReg(CC2500_23_FSCAL3, 0x89); // 23 - 89
  64. cc2500Strobe(CC2500_SRX);
  65. }
  66. static void initialize(uint8_t bind) {
  67. cc2500ResetChip();
  68. cc2500WriteReg(CC2500_02_IOCFG0, 0x01); // RX complete interrupt(GDO0)
  69. cc2500WriteReg(CC2500_17_MCSM1, 0x0F);
  70. cc2500WriteReg(CC2500_18_MCSM0, 0x18);
  71. cc2500WriteReg(CC2500_06_PKTLEN, 0x19); // Leave room for appended status bytes
  72. cc2500WriteReg(CC2500_08_PKTCTRL0, 0x05);
  73. cc2500WriteReg(CC2500_3E_PATABLE, 0xFF);
  74. cc2500WriteReg(CC2500_0B_FSCTRL1, 0x08);
  75. cc2500WriteReg(CC2500_0C_FSCTRL0, 0x00);
  76. #ifdef FREQ_ORIGINAL
  77. /*
  78. * According to the internet, these are the default FrSky
  79. * FREQ values (0x5C7627) which should equal 2.404GHz.
  80. * The datasheet mentions Fcarrier = Fxosc * FREQ / 2^16
  81. * Therefore, FrSky seems to be using 26MHz too...?
  82. */
  83. cc2500WriteReg(CC2500_0D_FREQ2, 0x5C);
  84. cc2500WriteReg(CC2500_0E_FREQ1, 0x76);
  85. cc2500WriteReg(CC2500_0F_FREQ0, 0x27);
  86. #else
  87. cc2500WriteReg(CC2500_0D_FREQ2, 0x5B); // freq2
  88. cc2500WriteReg(CC2500_0E_FREQ1, 0x00); // freq1
  89. cc2500WriteReg(CC2500_0F_FREQ0, 0x00); // freq0
  90. #endif
  91. cc2500WriteReg(CC2500_10_MDMCFG4, 0xAA);
  92. cc2500WriteReg(CC2500_11_MDMCFG3, 0x39);
  93. cc2500WriteReg(CC2500_12_MDMCFG2, 0x11);
  94. cc2500WriteReg(CC2500_13_MDMCFG1, 0x23);
  95. cc2500WriteReg(CC2500_14_MDMCFG0, 0x7A);
  96. cc2500WriteReg(CC2500_15_DEVIATN, 0x42);
  97. cc2500WriteReg(CC2500_19_FOCCFG, 0x16);
  98. cc2500WriteReg(CC2500_1A_BSCFG, 0x6C);
  99. cc2500WriteReg(CC2500_1B_AGCCTRL2, 0x03);
  100. cc2500WriteReg(CC2500_1C_AGCCTRL1, 0x40);
  101. cc2500WriteReg(CC2500_1D_AGCCTRL0, 0x91);
  102. cc2500WriteReg(CC2500_21_FREND1, 0x56);
  103. cc2500WriteReg(CC2500_22_FREND0, 0x10);
  104. cc2500WriteReg(CC2500_23_FSCAL3, 0xA9);
  105. cc2500WriteReg(CC2500_24_FSCAL2, 0x05);
  106. cc2500WriteReg(CC2500_25_FSCAL1, 0x00);
  107. cc2500WriteReg(CC2500_26_FSCAL0, 0x11);
  108. //cc2500WriteReg(CC2500_29_FSTEST, 0x59);
  109. //cc2500WriteReg(CC2500_2C_TEST2, 0x88);
  110. //cc2500WriteReg(CC2500_2D_TEST1, 0x31);
  111. //cc2500WriteReg(CC2500_2E_TEST0, 0x0B);
  112. //cc2500WriteReg(CC2500_03_FIFOTHR, 0x0F); // 0x07?
  113. cc2500WriteReg(CC2500_09_ADDR, bind ? 0x03 : txid[0]);
  114. //cc2500WriteReg(CC2500_09_ADDR, bind ? 0x00 : txid[0]);
  115. debugWrite("CC2500: Entering IDLE mode...\n");
  116. cc2500Strobe(CC2500_SIDLE); // Go to idle...
  117. #ifdef DEBUG
  118. uint8_t part = cc2500ReadReg(CC2500_30_PARTNUM);
  119. uint8_t version = cc2500ReadReg(CC2500_31_VERSION);
  120. debugWrite("CC2500: Part Number: 0x");
  121. debugHex(part);
  122. debugWrite("\nCC2500: Version: 0x");
  123. debugHex(version);
  124. debugWrite("\n");
  125. if ((part != 0x80) || (version != 0x03)) {
  126. debugWrite("INVALID CC2500 STATUS! IT MAY BE DEAD!\n");
  127. }
  128. #endif
  129. // hack: Append status, filter by address, auto-flush on bad crc, PQT=0
  130. cc2500WriteReg(CC2500_07_PKTCTRL1, 0x0D);
  131. //cc2500WriteReg(CC2500_0C_FSCTRL0, 0); // Frequency offset
  132. cc2500WriteReg(CC2500_0C_FSCTRL0, bind ? 0x00 : frequencyOffsetHack);
  133. cc2500WriteReg(CC2500_0A_CHANNR, 0x00);
  134. }
  135. static void binding(void) {
  136. readBindingData();
  137. if ((txid[0] != 0xff) || (txid[1] != 0xff)) {
  138. // valid binding data found
  139. debugWrite("RX: found data in EEPROM!\n");
  140. return;
  141. }
  142. debugWrite("RX: no stored data, tuning...\n");
  143. // No valid txid, forcing bind
  144. tuning();
  145. //frequencyOffsetHack = 0xC8; // for test
  146. cc2500WriteReg(CC2500_0C_FSCTRL0, frequencyOffsetHack);
  147. eeprom_write_byte(EEPROM_BASE_ADDRESS + 101, frequencyOffsetHack);
  148. debugWrite("RX: tuned, binding...\n");
  149. performBind();
  150. }
  151. static void tuning() {
  152. cc2500Strobe(CC2500_SRX); // enter in rx mode
  153. uint16_t frequencyOffsetTimer = 0;
  154. while (1) {
  155. frequencyOffsetTimer++;
  156. if (frequencyOffsetTimer > 3000) {
  157. frequencyOffsetTimer = 0;
  158. cc2500WriteReg(CC2500_0C_FSCTRL0, frequencyOffsetHack);
  159. if (frequencyOffsetHack <= 250) {
  160. frequencyOffsetHack += 5;
  161. } else {
  162. frequencyOffsetHack = 0;
  163. if (freq0 < 255) {
  164. freq0++;
  165. } else {
  166. freq0 = 0;
  167. if (freq1 < 255) {
  168. freq1++;
  169. } else {
  170. freq1 = 0;
  171. if (freq2 < 255) {
  172. freq2++;
  173. } else {
  174. freq2 = 0;
  175. }
  176. }
  177. }
  178. debugWrite("0x");
  179. debugHex(freq2);
  180. debugHex(freq1);
  181. debugHex(freq0);
  182. debugWrite("\n");
  183. cc2500WriteReg(CC2500_0D_FREQ2, freq2);
  184. cc2500WriteReg(CC2500_0E_FREQ1, freq1);
  185. cc2500WriteReg(CC2500_0F_FREQ0, freq0);
  186. }
  187. //cc2500Strobe(CC2500_SRX); // enter in rx mode
  188. }
  189. if (GDO_1) {
  190. debugWrite("Tuning: data flag has been set!\n");
  191. //ccLen = cc2500ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
  192. ccLen = cc2500ReadReg(CC2500_3B_RXBYTES) & 0x7F;
  193. if (ccLen) {
  194. debugWrite("Tuning: got data!\n");
  195. cc2500ReadFifo(ccData, ccLen);
  196. if ((ccData[ccLen - 1] & 0x80)
  197. && (ccData[2] == 0x01)
  198. && (ccData[5] == 0x00)) {
  199. break;
  200. }
  201. } else {
  202. debugWrite("Tuning: no data?!\n");
  203. }
  204. }
  205. wdt_reset();
  206. #ifdef DEBUG
  207. uartMenu();
  208. #endif
  209. }
  210. }
  211. static void performBind(void) {
  212. cc2500Strobe(CC2500_SRX); // enter in rx mode
  213. while (1) {
  214. if (GDO_1) {
  215. //ccLen = cc2500ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
  216. ccLen = cc2500ReadReg(CC2500_3B_RXBYTES) & 0x7F;
  217. if (ccLen) {
  218. cc2500ReadFifo(ccData, ccLen);
  219. if ((ccData[ccLen - 1] & 0x80)
  220. && (ccData[2] == 0x01)
  221. && (ccData[5] == 0x00)) {
  222. txid[0] = ccData[3];
  223. txid[1] = ccData[4];
  224. for (uint8_t n = 0; n < 5; n++) {
  225. hopData[ccData[5] + n] = ccData[6 + n];
  226. }
  227. break;
  228. }
  229. }
  230. }
  231. wdt_reset();
  232. #ifdef DEBUG
  233. uartMenu();
  234. #endif
  235. }
  236. debugWrite("RX: got hop data, reading list...\n");
  237. listLength = 0;
  238. uint8_t eol = 0;
  239. for (uint8_t bindIdx = 0x05; bindIdx <= 120; bindIdx += 5) {
  240. while (1) {
  241. if (GDO_1) {
  242. //ccLen = cc2500ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
  243. ccLen = cc2500ReadReg(CC2500_3B_RXBYTES) & 0x7F;
  244. if (ccLen) {
  245. cc2500ReadFifo(ccData, ccLen);
  246. if ((ccData[ccLen - 1] & 0x80)
  247. && (ccData[2] == 0x01)
  248. && (ccData[3] == txid[0])
  249. && (ccData[4] == txid[1])
  250. && (ccData[5] == bindIdx)) {
  251. for (uint8_t n = 0; n < 5; n++) {
  252. //if (ccData[6 + n] == ccData[ccLen - 3]) {
  253. if (ccData[6 + n] <= 3) {
  254. eol = 1;
  255. listLength = ccData[5] + n;
  256. break;
  257. }
  258. hopData[ccData[5] + n] = ccData[6 + n];
  259. }
  260. break;
  261. }
  262. }
  263. }
  264. wdt_reset();
  265. #ifdef DEBUG
  266. uartMenu();
  267. #endif
  268. }
  269. if (eol) {
  270. break; // End of list found, stop!
  271. }
  272. }
  273. debugWrite("RX: binding finished!\n");
  274. writeBindingData();
  275. cc2500Strobe(CC2500_SIDLE); // Back to idle
  276. }
  277. static void nextChannel(uint8_t skip) {
  278. channr += skip;
  279. if (channr >= listLength) {
  280. channr -= listLength;
  281. }
  282. cc2500WriteReg(CC2500_0A_CHANNR, hopData[channr]);
  283. cc2500WriteReg(CC2500_23_FSCAL3, 0x89);
  284. }
  285. static void readBindingData() {
  286. for (uint8_t i = 0; i < 2; i++) {
  287. txid[i] = eeprom_read_byte(EEPROM_BASE_ADDRESS + i);
  288. }
  289. for (uint8_t i = 0; i < HOP_DATA_LENGTH; i++) {
  290. hopData[i] = eeprom_read_byte(EEPROM_BASE_ADDRESS + 10 + i);
  291. }
  292. listLength = eeprom_read_byte(EEPROM_BASE_ADDRESS + 100);
  293. frequencyOffsetHack = eeprom_read_byte(EEPROM_BASE_ADDRESS + 101);
  294. }
  295. static void writeBindingData() {
  296. for (uint8_t i = 0; i < 2; i++) {
  297. eeprom_write_byte(EEPROM_BASE_ADDRESS + i, txid[i]);
  298. }
  299. for (uint8_t i = 0; i < HOP_DATA_LENGTH; i++) {
  300. eeprom_write_byte(EEPROM_BASE_ADDRESS + 10 + i, hopData[i]);
  301. }
  302. eeprom_write_byte(EEPROM_BASE_ADDRESS + 100, listLength);
  303. }
  304. void rxReceivePacket() {
  305. time_t time = timerGet();
  306. if (missingPackets > FAILSAFE_MISSING_PACKET) {
  307. failed = 1;
  308. missingPackets = 0;
  309. }
  310. while (1) {
  311. if ((timerGet() - time) > MISSING_PACKET_DELAY) {
  312. missingPackets++;
  313. cc2500Strobe(CC2500_SIDLE);
  314. if (missingPackets > MAX_MISSING_PACKET) {
  315. nextChannel(SEEK_CHANNEL_SKIP);
  316. counter++;
  317. if (counter > (MAX_MISSING_PACKET << 1)) {
  318. debugWrite("RX: missing packet notification!\n");
  319. }
  320. if (counter == (MAX_MISSING_PACKET << 2)) counter = 0;
  321. break;
  322. } else
  323. nextChannel(1);
  324. break;
  325. }
  326. if (GDO_1) {
  327. //ccLen = cc2500ReadReg(CC2500_3B_RXBYTES | CC2500_READ_BURST) & 0x7F;
  328. ccLen = cc2500ReadReg(CC2500_3B_RXBYTES) & 0x7F;
  329. if (ccLen > 20) {
  330. ccLen = 20;
  331. }
  332. if (ccLen) {
  333. cc2500ReadFifo((uint8_t *)ccData, ccLen);
  334. if (ccData[ccLen - 1] & 0x80) { // Only if correct CRC
  335. missingPackets = 0;
  336. if ((ccData[0] == 0x11) // Correct length
  337. && (ccData[1] == txid[0]) // Correct txid
  338. && (ccData[2] == txid[1])) {
  339. packet = 1;
  340. #ifdef RSSI_OVER_PPM
  341. //int rssi_dec = cc2500ReadReg(CC2500_34_RSSI | CC2500_READ_BURST);
  342. int rssi_dec = cc2500ReadReg(CC2500_34_RSSI);
  343. if (rssi_dec < 128) {
  344. rssi = ((rssi_dec / 2) - RSSI_OFFSET) & 0x7f;
  345. } else {
  346. rssi = (((rssi_dec - 256) / 2)) - RSSI_OFFSET;
  347. }
  348. rssi = constrain(rssi, RSSI_MIN, RSSI_MAX);
  349. #endif
  350. cc2500Strobe(CC2500_SIDLE);
  351. nextChannel(1);
  352. failed = 0;
  353. break;
  354. }
  355. }
  356. }
  357. }
  358. wdt_reset();
  359. #ifdef DEBUG
  360. uartMenu();
  361. #endif
  362. }
  363. if (packet != 0) {
  364. packet = 0;
  365. c[0] = (uint16_t)(ccData[10] & 0x0F) << 8 | ccData[6];
  366. c[1] = (uint16_t)(ccData[10] & 0xF0) << 4 | ccData[7];
  367. c[2] = (uint16_t)(ccData[11] & 0x0F) << 8 | ccData[8];
  368. c[3] = (uint16_t)(ccData[11] & 0xF0) << 4 | ccData[9];
  369. c[4] = (uint16_t)(ccData[16] & 0x0F) << 8 | ccData[12];
  370. c[5] = (uint16_t)(ccData[16] & 0xF0) << 4 | ccData[13];
  371. c[6] = (uint16_t)(ccData[17] & 0x0F) << 8 | ccData[14];
  372. c[7] = (uint16_t)(ccData[17] & 0xF0) << 4 | ccData[15];
  373. for (int i = 0; i < CHANNELS; i++) {
  374. ppmBuffer[i] = PPM_SCALE * c[i];
  375. if ((ppmBuffer[i] < 900) || (ppmBuffer[i] > 2100)) {
  376. ppmBuffer[i] = 850;
  377. }
  378. }
  379. #ifdef RSSI_OVER_PPM
  380. ppmBuffer[RSSI_OVER_PPM] = map(rssi, RSSI_MIN, RSSI_MAX, PPM_MIN, PPM_MAX);
  381. #endif
  382. debugWrite("RX: packet received, sending CPPM!\n");
  383. cppmCopy(ppmBuffer);
  384. }
  385. cc2500Strobe(CC2500_SRX);
  386. }
  387. static long map(long x, long in_min, long in_max, long out_min, long out_max) {
  388. return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min;
  389. }
  390. static long constrain(long x, long min, long max) {
  391. if (x < min) {
  392. x = min;
  393. }
  394. if (x > max) {
  395. x = max;
  396. }
  397. return x;
  398. }