Kiibohd Controller
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
This repo is archived. You can view files and clone it, but cannot push or open issues/pull-requests.

scan_loop.c 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682
  1. /* Copyright (C) 2014 by Jacob Alexander
  2. *
  3. * Permission is hereby granted, free of charge, to any person obtaining a copy
  4. * of this software and associated documentation files (the "Software"), to deal
  5. * in the Software without restriction, including without limitation the rights
  6. * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  7. * copies of the Software, and to permit persons to whom the Software is
  8. * furnished to do so, subject to the following conditions:
  9. *
  10. * The above copyright notice and this permission notice shall be included in
  11. * all copies or substantial portions of the Software.
  12. *
  13. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  14. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  15. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  16. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  17. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  18. * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  19. * THE SOFTWARE.
  20. */
  21. // ----- Includes -----
  22. // Compiler Includes
  23. #include <Lib/ScanLib.h>
  24. // Project Includes
  25. #include <cli.h>
  26. #include <led.h>
  27. #include <print.h>
  28. #include <matrix_scan.h>
  29. // Local Includes
  30. #include "scan_loop.h"
  31. #include "macro.h"
  32. typedef struct I2C_Buffer {
  33. uint16_t head;
  34. uint16_t tail;
  35. uint8_t sequencePos;
  36. uint16_t size;
  37. uint8_t *buffer;
  38. } I2C_Buffer;
  39. // ----- Function Declarations -----
  40. // CLI Functions
  41. void cliFunc_echo( char* args );
  42. void cliFunc_i2cRecv( char* args );
  43. void cliFunc_i2cSend( char* args );
  44. void cliFunc_ledZero( char* args );
  45. uint8_t I2C_TxBufferPop();
  46. void I2C_BufferPush( uint8_t byte, I2C_Buffer *buffer );
  47. uint16_t I2C_BufferLen( I2C_Buffer *buffer );
  48. uint8_t I2C_Send( uint8_t *data, uint8_t sendLen, uint8_t recvLen );
  49. // ----- Variables -----
  50. // Scan Module command dictionary
  51. CLIDict_Entry( echo, "Example command, echos the arguments." );
  52. CLIDict_Entry( i2cRecv, "Send I2C sequence of bytes and expect a reply of 1 byte on the last sequence. Use |'s to split sequences with a stop." );
  53. CLIDict_Entry( i2cSend, "Send I2C sequence of bytes. Use |'s to split sequences with a stop." );
  54. CLIDict_Entry( ledZero, "Zero out LED register pages (non-configuration)." );
  55. CLIDict_Def( scanCLIDict, "Scan Module Commands" ) = {
  56. CLIDict_Item( echo ),
  57. CLIDict_Item( i2cRecv ),
  58. CLIDict_Item( i2cSend ),
  59. CLIDict_Item( ledZero ),
  60. { 0, 0, 0 } // Null entry for dictionary end
  61. };
  62. // Number of scans since the last USB send
  63. uint16_t Scan_scanCount = 0;
  64. // Before sending the sequence, I2C_TxBuffer_CurLen is assigned and as each byte is sent, it is decremented
  65. // Once I2C_TxBuffer_CurLen reaches zero, a STOP on the I2C bus is sent
  66. #define I2C_TxBufferLength 300
  67. #define I2C_RxBufferLength 8
  68. volatile uint8_t I2C_TxBufferPtr[ I2C_TxBufferLength ];
  69. volatile uint8_t I2C_RxBufferPtr[ I2C_TxBufferLength ];
  70. volatile I2C_Buffer I2C_TxBuffer = { 0, 0, 0, I2C_TxBufferLength, (uint8_t*)I2C_TxBufferPtr };
  71. volatile I2C_Buffer I2C_RxBuffer = { 0, 0, 0, I2C_RxBufferLength, (uint8_t*)I2C_RxBufferPtr };
  72. void I2C_setup()
  73. {
  74. // Enable I2C internal clock
  75. SIM_SCGC4 |= SIM_SCGC4_I2C0; // Bus 0
  76. // External pull-up resistor
  77. PORTB_PCR0 = PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(2);
  78. PORTB_PCR1 = PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(2);
  79. // SCL Frequency Divider
  80. // 400kHz -> 120 (0x85) @ 48 MHz F_BUS
  81. I2C0_F = 0x85;
  82. I2C0_FLT = 4;
  83. I2C0_C1 = I2C_C1_IICEN;
  84. I2C0_C2 = I2C_C2_HDRS; // High drive select
  85. // Enable I2C Interrupt
  86. NVIC_ENABLE_IRQ( IRQ_I2C0 );
  87. }
  88. // ----- Interrupt Functions -----
  89. void i2c0_isr()
  90. {
  91. cli(); // Disable Interrupts
  92. uint8_t status = I2C0_S; // Read I2C Bus status
  93. // Master Mode Transmit
  94. if ( I2C0_C1 & I2C_C1_TX )
  95. {
  96. // Check current use of the I2C bus
  97. // Currently sending data
  98. if ( I2C_TxBuffer.sequencePos > 0 )
  99. {
  100. // Make sure slave sent an ACK
  101. if ( status & I2C_S_RXAK )
  102. {
  103. // NACK Detected, disable interrupt
  104. erro_print("I2C NAK detected...");
  105. I2C0_C1 = I2C_C1_IICEN;
  106. // Abort Tx Buffer
  107. I2C_TxBuffer.head = 0;
  108. I2C_TxBuffer.tail = 0;
  109. I2C_TxBuffer.sequencePos = 0;
  110. }
  111. else
  112. {
  113. // Transmit byte
  114. I2C0_D = I2C_TxBufferPop();
  115. }
  116. }
  117. // Receiving data
  118. else if ( I2C_RxBuffer.sequencePos > 0 )
  119. {
  120. // Master Receive, addr sent
  121. if ( status & I2C_S_ARBL )
  122. {
  123. // Arbitration Lost
  124. erro_print("Arbitration lost...");
  125. // TODO Abort Rx
  126. I2C0_C1 = I2C_C1_IICEN;
  127. I2C0_S = I2C_S_ARBL | I2C_S_IICIF; // Clear ARBL flag and interrupt
  128. }
  129. if ( status & I2C_S_RXAK )
  130. {
  131. // Slave Address NACK Detected, disable interrupt
  132. erro_print("Slave Address I2C NAK detected...");
  133. // TODO Abort Rx
  134. I2C0_C1 = I2C_C1_IICEN;
  135. }
  136. else
  137. {
  138. dbug_print("Attempting to read byte");
  139. I2C0_C1 = I2C_RxBuffer.sequencePos == 1
  140. ? I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TXAK // Single byte read
  141. : I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST; // Multi-byte read
  142. }
  143. }
  144. else
  145. {
  146. /*
  147. dbug_msg("STOP - ");
  148. printHex( I2C_BufferLen( (I2C_Buffer*)&I2C_TxBuffer ) );
  149. print(NL);
  150. */
  151. // Delay around STOP to make sure it actually happens...
  152. delayMicroseconds( 1 );
  153. I2C0_C1 = I2C_C1_IICEN; // Send STOP
  154. delayMicroseconds( 7 );
  155. // If there is another sequence, start sending
  156. if ( I2C_BufferLen( (I2C_Buffer*)&I2C_TxBuffer ) < I2C_TxBuffer.size )
  157. {
  158. // Clear status flags
  159. I2C0_S = I2C_S_IICIF | I2C_S_ARBL;
  160. // Wait...till the master dies
  161. while ( I2C0_S & I2C_S_BUSY );
  162. // Enable I2C interrupt
  163. I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX;
  164. // Transmit byte
  165. I2C0_D = I2C_TxBufferPop();
  166. }
  167. }
  168. }
  169. // Master Mode Receive
  170. else
  171. {
  172. // XXX Do we need to handle 2nd last byte?
  173. //I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TXAK; // No STOP, Rx, NAK on recv
  174. // Last byte
  175. if ( I2C_TxBuffer.sequencePos <= 1 )
  176. {
  177. // Change to Tx mode
  178. I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX;
  179. // Grab last byte
  180. I2C_BufferPush( I2C0_D, (I2C_Buffer*)&I2C_RxBuffer );
  181. delayMicroseconds( 1 ); // Should be enough time before issuing the stop
  182. I2C0_C1 = I2C_C1_IICEN; // Send STOP
  183. }
  184. else
  185. {
  186. // Retrieve data
  187. I2C_BufferPush( I2C0_D, (I2C_Buffer*)&I2C_RxBuffer );
  188. }
  189. }
  190. I2C0_S = I2C_S_IICIF; // Clear interrupt
  191. sei(); // Re-enable Interrupts
  192. }
  193. // ----- Functions -----
  194. void LED_zeroPages( uint8_t startPage, uint8_t numPages, uint8_t pageLen )
  195. {
  196. // Page Setup
  197. uint8_t pageSetup[] = { 0xE8, 0xFD, 0x00 };
  198. // Max length of a page + chip id + reg start
  199. uint8_t fullPage[ 0xB3 + 2 ] = { 0 };
  200. fullPage[0] = 0xE8; // Set chip id, starting reg is already 0x00
  201. // Iterate through given pages, zero'ing out the given register regions
  202. for ( uint8_t page = startPage; page < startPage + numPages; page++ )
  203. {
  204. // Set page
  205. pageSetup[2] = page;
  206. // Setup page
  207. while ( I2C_Send( pageSetup, sizeof( pageSetup ), 0 ) == 0 )
  208. delay(1);
  209. // Zero out page
  210. while ( I2C_Send( fullPage, pageLen + 2, 0 ) == 0 )
  211. delay(1);
  212. }
  213. }
  214. // Setup
  215. inline void LED_setup()
  216. {
  217. I2C_setup();
  218. // Zero out Frame Registers
  219. LED_zeroPages( 0x00, 8, 0xB3 ); // LED Registers
  220. LED_zeroPages( 0x0B, 1, 0x0C ); // Control Registers
  221. // Disable Hardware shutdown of ISSI chip (pull high)
  222. GPIOD_PDDR |= (1<<1);
  223. PORTD_PCR1 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
  224. GPIOD_PSOR |= (1<<1);
  225. }
  226. inline uint8_t I2C_BufferCopy( uint8_t *data, uint8_t sendLen, uint8_t recvLen, I2C_Buffer *buffer )
  227. {
  228. uint8_t reTurn = 0;
  229. // If sendLen is greater than buffer fail right away
  230. if ( sendLen > buffer->size )
  231. return 0;
  232. // Calculate new tail to determine if buffer has enough space
  233. // The first element specifies the expected number of bytes from the slave (+1)
  234. // The second element in the new buffer is the length of the buffer sequence (+1)
  235. uint16_t newTail = buffer->tail + sendLen + 2;
  236. if ( newTail >= buffer->size )
  237. newTail -= buffer->size;
  238. if ( I2C_BufferLen( buffer ) < sendLen + 2 )
  239. return 0;
  240. /*
  241. print("|");
  242. printHex( sendLen + 2 );
  243. print("|");
  244. printHex( *tail );
  245. print("@");
  246. printHex( newTail );
  247. print("@");
  248. */
  249. // If buffer is clean, return 1, otherwise 2
  250. reTurn = buffer->head == buffer->tail ? 1 : 2;
  251. // Add to buffer, already know there is enough room (simplifies adding logic)
  252. uint8_t bufferHeaderPos = 0;
  253. for ( uint16_t c = 0; c < sendLen; c++ )
  254. {
  255. // Add data to buffer
  256. switch ( bufferHeaderPos )
  257. {
  258. case 0:
  259. buffer->buffer[ buffer->tail ] = recvLen;
  260. bufferHeaderPos++;
  261. c--;
  262. break;
  263. case 1:
  264. buffer->buffer[ buffer->tail ] = sendLen;
  265. bufferHeaderPos++;
  266. c--;
  267. break;
  268. default:
  269. buffer->buffer[ buffer->tail ] = data[ c ];
  270. break;
  271. }
  272. // Check for wrap-around case
  273. if ( buffer->tail + 1 >= buffer->size )
  274. {
  275. buffer->tail = 0;
  276. }
  277. // Normal case
  278. else
  279. {
  280. buffer->tail++;
  281. }
  282. }
  283. return reTurn;
  284. }
  285. inline uint16_t I2C_BufferLen( I2C_Buffer *buffer )
  286. {
  287. // Tail >= Head
  288. if ( buffer->tail >= buffer->head )
  289. return buffer->head + buffer->size - buffer->tail;
  290. // Head > Tail
  291. return buffer->head - buffer->tail;
  292. }
  293. void I2C_BufferPush( uint8_t byte, I2C_Buffer *buffer )
  294. {
  295. // Make sure buffer isn't full
  296. if ( buffer->tail + 1 == buffer->head || ( buffer->head > buffer->tail && buffer->tail + 1 - buffer->size == buffer->head ) )
  297. {
  298. warn_msg("I2C_BufferPush failed, buffer full: ");
  299. printHex( byte );
  300. print( NL );
  301. return;
  302. }
  303. // Check for wrap-around case
  304. if ( buffer->tail + 1 >= buffer->size )
  305. {
  306. buffer->tail = 0;
  307. }
  308. // Normal case
  309. else
  310. {
  311. buffer->tail++;
  312. }
  313. // Add byte to buffer
  314. buffer->buffer[ buffer->tail ] = byte;
  315. }
  316. uint8_t I2C_TxBufferPop()
  317. {
  318. // Return 0xFF if no buffer left (do not rely on this)
  319. if ( I2C_BufferLen( (I2C_Buffer*)&I2C_TxBuffer ) >= I2C_TxBuffer.size )
  320. {
  321. erro_msg("No buffer to pop an entry from... ");
  322. printHex( I2C_TxBuffer.head );
  323. print(" ");
  324. printHex( I2C_TxBuffer.tail );
  325. print(" ");
  326. printHex( I2C_TxBuffer.sequencePos );
  327. print(NL);
  328. return 0xFF;
  329. }
  330. // If there is currently no sequence being sent, the first entry in the RingBuffer is the length
  331. if ( I2C_TxBuffer.sequencePos == 0 )
  332. {
  333. I2C_TxBuffer.sequencePos = 0xFF; // So this doesn't become an infinite loop
  334. I2C_RxBuffer.sequencePos = I2C_TxBufferPop();
  335. I2C_TxBuffer.sequencePos = I2C_TxBufferPop();
  336. }
  337. uint8_t data = I2C_TxBuffer.buffer[ I2C_TxBuffer.head ];
  338. // Prune head
  339. I2C_TxBuffer.head++;
  340. // Wrap-around case
  341. if ( I2C_TxBuffer.head >= I2C_TxBuffer.size )
  342. I2C_TxBuffer.head = 0;
  343. // Decrement buffer sequence (until next stop will be sent)
  344. I2C_TxBuffer.sequencePos--;
  345. /*
  346. dbug_msg("Popping: ");
  347. printHex( data );
  348. print(" ");
  349. printHex( I2C_TxBuffer.head );
  350. print(" ");
  351. printHex( I2C_TxBuffer.tail );
  352. print(" ");
  353. printHex( I2C_TxBuffer.sequencePos );
  354. print(NL);
  355. */
  356. return data;
  357. }
  358. uint8_t I2C_Send( uint8_t *data, uint8_t sendLen, uint8_t recvLen )
  359. {
  360. // Check head and tail pointers
  361. // If full, return 0
  362. // If empty, start up I2C Master Tx
  363. // If buffer is non-empty and non-full, just append to the buffer
  364. switch ( I2C_BufferCopy( data, sendLen, recvLen, (I2C_Buffer*)&I2C_TxBuffer ) )
  365. {
  366. // Not enough buffer space...
  367. case 0:
  368. /*
  369. erro_msg("Not enough Tx buffer space... ");
  370. printHex( I2C_TxBuffer.head );
  371. print(":");
  372. printHex( I2C_TxBuffer.tail );
  373. print("+");
  374. printHex( sendLen );
  375. print("|");
  376. printHex( I2C_TxBuffer.size );
  377. print( NL );
  378. */
  379. return 0;
  380. // Empty buffer, initialize I2C
  381. case 1:
  382. // Clear status flags
  383. I2C0_S = I2C_S_IICIF | I2C_S_ARBL;
  384. // Check to see if we already have control of the bus
  385. if ( I2C0_C1 & I2C_C1_MST )
  386. {
  387. // Already the master (ah yeah), send a repeated start
  388. I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_RSTA | I2C_C1_TX;
  389. }
  390. // Otherwise, seize control
  391. else
  392. {
  393. // Wait...till the master dies
  394. while ( I2C0_S & I2C_S_BUSY );
  395. // Now we're the master (ah yisss), get ready to send stuffs
  396. I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX;
  397. }
  398. // Enable I2C interrupt
  399. I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX;
  400. // Depending on what type of transfer, the first byte is configured for R or W
  401. I2C0_D = I2C_TxBufferPop();
  402. return 1;
  403. }
  404. // Dirty buffer, I2C already initialized
  405. return 2;
  406. }
  407. // LED State processing loop
  408. inline uint8_t LED_loop()
  409. {
  410. // I2C Busy
  411. // S & I2C_S_BUSY
  412. //I2C_S_BUSY
  413. }
  414. // Setup
  415. inline void Scan_setup()
  416. {
  417. // Register Scan CLI dictionary
  418. CLI_registerDictionary( scanCLIDict, scanCLIDictName );
  419. // Setup GPIO pins for matrix scanning
  420. //Matrix_setup();
  421. // Reset scan count
  422. Scan_scanCount = 0;
  423. // Setup LED Drivers
  424. LED_setup();
  425. }
  426. // Main Detection Loop
  427. inline uint8_t Scan_loop()
  428. {
  429. //Matrix_scan( Scan_scanCount++ );
  430. //LED_scan();
  431. return 0;
  432. }
  433. // Signal from Macro Module that all keys have been processed (that it knows about)
  434. inline void Scan_finishedWithMacro( uint8_t sentKeys )
  435. {
  436. }
  437. // Signal from Output Module that all keys have been processed (that it knows about)
  438. inline void Scan_finishedWithOutput( uint8_t sentKeys )
  439. {
  440. // Reset scan loop indicator (resets each key debounce state)
  441. // TODO should this occur after USB send or Macro processing?
  442. Scan_scanCount = 0;
  443. }
  444. // ----- CLI Command Functions -----
  445. // XXX Just an example command showing how to parse arguments (more complex than generally needed)
  446. void cliFunc_echo( char* args )
  447. {
  448. char* curArgs;
  449. char* arg1Ptr;
  450. char* arg2Ptr = args;
  451. // Parse args until a \0 is found
  452. while ( 1 )
  453. {
  454. print( NL ); // No \r\n by default after the command is entered
  455. curArgs = arg2Ptr; // Use the previous 2nd arg pointer to separate the next arg from the list
  456. CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
  457. // Stop processing args if no more are found
  458. if ( *arg1Ptr == '\0' )
  459. break;
  460. // Print out the arg
  461. dPrint( arg1Ptr );
  462. }
  463. }
  464. void cliFunc_i2cSend( char* args )
  465. {
  466. char* curArgs;
  467. char* arg1Ptr;
  468. char* arg2Ptr = args;
  469. // Buffer used after interpretting the args, will be sent to I2C functions
  470. // NOTE: Limited to 8 bytes currently (can be increased if necessary
  471. #define i2cSend_BuffLenMax 8
  472. uint8_t buffer[ i2cSend_BuffLenMax ];
  473. uint8_t bufferLen = 0;
  474. // No \r\n by default after the command is entered
  475. print( NL );
  476. info_msg("Sending: ");
  477. // Parse args until a \0 is found
  478. while ( bufferLen < i2cSend_BuffLenMax )
  479. {
  480. curArgs = arg2Ptr; // Use the previous 2nd arg pointer to separate the next arg from the list
  481. CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
  482. // Stop processing args if no more are found
  483. if ( *arg1Ptr == '\0' )
  484. break;
  485. // If | is found, end sequence and start new one
  486. if ( *arg1Ptr == '|' )
  487. {
  488. print("| ");
  489. I2C_Send( buffer, bufferLen, 0 );
  490. bufferLen = 0;
  491. continue;
  492. }
  493. // Interpret the argument
  494. buffer[ bufferLen++ ] = (uint8_t)numToInt( arg1Ptr );
  495. // Print out the arg
  496. dPrint( arg1Ptr );
  497. print(" ");
  498. }
  499. print( NL );
  500. I2C_Send( buffer, bufferLen, 0 );
  501. }
  502. void cliFunc_i2cRecv( char* args )
  503. {
  504. char* curArgs;
  505. char* arg1Ptr;
  506. char* arg2Ptr = args;
  507. // Buffer used after interpretting the args, will be sent to I2C functions
  508. // NOTE: Limited to 8 bytes currently (can be increased if necessary
  509. #define i2cSend_BuffLenMax 8
  510. uint8_t buffer[ i2cSend_BuffLenMax ];
  511. uint8_t bufferLen = 0;
  512. // No \r\n by default after the command is entered
  513. print( NL );
  514. info_msg("Sending: ");
  515. // Parse args until a \0 is found
  516. while ( bufferLen < i2cSend_BuffLenMax )
  517. {
  518. curArgs = arg2Ptr; // Use the previous 2nd arg pointer to separate the next arg from the list
  519. CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
  520. // Stop processing args if no more are found
  521. if ( *arg1Ptr == '\0' )
  522. break;
  523. // If | is found, end sequence and start new one
  524. if ( *arg1Ptr == '|' )
  525. {
  526. print("| ");
  527. I2C_Send( buffer, bufferLen, 0 );
  528. bufferLen = 0;
  529. continue;
  530. }
  531. // Interpret the argument
  532. buffer[ bufferLen++ ] = (uint8_t)numToInt( arg1Ptr );
  533. // Print out the arg
  534. dPrint( arg1Ptr );
  535. print(" ");
  536. }
  537. print( NL );
  538. I2C_Send( buffer, bufferLen, 1 ); // Only 1 byte is ever read at a time with the ISSI chip
  539. }
  540. void cliFunc_ledZero( char* args )
  541. {
  542. print( NL ); // No \r\n by default after the command is entered
  543. LED_zeroPages( 0x00, 8, 0xB3 );
  544. }