Kiibohd Controller
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
Repozitorijs ir arhivēts. Tam var aplūkot failus un to var klonēt, bet nevar iesūtīt jaunas izmaiņas, kā arī atvērt jaunas problēmas/izmaiņu pieprasījumus.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161
  1. /* Copyright (C) 2014-2016 by Jacob Alexander
  2. *
  3. * This file is free software: you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation, either version 3 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This file is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this file. If not, see <http://www.gnu.org/licenses/>.
  15. */
  16. // ----- Includes -----
  17. // Compiler Includes
  18. #include <Lib/ScanLib.h>
  19. // Project Includes
  20. #include <cli.h>
  21. #include <kll_defs.h>
  22. #include <led.h>
  23. #include <print.h>
  24. #include <pixel.h>
  25. // Interconnect module if compiled in
  26. #if defined(ConnectEnabled_define)
  27. #include <connect_scan.h>
  28. #endif
  29. // Local Includes
  30. #include "i2c.h"
  31. #include "led_scan.h"
  32. // ----- Defines -----
  33. // TODO Make this a kll define
  34. // I2C transfers are more efficient if all 144 don't have to be updated
  35. // (and most implementations don't use all the channels)
  36. // Ergodox tested @ 83fps /w 38
  37. // Whitefox tested @ 45fps /w 71
  38. #define LED_BufferLength 144
  39. #define LED_EnableBufferLength 18
  40. #define LED_FrameBuffersMax 4
  41. #define LED_TotalChannels (LED_BufferLength * ISSI_Chips_define)
  42. // ISSI Addresses
  43. // IS31FL3731 (max 4 channels per bus)
  44. #if ISSI_Chip_31FL3731_define == 1
  45. #define ISSI_Ch1 0xE8
  46. #define ISSI_Ch2 0xEA
  47. #define ISSI_Ch3 0xEC
  48. #define ISSI_Ch4 0xEE
  49. // IS31FL3732 (max 16 channels per bus)
  50. #elif ISSI_Chip_31FL3732_define == 1
  51. #define ISSI_Ch1 0xA0
  52. #define ISSI_Ch2 0xA2
  53. #define ISSI_Ch3 0xA4
  54. #define ISSI_Ch4 0xA6
  55. #define ISSI_Ch5 0xA8
  56. #define ISSI_Ch6 0xAA
  57. #define ISSI_Ch7 0xAC
  58. #define ISSI_Ch8 0xAE
  59. #define ISSI_Ch9 0xB0
  60. #define ISSI_Ch10 0xB2
  61. #define ISSI_Ch11 0xB4
  62. #define ISSI_Ch12 0xB6
  63. #define ISSI_Ch13 0xB8
  64. #define ISSI_Ch14 0xBA
  65. #define ISSI_Ch15 0xBC
  66. #define ISSI_Ch16 0xBE
  67. #else
  68. #error "ISSI Driver Chip not defined in Scan defaultMap.kll..."
  69. #endif
  70. // TODO Generate in KLL
  71. #define LED_MapCh1_Bus_define 0x0
  72. #define LED_MapCh1_Addr_define ISSI_Ch1
  73. #define LED_MapCh2_Bus_define 0x0
  74. #define LED_MapCh2_Addr_define ISSI_Ch2
  75. #define LED_MapCh3_Bus_define 0x1
  76. #define LED_MapCh3_Addr_define ISSI_Ch1
  77. #define LED_MapCh4_Bus_define 0x1
  78. #define LED_MapCh4_Addr_define ISSI_Ch2
  79. // ----- Macros -----
  80. #define LED_ChannelMapDefine(ch) \
  81. { \
  82. LED_MapCh##ch##_Bus_define, /* I2C bus number */ \
  83. LED_MapCh##ch##_Addr_define, /* I2C address */ \
  84. }
  85. #define LED_MaskDefine(ch) \
  86. { \
  87. LED_MapCh##ch##_Addr_define, /* I2C address */ \
  88. 0x00, /* Starting register address */ \
  89. { ISSILedMask##ch##_define }, \
  90. }
  91. #define LED_BrightnessDefine(ch) \
  92. { \
  93. LED_MapCh##ch##_Addr_define, /* I2C address */ \
  94. 0x24, /* Starting register address */ \
  95. { ISSILedBrightness##ch##_define }, \
  96. }
  97. // ----- Structs -----
  98. typedef struct LED_Buffer {
  99. uint16_t i2c_addr;
  100. uint16_t reg_addr;
  101. uint16_t buffer[LED_BufferLength];
  102. } LED_Buffer;
  103. typedef struct LED_EnableBuffer {
  104. uint16_t i2c_addr;
  105. uint16_t reg_addr;
  106. uint16_t buffer[LED_EnableBufferLength];
  107. } LED_EnableBuffer;
  108. typedef struct LED_ChannelMap {
  109. uint8_t bus;
  110. uint8_t addr;
  111. } LED_ChannelMap;
  112. // ----- Function Declarations -----
  113. // CLI Functions
  114. void cliFunc_i2cSend ( char* args );
  115. void cliFunc_ledCtrl ( char* args );
  116. void cliFunc_ledReset ( char* args );
  117. void cliFunc_ledSpeed ( char* args );
  118. // ----- Variables -----
  119. // Scan Module command dictionary
  120. CLIDict_Entry( i2cSend, "Send I2C sequence of bytes. Use |'s to split sequences with a stop." );
  121. CLIDict_Entry( ledCtrl, "Basic LED control. Args: <mode> <amount> [<index>]" );
  122. CLIDict_Entry( ledReset, "Reset ISSI chips." );
  123. CLIDict_Entry( ledSpeed, "ISSI frame rate 0-63, 1 is fastest. f - display fps" );
  124. CLIDict_Def( ledCLIDict, "ISSI LED Module Commands" ) = {
  125. CLIDict_Item( i2cSend ),
  126. CLIDict_Item( ledCtrl ),
  127. CLIDict_Item( ledReset ),
  128. CLIDict_Item( ledSpeed ),
  129. { 0, 0, 0 } // Null entry for dictionary end
  130. };
  131. volatile LED_Buffer LED_pageBuffer[ISSI_Chips_define];
  132. uint8_t LED_FrameBuffersReady; // Starts at maximum, reset on interrupt from ISSI
  133. volatile uint8_t LED_FrameBufferReset; // INTB interrupt received, reset available buffer count when ready
  134. uint8_t LED_FrameBufferPage; // Current page of the buffer
  135. uint8_t LED_FrameBufferStart; // Whether or not a start signal can be sent
  136. uint8_t LED_displayFPS; // Display fps to cli
  137. // TODO - Autogenerate for each keyboard
  138. // ISSI Driver Channel to Bus:Address mapping
  139. const LED_ChannelMap LED_ChannelMapping[ISSI_Chips_define] = {
  140. LED_ChannelMapDefine( 1 ),
  141. #if ISSI_Chips_define >= 2
  142. LED_ChannelMapDefine( 2 ),
  143. #endif
  144. #if ISSI_Chips_define >= 3
  145. LED_ChannelMapDefine( 3 ),
  146. #endif
  147. #if ISSI_Chips_define >= 4
  148. LED_ChannelMapDefine( 4 ),
  149. #endif
  150. };
  151. // Enable mask and default brightness for ISSI chip channel
  152. const LED_EnableBuffer LED_ledEnableMask[ISSI_Chips_define] = {
  153. LED_MaskDefine( 1 ),
  154. #if ISSI_Chips_define >= 2
  155. LED_MaskDefine( 2 ),
  156. #endif
  157. #if ISSI_Chips_define >= 3
  158. LED_MaskDefine( 3 ),
  159. #endif
  160. #if ISSI_Chips_define >= 4
  161. LED_MaskDefine( 4 ),
  162. #endif
  163. };
  164. // Default LED brightness
  165. const LED_Buffer LED_defaultBrightness[ISSI_Chips_define] = {
  166. LED_BrightnessDefine( 1 ),
  167. #if ISSI_Chips_define >= 2
  168. LED_BrightnessDefine( 2 ),
  169. #endif
  170. #if ISSI_Chips_define >= 3
  171. LED_BrightnessDefine( 3 ),
  172. #endif
  173. #if ISSI_Chips_define >= 4
  174. LED_BrightnessDefine( 4 ),
  175. #endif
  176. };
  177. #if ISSI_Chips_define >= 5
  178. #error "Invalid number of ISSI Chips"
  179. #endif
  180. // ----- Interrupt Functions -----
  181. void portb_isr()
  182. {
  183. // Check for ISSI INTB IRQ
  184. if ( PORTB_ISFR & (1 << 17) )
  185. {
  186. // Set frame buffer replenish condition
  187. LED_FrameBufferReset = 1;
  188. // Clear IRQ
  189. PORTB_ISFR |= (1 << 17);
  190. }
  191. }
  192. // ----- Functions -----
  193. void LED_zeroPages( uint8_t bus, uint8_t addr, uint8_t startPage, uint8_t numPages, uint8_t startReg, uint8_t endReg )
  194. {
  195. // Clear Page
  196. // Max length of a page + chip id + reg start
  197. uint16_t clearPage[2 + 0xB4] = { 0 };
  198. clearPage[0] = addr;
  199. clearPage[1] = startReg;
  200. // Iterate through given pages, zero'ing out the given register regions
  201. for ( uint8_t page = startPage; page < startPage + numPages; page++ )
  202. {
  203. // Page Setup
  204. uint16_t pageSetup[] = { addr, 0xFD, page };
  205. // Setup page
  206. while ( i2c_send( bus, pageSetup, sizeof( pageSetup ) / 2 ) == -1 )
  207. delay(1);
  208. // Zero out page
  209. while ( i2c_send( bus, clearPage, 2 + endReg - startReg ) == -1 )
  210. delay(1);
  211. }
  212. // Wait until finished zero'ing
  213. while ( i2c_busy( bus ) )
  214. delay(1);
  215. }
  216. void LED_sendPage( uint8_t bus, uint8_t addr, uint16_t *buffer, uint32_t len, uint8_t page )
  217. {
  218. /*
  219. info_msg("I2C Send Page Addr: ");
  220. printHex( addr );
  221. print(" Len: ");
  222. printHex( len );
  223. print(" Page: ");
  224. printHex( page );
  225. print( NL );
  226. */
  227. // Page Setup
  228. uint16_t pageSetup[] = { addr, 0xFD, page };
  229. // Setup page
  230. while ( i2c_send( bus, pageSetup, sizeof( pageSetup ) / 2 ) == -1 )
  231. delay(1);
  232. // Write page to I2C Tx Buffer
  233. while ( i2c_send( bus, buffer, len ) == -1 )
  234. delay(1);
  235. }
  236. // Write register on all ISSI chips
  237. // Prepare pages first, then attempt write register with a minimal delay between chips
  238. void LED_syncReg( uint8_t reg, uint8_t val, uint8_t page )
  239. {
  240. uint16_t pageSetup[] = { 0, 0xFD, page };
  241. // Setup each of the pages
  242. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  243. {
  244. pageSetup[0] = LED_ChannelMapping[ ch ].addr;
  245. uint8_t bus = LED_ChannelMapping[ ch ].bus;
  246. while ( i2c_send( bus, pageSetup, sizeof( pageSetup ) / 2 ) == -1 )
  247. delay(1);
  248. }
  249. // Reg Write Setup
  250. uint16_t writeData[] = { 0, reg, val };
  251. // Write to all the registers
  252. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  253. {
  254. writeData[0] = LED_ChannelMapping[ ch ].addr;
  255. uint8_t bus = LED_ChannelMapping[ ch ].bus;
  256. // Delay very little to help with synchronization
  257. while ( i2c_send( bus, writeData, sizeof( writeData ) / 2 ) == -1 )
  258. delayMicroseconds(10);
  259. }
  260. // Delay until written
  261. while ( i2c_any_busy() )
  262. delay(1);
  263. }
  264. // Write address
  265. void LED_writeReg( uint8_t bus, uint8_t addr, uint8_t reg, uint8_t val, uint8_t page )
  266. {
  267. // Page Setup
  268. uint16_t pageSetup[] = { addr, 0xFD, page };
  269. // Reg Write Setup
  270. uint16_t writeData[] = { addr, reg, val };
  271. // Setup page
  272. while ( i2c_send( bus, pageSetup, sizeof( pageSetup ) / 2 ) == -1 )
  273. delay(1);
  274. // Write register
  275. while ( i2c_send( bus, writeData, sizeof( writeData ) / 2 ) == -1 )
  276. delay(1);
  277. // Delay until written
  278. while ( i2c_busy( bus ) )
  279. delay(1);
  280. }
  281. // Read address
  282. // TODO Not working?
  283. uint8_t LED_readReg( uint8_t bus, uint8_t addr, uint8_t reg, uint8_t page )
  284. {
  285. // Software shutdown must be enabled to read registers
  286. LED_writeReg( bus, addr, 0x0A, 0x00, 0x0B );
  287. // Page Setup
  288. uint16_t pageSetup[] = { addr, 0xFD, page };
  289. // Setup page
  290. while ( i2c_send( bus, pageSetup, sizeof( pageSetup ) / 2 ) == -1 )
  291. delay(1);
  292. // Register Setup
  293. uint16_t regSetup[] = { addr, reg };
  294. // Configure register
  295. while ( i2c_send( bus, regSetup, sizeof( regSetup ) / 2 ) == -1 )
  296. delay(1);
  297. // Register Read Command
  298. uint16_t regReadCmd[] = { addr | 0x1, I2C_READ };
  299. uint8_t recv_data;
  300. // Request single register byte
  301. while ( i2c_read( bus, regReadCmd, sizeof( regReadCmd ) / 2, &recv_data ) == -1 )
  302. delay(1);
  303. // Disable software shutdown
  304. LED_writeReg( bus, addr, 0x0A, 0x01, 0x0B );
  305. return recv_data;
  306. }
  307. void LED_reset()
  308. {
  309. // Reset frame buffer used count
  310. LED_FrameBuffersReady = LED_FrameBuffersMax;
  311. // Starting page for the buffers
  312. LED_FrameBufferPage = 4;
  313. // Initially do not allow autoplay to restart
  314. LED_FrameBufferStart = 0;
  315. // Disable FPS by default
  316. LED_displayFPS = 0;
  317. // Clear LED Pages
  318. // Enable LEDs based upon mask
  319. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  320. {
  321. uint8_t addr = LED_ChannelMapping[ ch ].addr;
  322. uint8_t bus = LED_ChannelMapping[ ch ].bus;
  323. LED_zeroPages( bus, addr, 0x00, 8, 0x00, 0xB4 ); // LED Registers
  324. // For each page
  325. for ( uint8_t pg = 0; pg < LED_FrameBuffersMax * 2; pg++ )
  326. {
  327. LED_sendPage(
  328. bus,
  329. addr,
  330. (uint16_t*)&LED_ledEnableMask[ ch ],
  331. sizeof( LED_EnableBuffer ) / 2,
  332. pg
  333. );
  334. }
  335. }
  336. // Set global brightness control
  337. #if ISSI_Chip_31FL3732_define == 1
  338. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  339. {
  340. uint8_t addr = LED_ChannelMapping[ ch ].addr;
  341. uint8_t bus = LED_ChannelMapping[ ch ].bus;
  342. // See, 31FL3732 datasheet for details on calculation
  343. // Depends on Rext
  344. LED_writeReg( bus, addr, 0x04, ISSI_Global_Brightness_define, 0x0B );
  345. }
  346. #endif
  347. // Setup ISSI auto frame play, but do not start yet
  348. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  349. {
  350. uint8_t addr = LED_ChannelMapping[ ch ].addr;
  351. uint8_t bus = LED_ChannelMapping[ ch ].bus;
  352. // CNS 1 loop, FNS 4 frames - 0x14
  353. LED_writeReg( bus, addr, 0x02, 0x14, 0x0B );
  354. // Default refresh speed - TxA
  355. // T is typically 11ms
  356. // A is 1 to 64 (where 0 is 64)
  357. LED_writeReg( bus, addr, 0x03, ISSI_AnimationSpeed_define, 0x0B );
  358. // Set MODE to Auto Frame Play
  359. LED_writeReg( bus, addr, 0x00, 0x08, 0x0B );
  360. }
  361. // Do not disable software shutdown of ISSI chip unless current is high enough
  362. // Require at least 150 mA
  363. // May be enabled/disabled at a later time
  364. if ( Output_current_available() >= 150 )
  365. {
  366. // Disable Software shutdown of ISSI chip
  367. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  368. {
  369. uint8_t addr = LED_ChannelMapping[ ch ].addr;
  370. uint8_t bus = LED_ChannelMapping[ ch ].bus;
  371. LED_writeReg( bus, addr, 0x0A, 0x01, 0x0B );
  372. }
  373. }
  374. }
  375. // Setup
  376. inline void LED_setup()
  377. {
  378. // Register Scan CLI dictionary
  379. CLI_registerDictionary( ledCLIDict, ledCLIDictName );
  380. // Initialize I2C
  381. i2c_setup();
  382. // Setup LED_pageBuffer addresses and brightness section
  383. LED_pageBuffer[0].i2c_addr = LED_MapCh1_Addr_define;
  384. LED_pageBuffer[0].reg_addr = 0x24;
  385. #if ISSI_Chips_define >= 2
  386. LED_pageBuffer[1].i2c_addr = LED_MapCh2_Addr_define;
  387. LED_pageBuffer[1].reg_addr = 0x24;
  388. #endif
  389. #if ISSI_Chips_define >= 3
  390. LED_pageBuffer[2].i2c_addr = LED_MapCh3_Addr_define;
  391. LED_pageBuffer[2].reg_addr = 0x24;
  392. #endif
  393. #if ISSI_Chips_define >= 4
  394. LED_pageBuffer[3].i2c_addr = LED_MapCh4_Addr_define;
  395. LED_pageBuffer[3].reg_addr = 0x24;
  396. #endif
  397. // Enable Hardware shutdown (pull low)
  398. GPIOB_PDDR |= (1<<16);
  399. PORTB_PCR16 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
  400. GPIOB_PCOR |= (1<<16);
  401. // Zero out Frame Registers
  402. // This needs to be done before disabling the hardware shutdown (or the leds will do undefined things)
  403. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  404. {
  405. uint8_t addr = LED_ChannelMapping[ ch ].addr;
  406. uint8_t bus = LED_ChannelMapping[ ch ].bus;
  407. LED_zeroPages( bus, addr, 0x0B, 1, 0x00, 0x0C ); // Control Registers
  408. }
  409. // Disable Hardware shutdown of ISSI chip (pull high)
  410. GPIOB_PSOR |= (1<<16);
  411. // Prepare pin to read INTB interrupt of ISSI chip (Active Low)
  412. // Enable interrupt to detect falling edge
  413. // Uses external pullup resistor
  414. GPIOB_PDDR |= ~(1<<17);
  415. PORTB_PCR17 = PORT_PCR_IRQC(0xA) | PORT_PCR_PFE | PORT_PCR_MUX(1);
  416. LED_FrameBufferReset = 0; // Clear frame buffer reset condition for ISSI
  417. // Enable PORTB interrupt
  418. NVIC_ENABLE_IRQ( IRQ_PORTB );
  419. // Reset LED sequencing
  420. LED_reset();
  421. }
  422. // LED Linked Send
  423. // Call-back for i2c write when updating led display
  424. // TODO Optimize linked send for multiple i2c buses
  425. uint8_t LED_chipSend;
  426. void LED_linkedSend()
  427. {
  428. // Check if we've updated all the ISSI chips for this frame
  429. if ( LED_chipSend >= ISSI_Chips_define )
  430. {
  431. // Increment the buffer page
  432. // And reset if necessary
  433. if ( ++LED_FrameBufferPage >= LED_FrameBuffersMax * 2 )
  434. {
  435. LED_FrameBufferPage = 0;
  436. }
  437. // Now ready to update the frame buffer
  438. Pixel_FrameState = FrameState_Update;
  439. return;
  440. }
  441. // Update ISSI Frame State
  442. Pixel_FrameState = FrameState_Sending;
  443. // Lookup bus number
  444. uint8_t bus = LED_ChannelMapping[ LED_chipSend ].bus;
  445. // Debug
  446. /*
  447. dbug_msg("Linked Send: chip(");
  448. printHex( LED_chipSend );
  449. print(") frame(");
  450. printHex( LED_FrameBufferPage );
  451. print(") addr(");
  452. printHex( LED_pageBuffer[0].i2c_addr );
  453. print(") reg(");
  454. printHex( LED_pageBuffer[0].reg_addr );
  455. print(") len(");
  456. printHex( sizeof( LED_Buffer ) / 2 );
  457. print(") data[]" NL "(");
  458. for ( uint8_t c = 0; c < 9; c++ )
  459. //for ( uint8_t c = 0; c < sizeof( LED_Buffer ) / 2 - 2; c++ )
  460. {
  461. printHex( LED_pageBuffer[0].buffer[c] );
  462. print(" ");
  463. }
  464. print(")" NL);
  465. */
  466. // Send, and recursively call this function when finished
  467. while ( i2c_send_sequence(
  468. bus,
  469. (uint16_t*)&LED_pageBuffer[ LED_chipSend ],
  470. sizeof( LED_Buffer ) / 2,
  471. 0,
  472. LED_linkedSend,
  473. 0
  474. ) == -1 )
  475. delay(1);
  476. // Increment chip position
  477. LED_chipSend++;
  478. }
  479. // LED State processing loop
  480. uint32_t LED_timePrev = 0;
  481. unsigned int LED_currentEvent = 0;
  482. inline void LED_scan()
  483. {
  484. // Check for current change event
  485. if ( LED_currentEvent )
  486. {
  487. // TODO dim LEDs in low power mode instead of shutting off
  488. if ( LED_currentEvent < 150 )
  489. {
  490. // Enable Software shutdown of ISSI chip
  491. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  492. {
  493. uint8_t addr = LED_ChannelMapping[ ch ].addr;
  494. uint8_t bus = LED_ChannelMapping[ ch ].bus;
  495. LED_writeReg( bus, addr, 0x0A, 0x00, 0x0B );
  496. }
  497. }
  498. else
  499. {
  500. // Disable Software shutdown of ISSI chip
  501. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  502. {
  503. uint8_t addr = LED_ChannelMapping[ ch ].addr;
  504. uint8_t bus = LED_ChannelMapping[ ch ].bus;
  505. LED_writeReg( bus, addr, 0x0A, 0x01, 0x0B );
  506. }
  507. }
  508. LED_currentEvent = 0;
  509. }
  510. // Check to see if frame buffers are ready to replenish
  511. if ( LED_FrameBufferReset )
  512. {
  513. LED_FrameBufferReset = 0;
  514. // Delay, in order to synchronize chips
  515. LED_FrameBufferStart = 1;
  516. // FPS Display
  517. if ( LED_displayFPS )
  518. {
  519. dbug_msg("4frames/");
  520. printInt32( systick_millis_count - LED_timePrev );
  521. LED_timePrev = systick_millis_count;
  522. print( "ms" NL );
  523. }
  524. }
  525. // Make sure there are buffers available
  526. if ( LED_FrameBuffersReady == 0 )
  527. {
  528. // Only start if we haven't already
  529. // And if we've finished updating the buffers
  530. if ( !LED_FrameBufferStart || Pixel_FrameState == FrameState_Sending )
  531. return;
  532. // Start Auto Frame Play on either frame 1 or 5
  533. uint8_t frame = LED_FrameBufferPage == 0 ? 4 : 0;
  534. LED_syncReg( 0x00, 0x08 | frame, 0x0B );
  535. LED_FrameBufferStart = 0;
  536. LED_FrameBuffersReady = LED_FrameBuffersMax;
  537. return;
  538. }
  539. /*
  540. else
  541. {
  542. dbug_msg(":/ - Start(");
  543. printHex( LED_FrameBufferStart );
  544. print(") BuffersReady(");
  545. printHex( LED_FrameBuffersReady );
  546. print(") State(");
  547. printHex( Pixel_FrameState );
  548. print(")"NL);
  549. }
  550. */
  551. // Only send frame to ISSI chip if buffers are ready
  552. if ( Pixel_FrameState != FrameState_Ready )
  553. return;
  554. LED_FrameBuffersReady--;
  555. // Set the page of all the ISSI chips
  556. // This way we can easily link the buffers to send the brightnesses in the background
  557. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  558. {
  559. // Page Setup
  560. uint8_t addr = LED_ChannelMapping[ ch ].addr;
  561. uint8_t bus = LED_ChannelMapping[ ch ].bus;
  562. uint16_t pageSetup[] = { addr, 0xFD, LED_FrameBufferPage };
  563. // Send each update
  564. while ( i2c_send( bus, pageSetup, sizeof( pageSetup ) / 2 ) == -1 )
  565. delay(1);
  566. }
  567. // Send current set of buffers
  568. // Uses interrupts to send to all the ISSI chips
  569. // Pixel_FrameState will be updated when complete
  570. LED_chipSend = 0; // Start with chip 0
  571. LED_linkedSend();
  572. }
  573. // Called by parent Scan Module whenver the available current has changed
  574. // current - mA
  575. void LED_currentChange( unsigned int current )
  576. {
  577. // Delay action till next LED scan loop (as this callback sometimes occurs during interrupt requests)
  578. LED_currentEvent = current;
  579. }
  580. // ----- Capabilities -----
  581. // Basic LED Control Capability
  582. typedef enum LedControlMode {
  583. // Single LED Modes
  584. LedControlMode_brightness_decrease,
  585. LedControlMode_brightness_increase,
  586. LedControlMode_brightness_set,
  587. // Set all LEDs (index argument not required)
  588. LedControlMode_brightness_decrease_all,
  589. LedControlMode_brightness_increase_all,
  590. LedControlMode_brightness_set_all,
  591. } LedControlMode;
  592. typedef struct LedControl {
  593. LedControlMode mode; // XXX Make sure to adjust the .kll capability if this variable is larger than 8 bits
  594. uint8_t amount;
  595. uint16_t index;
  596. } LedControl;
  597. void LED_control( LedControl *control )
  598. {
  599. // Configure based upon the given mode
  600. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  601. {
  602. // TODO Perhaps do gamma adjustment?
  603. switch ( control->mode )
  604. {
  605. case LedControlMode_brightness_decrease:
  606. // Don't worry about rolling over, the cycle is quick
  607. LED_pageBuffer[ ch ].buffer[ control->index ] -= control->amount;
  608. break;
  609. case LedControlMode_brightness_increase:
  610. // Don't worry about rolling over, the cycle is quick
  611. LED_pageBuffer[ ch ].buffer[ control->index ] += control->amount;
  612. break;
  613. case LedControlMode_brightness_set:
  614. LED_pageBuffer[ ch ].buffer[ control->index ] = control->amount;
  615. break;
  616. case LedControlMode_brightness_decrease_all:
  617. for ( uint8_t channel = 0; channel < LED_TotalChannels; channel++ )
  618. {
  619. // Don't worry about rolling over, the cycle is quick
  620. LED_pageBuffer[ ch ].buffer[ channel ] -= control->amount;
  621. }
  622. break;
  623. case LedControlMode_brightness_increase_all:
  624. for ( uint8_t channel = 0; channel < LED_TotalChannels; channel++ )
  625. {
  626. // Don't worry about rolling over, the cycle is quick
  627. LED_pageBuffer[ ch ].buffer[ channel ] += control->amount;
  628. }
  629. break;
  630. case LedControlMode_brightness_set_all:
  631. for ( uint8_t channel = 0; channel < LED_TotalChannels; channel++ )
  632. {
  633. LED_pageBuffer[ ch ].buffer[ channel ] = control->amount;
  634. }
  635. break;
  636. }
  637. }
  638. // Sync LED buffer with ISSI chip buffer
  639. // TODO Support multiple frames
  640. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  641. {
  642. LED_sendPage(
  643. LED_ChannelMapping[ ch ].bus,
  644. LED_ChannelMapping[ ch ].addr,
  645. (uint16_t*)&LED_pageBuffer[ ch ],
  646. sizeof( LED_Buffer ) / 2, 0
  647. );
  648. }
  649. }
  650. uint8_t LED_control_timer = 0;
  651. void LED_control_capability( uint8_t state, uint8_t stateType, uint8_t *args )
  652. {
  653. // Display capability name
  654. if ( stateType == 0xFF && state == 0xFF )
  655. {
  656. print("LED_control_capability(mode,amount,index)");
  657. return;
  658. }
  659. // Only use capability on press
  660. // TODO Analog
  661. if ( stateType == 0x00 && state == 0x03 ) // Not on release
  662. return;
  663. // XXX
  664. // ISSI Chip locks up if we spam updates too quickly (might be an I2C bug on this side too -HaaTa)
  665. // Make sure we only send an update every 30 milliseconds at most
  666. // It may be possible to optimize speed even further, but will likely require serious time with a logic analyzer
  667. uint8_t currentTime = (uint8_t)systick_millis_count;
  668. int8_t compare = (int8_t)(currentTime - LED_control_timer) & 0x7F;
  669. if ( compare < 30 )
  670. {
  671. return;
  672. }
  673. LED_control_timer = currentTime;
  674. // Set the input structure
  675. LedControl *control = (LedControl*)args;
  676. // Interconnect broadcasting
  677. #if defined(ConnectEnabled_define)
  678. uint8_t send_packet = 0;
  679. uint8_t ignore_node = 0;
  680. // By default send to the *next* node, which will determine where to go next
  681. extern uint8_t Connect_id; // connect_scan.c
  682. uint8_t addr = Connect_id + 1;
  683. switch ( control->mode )
  684. {
  685. // Calculate the led address to send
  686. // If greater than the Total hannels
  687. // Set address - Total channels
  688. // Otherwise, ignore
  689. case LedControlMode_brightness_decrease:
  690. case LedControlMode_brightness_increase:
  691. case LedControlMode_brightness_set:
  692. // Ignore if led is on this node
  693. if ( control->index < LED_TotalChannels )
  694. break;
  695. // Calculate new led index
  696. control->index -= LED_TotalChannels;
  697. ignore_node = 1;
  698. send_packet = 1;
  699. break;
  700. // Broadcast to all nodes
  701. // XXX Do not set broadcasting address
  702. // Will send command twice
  703. case LedControlMode_brightness_decrease_all:
  704. case LedControlMode_brightness_increase_all:
  705. case LedControlMode_brightness_set_all:
  706. send_packet = 1;
  707. break;
  708. }
  709. // Only send interconnect remote capability packet if necessary
  710. if ( send_packet )
  711. {
  712. // generatedKeymap.h
  713. extern const Capability CapabilitiesList[];
  714. // Broadcast layerStackExact remote capability (0xFF is the broadcast id)
  715. Connect_send_RemoteCapability(
  716. addr,
  717. LED_control_capability_index,
  718. state,
  719. stateType,
  720. CapabilitiesList[ LED_control_capability_index ].argCount,
  721. args
  722. );
  723. }
  724. // If there is nothing to do on this node, ignore
  725. if ( ignore_node )
  726. return;
  727. #endif
  728. // Modify led state of this node
  729. LED_control( control );
  730. }
  731. // ----- CLI Command Functions -----
  732. // TODO Currently not working correctly
  733. void cliFunc_i2cSend( char* args )
  734. {
  735. /*
  736. char* curArgs;
  737. char* arg1Ptr;
  738. char* arg2Ptr = args;
  739. // Buffer used after interpretting the args, will be sent to I2C functions
  740. // NOTE: Limited to 8 bytes currently (can be increased if necessary
  741. #define i2cSend_BuffLenMax 8
  742. uint16_t buffer[ i2cSend_BuffLenMax ];
  743. uint8_t bufferLen = 0;
  744. // No \r\n by default after the command is entered
  745. print( NL );
  746. info_msg("Sending: ");
  747. // Parse args until a \0 is found
  748. while ( bufferLen < i2cSend_BuffLenMax )
  749. {
  750. curArgs = arg2Ptr; // Use the previous 2nd arg pointer to separate the next arg from the list
  751. CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
  752. // Stop processing args if no more are found
  753. if ( *arg1Ptr == '\0' )
  754. break;
  755. // If | is found, end sequence and start new one
  756. if ( *arg1Ptr == '|' )
  757. {
  758. print("| ");
  759. i2c_send( buffer, bufferLen );
  760. bufferLen = 0;
  761. continue;
  762. }
  763. // Interpret the argument
  764. buffer[ bufferLen++ ] = (uint8_t)numToInt( arg1Ptr );
  765. // Print out the arg
  766. dPrint( arg1Ptr );
  767. print(" ");
  768. }
  769. print( NL );
  770. i2c_send( buffer, bufferLen );
  771. */
  772. }
  773. /*
  774. void cliFunc_ledWPage( char* args )
  775. {
  776. char* curArgs;
  777. char* arg1Ptr;
  778. char* arg2Ptr = args;
  779. // First specify the write address
  780. curArgs = arg2Ptr;
  781. CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
  782. // Stop processing args if no more are found
  783. if ( *arg1Ptr == '\0' )
  784. return;
  785. uint8_t addr = numToInt( arg1Ptr );
  786. // Next process page and starting address
  787. curArgs = arg2Ptr;
  788. CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
  789. // Stop processing args if no more are found
  790. if ( *arg1Ptr == '\0' )
  791. return;
  792. uint8_t page[] = { addr, 0xFD, numToInt( arg1Ptr ) };
  793. curArgs = arg2Ptr;
  794. CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
  795. // Stop processing args if no more are found
  796. if ( *arg1Ptr == '\0' )
  797. return;
  798. uint8_t data[] = { addr, numToInt( arg1Ptr ), 0 };
  799. // Set the register page
  800. while ( I2C_Send( page, sizeof( page ), 0 ) == 0 )
  801. delay(1);
  802. // Process all args
  803. for ( ;; )
  804. {
  805. curArgs = arg2Ptr;
  806. CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
  807. // Stop processing args if no more are found
  808. if ( *arg1Ptr == '\0' )
  809. break;
  810. data[2] = numToInt( arg1Ptr );
  811. // Write register location and data to I2C
  812. while ( I2C_Send( data, sizeof( data ), 0 ) == 0 )
  813. delay(1);
  814. // Increment address
  815. data[1]++;
  816. }
  817. }
  818. */
  819. void cliFunc_ledReset( char* args )
  820. {
  821. print( NL ); // No \r\n by default after the command is entered
  822. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  823. {
  824. LED_zeroPages(
  825. LED_ChannelMapping[ ch ].bus,
  826. LED_ChannelMapping[ ch ].addr,
  827. 0x0B, 1, 0x00, 0x0C
  828. ); // Control Registers
  829. }
  830. // Clear buffers
  831. for ( uint8_t buf = 0; buf < ISSI_Chips_define; buf++ )
  832. {
  833. memset( (void*)LED_pageBuffer[ buf ].buffer, 0, LED_BufferLength * 2 );
  834. }
  835. LED_reset();
  836. // TODO Remove me
  837. /*
  838. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  839. {
  840. LED_sendPage(
  841. LED_ChannelMapping[ ch ].bus,
  842. LED_ChannelMapping[ ch ].addr,
  843. 0x0B, 1, 0x00, 0x0C
  844. ); // Control Registers
  845. }
  846. */
  847. }
  848. void cliFunc_ledSpeed( char* args )
  849. {
  850. print( NL ); // No \r\n by default after the command is entered
  851. char* curArgs;
  852. char* arg1Ptr;
  853. char* arg2Ptr = args;
  854. uint8_t speed = ISSI_AnimationSpeed_define;
  855. // Process speed argument if given
  856. curArgs = arg2Ptr;
  857. CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
  858. // Check if f argument was given
  859. switch ( *arg1Ptr )
  860. {
  861. case 'f':
  862. case 'F':
  863. info_msg("FPS Toggle");
  864. LED_displayFPS = !LED_displayFPS;
  865. return;
  866. }
  867. // Stop processing args if no more are found
  868. if ( *arg1Ptr != '\0' )
  869. {
  870. speed = numToInt( arg1Ptr );
  871. }
  872. // Default to default speed
  873. else
  874. {
  875. info_msg("Setting default speed: ");
  876. printInt8( speed );
  877. }
  878. // Set refresh speed per ISSI chip
  879. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  880. {
  881. uint8_t addr = LED_ChannelMapping[ ch ].addr;
  882. uint8_t bus = LED_ChannelMapping[ ch ].bus;
  883. // Default refresh speed - TxA
  884. // T is typically 11ms
  885. // A is 1 to 64 (where 0 is 64)
  886. LED_writeReg( bus, addr, 0x03, speed, 0x0B );
  887. }
  888. }
  889. void cliFunc_ledCtrl( char* args )
  890. {
  891. char* curArgs;
  892. char* arg1Ptr;
  893. char* arg2Ptr = args;
  894. LedControl control;
  895. // First process mode
  896. curArgs = arg2Ptr;
  897. CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
  898. // Stop processing args if no more are found
  899. if ( *arg1Ptr == '\0' )
  900. return;
  901. control.mode = numToInt( arg1Ptr );
  902. // Next process amount
  903. curArgs = arg2Ptr;
  904. CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
  905. // Stop processing args if no more are found
  906. if ( *arg1Ptr == '\0' )
  907. return;
  908. control.amount = numToInt( arg1Ptr );
  909. // Finally process led index, if it exists
  910. // Default to 0
  911. curArgs = arg2Ptr;
  912. CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
  913. control.index = *arg1Ptr == '\0' ? 0 : numToInt( arg1Ptr );
  914. // Process request
  915. LED_control( &control );
  916. }
  917. void cliFunc_ledNFrame( char* args )
  918. {
  919. // TODO REMOVEME
  920. LED_FrameBufferStart = 1;
  921. return;
  922. /*
  923. LED_FrameBufferReset = 0;
  924. LED_FrameBuffersReady = LED_FrameBuffersMax;
  925. LED_FrameBufferStart = 1;
  926. */
  927. //LED_FrameBuffersReady++;
  928. //LED_FrameBufferStart = 1;
  929. //uint8_t addr = LED_pageBuffer[ 0 ].i2c_addr;
  930. //LED_writeReg( addr, 0x00, 0x08, 0x0B );
  931. //LED_FrameBuffersReady--;
  932. // Iterate over available buffers
  933. // Each pass can only send one buffer (per chip)
  934. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  935. {
  936. // XXX It is more efficient to only send positions that are used
  937. // However, this may actually have more addressing overhead
  938. // For simplicity, just sending the full 144 positions per ISSI chip
  939. uint8_t addr = LED_ChannelMapping[ ch ].addr;
  940. uint8_t bus = LED_ChannelMapping[ ch ].bus;
  941. LED_sendPage(
  942. bus,
  943. addr,
  944. (uint16_t*)&LED_pageBuffer[ ch ],
  945. sizeof( LED_Buffer ) / 2,
  946. LED_FrameBufferPage
  947. );
  948. }
  949. // Increment the buffer page
  950. // And reset if necessary
  951. if ( ++LED_FrameBufferPage >= LED_FrameBuffersMax * 2 )
  952. {
  953. LED_FrameBufferPage = 0;
  954. }
  955. }