Kiibohd Controller
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
此仓库已存档。您可以查看文件和克隆,但不能推送或创建工单/合并请求。

led_scan.c 25KB

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