Kiibohd Controller
Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

led_scan.c 26KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060
  1. /* Copyright (C) 2014-2015 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 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. #else
  51. #define ISSI_Ch1 0xB0
  52. #define ISSI_Ch2 0xB2
  53. #define ISSI_Ch3 0xB4
  54. #define ISSI_Ch4 0xB6
  55. #endif
  56. // ----- Macros -----
  57. #define LED_MaskDefine(ch) \
  58. { \
  59. ISSI_Ch##ch, /* I2C address */ \
  60. 0x00, /* Starting register address */ \
  61. { ISSILedMask##ch##_define }, \
  62. }
  63. #define LED_BrightnessDefine(ch) \
  64. { \
  65. ISSI_Ch##ch, /* I2C address */ \
  66. 0x24, /* Starting register address */ \
  67. { ISSILedBrightness##ch##_define }, \
  68. }
  69. // ----- Structs -----
  70. typedef struct LED_Buffer {
  71. uint16_t i2c_addr;
  72. uint16_t reg_addr;
  73. uint16_t buffer[LED_BufferLength];
  74. } LED_Buffer;
  75. typedef struct LED_EnableBuffer {
  76. uint16_t i2c_addr;
  77. uint16_t reg_addr;
  78. uint16_t buffer[LED_EnableBufferLength];
  79. } LED_EnableBuffer;
  80. // ----- Function Declarations -----
  81. // CLI Functions
  82. void cliFunc_i2cSend ( char* args );
  83. void cliFunc_ledCtrl ( char* args );
  84. void cliFunc_ledNFrame( char* args );
  85. void cliFunc_ledStart ( char* args );
  86. void cliFunc_ledTest ( char* args );
  87. void cliFunc_ledWPage ( char* args );
  88. void cliFunc_ledZero ( char* args );
  89. // ----- Variables -----
  90. // Scan Module command dictionary
  91. CLIDict_Entry( i2cSend, "Send I2C sequence of bytes. Use |'s to split sequences with a stop." );
  92. CLIDict_Entry( ledCtrl, "Basic LED control. Args: <mode> <amount> [<index>]" );
  93. CLIDict_Entry( ledNFrame, "Increment led frame." );
  94. CLIDict_Entry( ledStart, "Disable software shutdown." );
  95. CLIDict_Entry( ledTest, "Test out the led pages." );
  96. CLIDict_Entry( ledWPage, "Write to given register page starting at address. i.e. 0xE8 0x2 0x24 0xF0 0x12" );
  97. CLIDict_Entry( ledZero, "Zero out LED register pages (non-configuration)." );
  98. CLIDict_Def( ledCLIDict, "ISSI LED Module Commands" ) = {
  99. CLIDict_Item( i2cSend ),
  100. CLIDict_Item( ledCtrl ),
  101. CLIDict_Item( ledNFrame ),
  102. CLIDict_Item( ledStart ),
  103. CLIDict_Item( ledTest ),
  104. CLIDict_Item( ledWPage ),
  105. CLIDict_Item( ledZero ),
  106. { 0, 0, 0 } // Null entry for dictionary end
  107. };
  108. LED_Buffer LED_pageBuffer[ ISSI_Chips_define ];
  109. uint8_t LED_FrameBuffersReady; // Starts at maximum, reset on interrupt from ISSI
  110. volatile uint8_t LED_FrameBufferReset; // INTB interrupt received, reset available buffer count when ready
  111. uint8_t LED_FrameBufferPage; // Current page of the buffer
  112. uint8_t LED_FrameBufferStart; // Whether or not a start signal can be sent
  113. // Enable mask and default brightness for ISSI chip channel
  114. const LED_EnableBuffer LED_ledEnableMask[ISSI_Chips_define] = {
  115. LED_MaskDefine( 1 ),
  116. #if ISSI_Chips_define >= 2
  117. LED_MaskDefine( 2 ),
  118. #endif
  119. #if ISSI_Chips_define >= 3
  120. LED_MaskDefine( 3 ),
  121. #endif
  122. #if ISSI_Chips_define >= 4
  123. LED_MaskDefine( 4 ),
  124. #endif
  125. };
  126. // Default LED brightness
  127. const LED_Buffer LED_defaultBrightness[ISSI_Chips_define] = {
  128. LED_BrightnessDefine( 1 ),
  129. #if ISSI_Chips_define >= 2
  130. LED_BrightnessDefine( 2 ),
  131. #endif
  132. #if ISSI_Chips_define >= 3
  133. LED_BrightnessDefine( 3 ),
  134. #endif
  135. #if ISSI_Chips_define >= 4
  136. LED_BrightnessDefine( 4 ),
  137. #endif
  138. };
  139. #if ISSI_Chips_define >= 5
  140. #error "Invalid number of ISSI Chips"
  141. #endif
  142. // ----- Interrupt Functions -----
  143. void portb_isr()
  144. {
  145. // Check for ISSI INTB IRQ
  146. if ( PORTB_ISFR & (1 << 17) )
  147. {
  148. // Set frame buffer replenish condition
  149. LED_FrameBufferReset = 1;
  150. // Clear IRQ
  151. PORTB_ISFR |= (1 << 17);
  152. }
  153. }
  154. // ----- Functions -----
  155. void LED_zeroPages( uint8_t addr, uint8_t startPage, uint8_t numPages, uint8_t startReg, uint8_t endReg )
  156. {
  157. // Clear Page
  158. // Max length of a page + chip id + reg start
  159. uint16_t clearPage[2 + 0xB4] = { 0 };
  160. clearPage[0] = addr;
  161. clearPage[1] = startReg;
  162. // Iterate through given pages, zero'ing out the given register regions
  163. for ( uint8_t page = startPage; page < startPage + numPages; page++ )
  164. {
  165. // Page Setup
  166. uint16_t pageSetup[] = { addr, 0xFD, page };
  167. // Setup page
  168. while ( i2c_send( pageSetup, sizeof( pageSetup ) / 2 ) == -1 )
  169. delay(1);
  170. // Zero out page
  171. while ( i2c_send( clearPage, 2 + endReg - startReg ) == -1 )
  172. delay(1);
  173. }
  174. // Wait until finished zero'ing
  175. while ( i2c_busy() )
  176. delay(1);
  177. }
  178. void LED_sendPage( uint8_t addr, uint16_t *buffer, uint32_t len, uint8_t page )
  179. {
  180. /*
  181. info_msg("I2C Send Page Addr: ");
  182. printHex( addr );
  183. print(" Len: ");
  184. printHex( len );
  185. print(" Page: ");
  186. printHex( page );
  187. print( NL );
  188. */
  189. // Page Setup
  190. uint16_t pageSetup[] = { addr, 0xFD, page };
  191. // Setup page
  192. while ( i2c_send( pageSetup, sizeof( pageSetup ) / 2 ) == -1 )
  193. delay(1);
  194. // Write page to I2C Tx Buffer
  195. while ( i2c_send( buffer, len ) == -1 )
  196. delay(1);
  197. }
  198. // Write address
  199. void LED_writeReg( uint8_t addr, uint8_t reg, uint8_t val, uint8_t page )
  200. {
  201. // Page Setup
  202. uint16_t pageSetup[] = { addr, 0xFD, page };
  203. // Reg Write Setup
  204. uint16_t writeData[] = { addr, reg, val };
  205. // Setup page
  206. while ( i2c_send( pageSetup, sizeof( pageSetup ) / 2 ) == -1 )
  207. delay(1);
  208. // Write register
  209. while ( i2c_send( writeData, sizeof( writeData ) / 2 ) == -1 )
  210. delay(1);
  211. // Delay until written
  212. while ( i2c_busy() )
  213. delay(1);
  214. }
  215. // Read address
  216. // TODO Not working?
  217. uint8_t LED_readReg( uint8_t addr, uint8_t reg, uint8_t page )
  218. {
  219. // Software shutdown must be enabled to read registers
  220. LED_writeReg( addr, 0x0A, 0x00, 0x0B );
  221. // Page Setup
  222. uint16_t pageSetup[] = { addr, 0xFD, page };
  223. // Setup page
  224. while ( i2c_send( pageSetup, sizeof( pageSetup ) / 2 ) == -1 )
  225. delay(1);
  226. // Register Setup
  227. uint16_t regSetup[] = { addr, reg };
  228. // Configure register
  229. while ( i2c_send( regSetup, sizeof( regSetup ) / 2 ) == -1 )
  230. delay(1);
  231. // Register Read Command
  232. uint16_t regReadCmd[] = { addr | 0x1, I2C_READ };
  233. uint8_t recv_data;
  234. // Request single register byte
  235. while ( i2c_read( regReadCmd, sizeof( regReadCmd ) / 2, &recv_data ) == -1 )
  236. delay(1);
  237. // Disable software shutdown
  238. LED_writeReg( addr, 0x0A, 0x01, 0x0B );
  239. return recv_data;
  240. }
  241. // Setup
  242. inline void LED_setup()
  243. {
  244. // Register Scan CLI dictionary
  245. CLI_registerDictionary( ledCLIDict, ledCLIDictName );
  246. // Initialize I2C
  247. i2c_setup();
  248. // Setup LED_pageBuffer addresses and brightness section
  249. LED_pageBuffer[0].i2c_addr = ISSI_Ch1;
  250. LED_pageBuffer[0].reg_addr = 0x24;
  251. #if ISSI_Chips_define >= 2
  252. LED_pageBuffer[1].i2c_addr = ISSI_Ch2;
  253. LED_pageBuffer[1].reg_addr = 0x24;
  254. #endif
  255. #if ISSI_Chips_define >= 3
  256. LED_pageBuffer[2].i2c_addr = ISSI_Ch3;
  257. LED_pageBuffer[2].reg_addr = 0x24;
  258. #endif
  259. #if ISSI_Chips_define >= 4
  260. LED_pageBuffer[3].i2c_addr = ISSI_Ch4;
  261. LED_pageBuffer[3].reg_addr = 0x24;
  262. #endif
  263. // Enable Hardware shutdown (pull low)
  264. GPIOB_PDDR |= (1<<16);
  265. PORTB_PCR16 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
  266. GPIOB_PCOR |= (1<<16);
  267. // Zero out Frame Registers
  268. // This needs to be done before disabling the hardware shutdown (or the leds will do undefined things)
  269. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  270. {
  271. uint8_t addr = LED_pageBuffer[ ch ].i2c_addr;
  272. LED_zeroPages( addr, 0x0B, 1, 0x00, 0x0C ); // Control Registers
  273. }
  274. // Disable Hardware shutdown of ISSI chip (pull high)
  275. GPIOB_PSOR |= (1<<16);
  276. // Prepare pin to read INTB interrupt of ISSI chip (Active Low)
  277. // Enable interrupt to detect falling edge
  278. // Uses external pullup resistor
  279. GPIOB_PDDR |= ~(1<<17);
  280. PORTB_PCR17 = PORT_PCR_IRQC(0xA) | PORT_PCR_PFE | PORT_PCR_MUX(1);
  281. LED_FrameBufferReset = 0; // Clear frame buffer reset condition for ISSI
  282. // Enable PORTB interrupt
  283. NVIC_ENABLE_IRQ( IRQ_PORTB );
  284. // Reset frame buffer used count
  285. LED_FrameBuffersReady = LED_FrameBuffersMax;
  286. // Starting page for the buffers
  287. LED_FrameBufferPage = 4;
  288. // Initially do not allow autoplay to restart
  289. LED_FrameBufferStart = 0;
  290. // Clear LED Pages
  291. // Enable LEDs based upon mask
  292. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  293. {
  294. uint8_t addr = LED_pageBuffer[ ch ].i2c_addr;
  295. LED_zeroPages( addr, 0x00, 8, 0x00, 0xB4 ); // LED Registers
  296. // For each page
  297. for ( uint8_t pg = 0; pg < LED_FrameBuffersMax * 2; pg++ )
  298. {
  299. LED_sendPage(
  300. addr,
  301. (uint16_t*)&LED_ledEnableMask[ ch ],
  302. sizeof( LED_EnableBuffer ) / 2,
  303. pg
  304. );
  305. }
  306. }
  307. // Setup ISSI auto frame play, but do not start yet
  308. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  309. {
  310. uint8_t addr = LED_pageBuffer[ ch ].i2c_addr;
  311. // CNS 1 loop, FNS 4 frames - 0x14
  312. LED_writeReg( addr, 0x02, 0x14, 0x0B );
  313. // Default refresh speed - TxA
  314. // T is typically 11ms
  315. // A is 1 to 64 (where 0 is 64)
  316. LED_writeReg( addr, 0x03, ISSI_AnimationSpeed_define, 0x0B );
  317. // Set MODE to Auto Frame Play
  318. LED_writeReg( addr, 0x00, 0x08, 0x0B );
  319. }
  320. // Disable Software shutdown of ISSI chip
  321. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  322. {
  323. uint8_t addr = LED_pageBuffer[ ch ].i2c_addr;
  324. LED_writeReg( addr, 0x0A, 0x01, 0x0B );
  325. }
  326. }
  327. // LED Linked Send
  328. // Call-back for i2c write when updating led display
  329. uint8_t LED_chipSend;
  330. void LED_linkedSend()
  331. {
  332. // Check if we've updated all the ISSI chips for this frame
  333. if ( LED_chipSend >= ISSI_Chips_define )
  334. {
  335. // Increment the buffer page
  336. // And reset if necessary
  337. if ( ++LED_FrameBufferPage >= LED_FrameBuffersMax * 2 )
  338. {
  339. LED_FrameBufferPage = 0;
  340. }
  341. // Now ready to update the frame buffer
  342. Pixel_FrameState = FrameState_Update;
  343. return;
  344. }
  345. // Update ISSI Frame State
  346. Pixel_FrameState = FrameState_Sending;
  347. // Debug
  348. /*
  349. dbug_msg("Linked Send: chip(");
  350. printHex( LED_chipSend );
  351. print(") frame(");
  352. printHex( LED_FrameBufferPage );
  353. print(") addr(");
  354. printHex( LED_pageBuffer[0].i2c_addr );
  355. print(") reg(");
  356. printHex( LED_pageBuffer[0].reg_addr );
  357. print(") len(");
  358. printHex( sizeof( LED_Buffer ) / 2 );
  359. print(") data[]" NL "(");
  360. for ( uint8_t c = 0; c < 9; c++ )
  361. //for ( uint8_t c = 0; c < sizeof( LED_Buffer ) / 2 - 2; c++ )
  362. {
  363. printHex( LED_pageBuffer[0].buffer[c] );
  364. print(" ");
  365. }
  366. print(")" NL);
  367. */
  368. // Send, and recursively call this function when finished
  369. while ( i2c_send_sequence(
  370. (uint16_t*)&LED_pageBuffer[ LED_chipSend ],
  371. sizeof( LED_Buffer ) / 2,
  372. 0,
  373. LED_linkedSend,
  374. 0
  375. ) == -1 )
  376. delay(1);
  377. // Increment chip position
  378. LED_chipSend++;
  379. }
  380. // LED State processing loop
  381. uint32_t LED_timePrev = 0;
  382. inline void LED_scan()
  383. {
  384. // Check to see if frame buffers are ready to replenish
  385. if ( LED_FrameBufferReset )
  386. {
  387. LED_FrameBufferReset = 0;
  388. LED_FrameBufferStart = 1;
  389. // Debug Status
  390. dbug_msg("4frames/");
  391. printInt32( systick_millis_count - LED_timePrev );
  392. LED_timePrev = systick_millis_count;
  393. print("ms" NL);
  394. }
  395. // Make sure there are buffers available
  396. if ( LED_FrameBuffersReady == 0 )
  397. {
  398. // Only start if we haven't already
  399. // And if we've finished updating the buffers
  400. if ( !LED_FrameBufferStart || Pixel_FrameState == FrameState_Sending )
  401. return;
  402. // Buffers are now full, start signal can be sent
  403. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  404. {
  405. uint8_t addr = LED_pageBuffer[ ch ].i2c_addr;
  406. // Start Auto Frame Play on either frame 1 or 5
  407. uint8_t frame = LED_FrameBufferPage == 0 ? 4 : 0;
  408. LED_writeReg( addr, 0x00, 0x08 | frame, 0x0B );
  409. }
  410. LED_FrameBufferStart = 0;
  411. LED_FrameBuffersReady = LED_FrameBuffersMax;
  412. return;
  413. }
  414. /*
  415. else
  416. {
  417. dbug_msg(":/ - Start(");
  418. printHex( LED_FrameBufferStart );
  419. print(") BuffersReady(");
  420. printHex( LED_FrameBuffersReady );
  421. print(") State(");
  422. printHex( Pixel_FrameState );
  423. print(")"NL);
  424. }
  425. */
  426. // Only send frame to ISSI chip if buffers are ready
  427. if ( Pixel_FrameState != FrameState_Ready )
  428. return;
  429. LED_FrameBuffersReady--;
  430. // Set the page of all the ISSI chips
  431. // This way we can easily link the buffers to send the brightnesses in the background
  432. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  433. {
  434. // Page Setup
  435. uint8_t addr = LED_pageBuffer[ ch ].i2c_addr;
  436. uint16_t pageSetup[] = { addr, 0xFD, LED_FrameBufferPage };
  437. // Send each update
  438. while ( i2c_send( pageSetup, sizeof( pageSetup ) / 2 ) == -1 )
  439. delay(1);
  440. }
  441. // Send current set of buffers
  442. // Uses interrupts to send to all the ISSI chips
  443. // Pixel_FrameState will be updated when complete
  444. LED_chipSend = 0; // Start with chip 0
  445. LED_linkedSend();
  446. }
  447. // ----- Capabilities -----
  448. // Basic LED Control Capability
  449. typedef enum LedControlMode {
  450. // Single LED Modes
  451. LedControlMode_brightness_decrease,
  452. LedControlMode_brightness_increase,
  453. LedControlMode_brightness_set,
  454. // Set all LEDs (index argument not required)
  455. LedControlMode_brightness_decrease_all,
  456. LedControlMode_brightness_increase_all,
  457. LedControlMode_brightness_set_all,
  458. } LedControlMode;
  459. typedef struct LedControl {
  460. LedControlMode mode; // XXX Make sure to adjust the .kll capability if this variable is larger than 8 bits
  461. uint8_t amount;
  462. uint16_t index;
  463. } LedControl;
  464. void LED_control( LedControl *control )
  465. {
  466. // Configure based upon the given mode
  467. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  468. {
  469. // TODO Perhaps do gamma adjustment?
  470. switch ( control->mode )
  471. {
  472. case LedControlMode_brightness_decrease:
  473. // Don't worry about rolling over, the cycle is quick
  474. LED_pageBuffer[ ch ].buffer[ control->index ] -= control->amount;
  475. break;
  476. case LedControlMode_brightness_increase:
  477. // Don't worry about rolling over, the cycle is quick
  478. LED_pageBuffer[ ch ].buffer[ control->index ] += control->amount;
  479. break;
  480. case LedControlMode_brightness_set:
  481. LED_pageBuffer[ ch ].buffer[ control->index ] = control->amount;
  482. break;
  483. case LedControlMode_brightness_decrease_all:
  484. for ( uint8_t channel = 0; channel < LED_TotalChannels; channel++ )
  485. {
  486. // Don't worry about rolling over, the cycle is quick
  487. LED_pageBuffer[ ch ].buffer[ channel ] -= control->amount;
  488. }
  489. break;
  490. case LedControlMode_brightness_increase_all:
  491. for ( uint8_t channel = 0; channel < LED_TotalChannels; channel++ )
  492. {
  493. // Don't worry about rolling over, the cycle is quick
  494. LED_pageBuffer[ ch ].buffer[ channel ] += control->amount;
  495. }
  496. break;
  497. case LedControlMode_brightness_set_all:
  498. for ( uint8_t channel = 0; channel < LED_TotalChannels; channel++ )
  499. {
  500. LED_pageBuffer[ ch ].buffer[ channel ] = control->amount;
  501. }
  502. break;
  503. }
  504. }
  505. // Sync LED buffer with ISSI chip buffer
  506. // TODO Support multiple frames
  507. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  508. {
  509. LED_sendPage( LED_pageBuffer[ ch ].i2c_addr, (uint16_t*)&LED_pageBuffer[ ch ], sizeof( LED_Buffer ) / 2, 0 );
  510. }
  511. }
  512. uint8_t LED_control_timer = 0;
  513. void LED_control_capability( uint8_t state, uint8_t stateType, uint8_t *args )
  514. {
  515. // Display capability name
  516. if ( stateType == 0xFF && state == 0xFF )
  517. {
  518. print("LED_control_capability(mode,amount,index)");
  519. return;
  520. }
  521. // Only use capability on press
  522. // TODO Analog
  523. if ( stateType == 0x00 && state == 0x03 ) // Not on release
  524. return;
  525. // XXX
  526. // ISSI Chip locks up if we spam updates too quickly (might be an I2C bug on this side too -HaaTa)
  527. // Make sure we only send an update every 30 milliseconds at most
  528. // It may be possible to optimize speed even further, but will likely require serious time with a logic analyzer
  529. uint8_t currentTime = (uint8_t)systick_millis_count;
  530. int8_t compare = (int8_t)(currentTime - LED_control_timer) & 0x7F;
  531. if ( compare < 30 )
  532. {
  533. return;
  534. }
  535. LED_control_timer = currentTime;
  536. // Set the input structure
  537. LedControl *control = (LedControl*)args;
  538. // Interconnect broadcasting
  539. #if defined(ConnectEnabled_define)
  540. uint8_t send_packet = 0;
  541. uint8_t ignore_node = 0;
  542. // By default send to the *next* node, which will determine where to go next
  543. extern uint8_t Connect_id; // connect_scan.c
  544. uint8_t addr = Connect_id + 1;
  545. switch ( control->mode )
  546. {
  547. // Calculate the led address to send
  548. // If greater than the Total hannels
  549. // Set address - Total channels
  550. // Otherwise, ignore
  551. case LedControlMode_brightness_decrease:
  552. case LedControlMode_brightness_increase:
  553. case LedControlMode_brightness_set:
  554. // Ignore if led is on this node
  555. if ( control->index < LED_TotalChannels )
  556. break;
  557. // Calculate new led index
  558. control->index -= LED_TotalChannels;
  559. ignore_node = 1;
  560. send_packet = 1;
  561. break;
  562. // Broadcast to all nodes
  563. // XXX Do not set broadcasting address
  564. // Will send command twice
  565. case LedControlMode_brightness_decrease_all:
  566. case LedControlMode_brightness_increase_all:
  567. case LedControlMode_brightness_set_all:
  568. send_packet = 1;
  569. break;
  570. }
  571. // Only send interconnect remote capability packet if necessary
  572. if ( send_packet )
  573. {
  574. // generatedKeymap.h
  575. extern const Capability CapabilitiesList[];
  576. // Broadcast layerStackExact remote capability (0xFF is the broadcast id)
  577. Connect_send_RemoteCapability(
  578. addr,
  579. LED_control_capability_index,
  580. state,
  581. stateType,
  582. CapabilitiesList[ LED_control_capability_index ].argCount,
  583. args
  584. );
  585. }
  586. // If there is nothing to do on this node, ignore
  587. if ( ignore_node )
  588. return;
  589. #endif
  590. // Modify led state of this node
  591. LED_control( control );
  592. }
  593. // ----- CLI Command Functions -----
  594. // TODO Currently not working correctly
  595. void cliFunc_i2cSend( char* args )
  596. {
  597. char* curArgs;
  598. char* arg1Ptr;
  599. char* arg2Ptr = args;
  600. // Buffer used after interpretting the args, will be sent to I2C functions
  601. // NOTE: Limited to 8 bytes currently (can be increased if necessary
  602. #define i2cSend_BuffLenMax 8
  603. uint16_t buffer[ i2cSend_BuffLenMax ];
  604. uint8_t bufferLen = 0;
  605. // No \r\n by default after the command is entered
  606. print( NL );
  607. info_msg("Sending: ");
  608. // Parse args until a \0 is found
  609. while ( bufferLen < i2cSend_BuffLenMax )
  610. {
  611. curArgs = arg2Ptr; // Use the previous 2nd arg pointer to separate the next arg from the list
  612. CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
  613. // Stop processing args if no more are found
  614. if ( *arg1Ptr == '\0' )
  615. break;
  616. // If | is found, end sequence and start new one
  617. if ( *arg1Ptr == '|' )
  618. {
  619. print("| ");
  620. i2c_send( buffer, bufferLen );
  621. bufferLen = 0;
  622. continue;
  623. }
  624. // Interpret the argument
  625. buffer[ bufferLen++ ] = (uint8_t)numToInt( arg1Ptr );
  626. // Print out the arg
  627. dPrint( arg1Ptr );
  628. print(" ");
  629. }
  630. print( NL );
  631. i2c_send( buffer, bufferLen );
  632. }
  633. void cliFunc_ledWPage( char* args )
  634. {
  635. /*
  636. char* curArgs;
  637. char* arg1Ptr;
  638. char* arg2Ptr = args;
  639. // First specify the write address
  640. curArgs = arg2Ptr;
  641. CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
  642. // Stop processing args if no more are found
  643. if ( *arg1Ptr == '\0' )
  644. return;
  645. uint8_t addr = numToInt( arg1Ptr );
  646. // Next process page and starting address
  647. curArgs = arg2Ptr;
  648. CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
  649. // Stop processing args if no more are found
  650. if ( *arg1Ptr == '\0' )
  651. return;
  652. uint8_t page[] = { addr, 0xFD, numToInt( arg1Ptr ) };
  653. curArgs = arg2Ptr;
  654. CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
  655. // Stop processing args if no more are found
  656. if ( *arg1Ptr == '\0' )
  657. return;
  658. uint8_t data[] = { addr, numToInt( arg1Ptr ), 0 };
  659. // Set the register page
  660. while ( I2C_Send( page, sizeof( page ), 0 ) == 0 )
  661. delay(1);
  662. // Process all args
  663. for ( ;; )
  664. {
  665. curArgs = arg2Ptr;
  666. CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
  667. // Stop processing args if no more are found
  668. if ( *arg1Ptr == '\0' )
  669. break;
  670. data[2] = numToInt( arg1Ptr );
  671. // Write register location and data to I2C
  672. while ( I2C_Send( data, sizeof( data ), 0 ) == 0 )
  673. delay(1);
  674. // Increment address
  675. data[1]++;
  676. }
  677. */
  678. }
  679. void cliFunc_ledStart( char* args )
  680. {
  681. print( NL ); // No \r\n by default after the command is entered
  682. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  683. {
  684. LED_zeroPages( LED_ledEnableMask[ ch ].i2c_addr, 0x0B, 1, 0x00, 0x0C ); // Control Registers
  685. //LED_zeroPages( 0x00, 8, 0x00, 0xB4 ); // LED Registers
  686. LED_writeReg( LED_ledEnableMask[ ch ].i2c_addr, 0x0A, 0x01, 0x0B );
  687. LED_sendPage( LED_ledEnableMask[ ch ].i2c_addr, (uint16_t*)&LED_ledEnableMask[ ch ], sizeof( LED_EnableBuffer ) / 2, 0 );
  688. }
  689. }
  690. void cliFunc_ledTest( char* args )
  691. {
  692. print( NL ); // No \r\n by default after the command is entered
  693. char* curArgs;
  694. char* arg1Ptr;
  695. char* arg2Ptr = args;
  696. uint8_t speed = ISSI_AnimationSpeed_define;
  697. // Process speed argument if given
  698. curArgs = arg2Ptr;
  699. CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
  700. // Stop processing args if no more are found
  701. if ( *arg1Ptr != '\0' )
  702. speed = numToInt( arg1Ptr );
  703. // TODO REMOVEME
  704. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  705. {
  706. uint8_t addr = LED_pageBuffer[ ch ].i2c_addr;
  707. // CNS 1 loop, FNS 4 frames - 0x14
  708. //LED_writeReg( addr, 0x02, 0x14, 0x0B );
  709. // Default refresh speed - TxA
  710. // T is typically 11ms
  711. // A is 1 to 64 (where 0 is 64)
  712. LED_writeReg( addr, 0x03, speed, 0x0B );
  713. // Set MODE to Auto Frame Play
  714. // Set FS to 5, this is to train the IRQ on the ISSI for the processing loop
  715. // The first 4 frames are blank, we fill the last 4
  716. // Clear the interrupt, and the movie display starts at frame 5
  717. //LED_writeReg( addr, 0x00, 0x0C, 0x0B );
  718. }
  719. return;
  720. // Zero out Frame Registers
  721. // This needs to be done before disabling the hardware shutdown (or the leds will do undefined things)
  722. info_print("LED - Zeroing out all pages");
  723. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  724. {
  725. uint8_t addr = LED_pageBuffer[ ch ].i2c_addr;
  726. LED_zeroPages( addr, 0x0B, 1, 0x00, 0x0C ); // Control Registers
  727. LED_zeroPages( addr, 0x00, 8, 0x00, 0xB4 ); // LED Registers
  728. }
  729. // Clear LED Pages
  730. // Enable LEDs based upon mask
  731. info_print("LED - Setting LED enable mask");
  732. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  733. //for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  734. {
  735. uint8_t addr = LED_pageBuffer[ ch ].i2c_addr;
  736. // For each page
  737. for ( uint8_t pg = 0; pg < LED_FrameBuffersMax * 2; pg++ )
  738. {
  739. LED_sendPage(
  740. addr,
  741. (uint16_t*)&LED_ledEnableMask[ ch ],
  742. sizeof( LED_EnableBuffer ) / 2,
  743. pg
  744. );
  745. }
  746. }
  747. // Setup ISSI auto frame play, but do not start yet
  748. /*
  749. info_print("LED - Enabling 8 frame 3 loop auto play");
  750. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  751. {
  752. uint8_t addr = LED_pageBuffer[ ch ].i2c_addr;
  753. // CNS 3 loops, FNS all frames - 0x30
  754. LED_writeReg( addr, 0x02, 0x30, 0x0B );
  755. // Default refresh speed - TxA
  756. // T is typically 11ms
  757. // A is 1 to 64 (where 0 is 64)
  758. LED_writeReg( addr, 0x03, speed, 0x0B );
  759. // Set MODE to Auto Frame Play
  760. // Set FS to frame 1
  761. //LED_writeReg( addr, 0x00, 0x08, 0x0B );
  762. }
  763. */
  764. // Load frame data
  765. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  766. {
  767. uint8_t addr = LED_pageBuffer[ ch ].i2c_addr;
  768. // Load each page with a different led enabled
  769. uint16_t data[] = {
  770. addr, 0xFD, 0x00,
  771. };
  772. while( i2c_send( data, sizeof( data ) / 2 ) == -1 )
  773. delay( 1 );
  774. data[1] = 0x24;
  775. data[2] = 0xFF;
  776. while( i2c_send( data, sizeof( data ) / 2 ) == -1 )
  777. delay( 1 );
  778. }
  779. // Disable Software shutdown of ISSI chip
  780. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  781. {
  782. uint8_t addr = LED_pageBuffer[ ch ].i2c_addr;
  783. LED_writeReg( addr, 0x0A, 0x01, 0x0B );
  784. }
  785. /*
  786. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  787. {
  788. LED_sendPage( LED_defaultBrightness[ ch ].i2c_addr, (uint16_t*)&LED_defaultBrightness[ ch ], sizeof( LED_Buffer ), 0 );
  789. }
  790. */
  791. }
  792. void cliFunc_ledZero( char* args )
  793. {
  794. print( NL ); // No \r\n by default after the command is entered
  795. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  796. {
  797. LED_zeroPages( LED_defaultBrightness[ ch ].i2c_addr, 0x0B, 1, 0x00, 0x0C ); // Control Registers
  798. LED_zeroPages( LED_defaultBrightness[ ch ].i2c_addr, 0x00, 8, 0x24, 0xB4 ); // Only PWMs
  799. }
  800. }
  801. void cliFunc_ledCtrl( char* args )
  802. {
  803. char* curArgs;
  804. char* arg1Ptr;
  805. char* arg2Ptr = args;
  806. LedControl control;
  807. // First process mode
  808. curArgs = arg2Ptr;
  809. CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
  810. // Stop processing args if no more are found
  811. if ( *arg1Ptr == '\0' )
  812. return;
  813. control.mode = numToInt( arg1Ptr );
  814. // Next process amount
  815. curArgs = arg2Ptr;
  816. CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
  817. // Stop processing args if no more are found
  818. if ( *arg1Ptr == '\0' )
  819. return;
  820. control.amount = numToInt( arg1Ptr );
  821. // Finally process led index, if it exists
  822. // Default to 0
  823. curArgs = arg2Ptr;
  824. CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
  825. control.index = *arg1Ptr == '\0' ? 0 : numToInt( arg1Ptr );
  826. // Process request
  827. LED_control( &control );
  828. }
  829. void cliFunc_ledNFrame( char* args )
  830. {
  831. // TODO REMOVEME
  832. LED_FrameBufferStart = 1;
  833. return;
  834. /*
  835. LED_FrameBufferReset = 0;
  836. LED_FrameBuffersReady = LED_FrameBuffersMax;
  837. LED_FrameBufferStart = 1;
  838. */
  839. //LED_FrameBuffersReady++;
  840. //LED_FrameBufferStart = 1;
  841. //uint8_t addr = LED_pageBuffer[ 0 ].i2c_addr;
  842. //LED_writeReg( addr, 0x00, 0x08, 0x0B );
  843. //LED_FrameBuffersReady--;
  844. // Iterate over available buffers
  845. // Each pass can only send one buffer (per chip)
  846. for ( uint8_t ch = 0; ch < ISSI_Chips_define; ch++ )
  847. {
  848. // XXX It is more efficient to only send positions that are used
  849. // However, this may actually have more addressing overhead
  850. // For simplicity, just sending the full 144 positions per ISSI chip
  851. uint8_t addr = LED_pageBuffer[ ch ].i2c_addr;
  852. LED_sendPage(
  853. addr,
  854. (uint16_t*)&LED_pageBuffer[ ch ],
  855. sizeof( LED_Buffer ) / 2,
  856. LED_FrameBufferPage
  857. );
  858. }
  859. // Increment the buffer page
  860. // And reset if necessary
  861. if ( ++LED_FrameBufferPage >= LED_FrameBuffersMax * 2 )
  862. {
  863. LED_FrameBufferPage = 0;
  864. }
  865. }