]> git.donarmstrong.com Git - kiibohd-controller.git/blob - Scan/ISSILed/led_scan.c
ef2400a6e4ef798107c1a71cbb10f0c292749fc7
[kiibohd-controller.git] / Scan / ISSILed / led_scan.c
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
17 // ----- Includes -----
18
19 // Compiler Includes
20 #include <Lib/ScanLib.h>
21
22 // Project Includes
23 #include <cli.h>
24 #include <led.h>
25 #include <print.h>
26
27 // Local Includes
28 #include "led_scan.h"
29
30
31
32 // ----- Defines -----
33
34 #define I2C_TxBufferLength 300
35 #define I2C_RxBufferLength 8
36
37 #define LED_BufferLength 144
38
39
40 // ----- Structs -----
41
42 typedef struct I2C_Buffer {
43         uint16_t  head;
44         uint16_t  tail;
45         uint8_t   sequencePos;
46         uint16_t  size;
47         uint8_t  *buffer;
48 } I2C_Buffer;
49
50 typedef struct LED_Buffer {
51         uint8_t buffer[LED_BufferLength];
52 } LED_Buffer;
53
54
55
56 // ----- Function Declarations -----
57
58 // CLI Functions
59 void cliFunc_i2cRecv( char* args );
60 void cliFunc_i2cSend( char* args );
61 void cliFunc_ledPage( char* args );
62 void cliFunc_ledStart( char* args );
63 void cliFunc_ledTest( char* args );
64 void cliFunc_ledZero( char* args );
65
66 uint8_t I2C_TxBufferPop();
67 void I2C_BufferPush( uint8_t byte, I2C_Buffer *buffer );
68 uint16_t I2C_BufferLen( I2C_Buffer *buffer );
69 uint8_t I2C_Send( uint8_t *data, uint8_t sendLen, uint8_t recvLen );
70
71
72
73 // ----- Variables -----
74
75 // Scan Module command dictionary
76 CLIDict_Entry( i2cRecv,     "Send I2C sequence of bytes and expect a reply of 1 byte on the last sequence." NL "\t\tUse |'s to split sequences with a stop." );
77 CLIDict_Entry( i2cSend,     "Send I2C sequence of bytes. Use |'s to split sequences with a stop." );
78 CLIDict_Entry( ledPage,     "Read the given register page." );
79 CLIDict_Entry( ledStart,    "Disable software shutdown." );
80 CLIDict_Entry( ledTest,     "Test out the led pages." );
81 CLIDict_Entry( ledZero,     "Zero out LED register pages (non-configuration)." );
82
83 CLIDict_Def( ledCLIDict, "ISSI LED Module Commands" ) = {
84         CLIDict_Item( i2cRecv ),
85         CLIDict_Item( i2cSend ),
86         CLIDict_Item( ledPage ),
87         CLIDict_Item( ledStart ),
88         CLIDict_Item( ledTest ),
89         CLIDict_Item( ledZero ),
90         { 0, 0, 0 } // Null entry for dictionary end
91 };
92
93
94
95 // Before sending the sequence, I2C_TxBuffer_CurLen is assigned and as each byte is sent, it is decremented
96 // Once I2C_TxBuffer_CurLen reaches zero, a STOP on the I2C bus is sent
97 volatile uint8_t I2C_TxBufferPtr[ I2C_TxBufferLength ];
98 volatile uint8_t I2C_RxBufferPtr[ I2C_TxBufferLength ];
99
100 volatile I2C_Buffer I2C_TxBuffer = { 0, 0, 0, I2C_TxBufferLength, (uint8_t*)I2C_TxBufferPtr };
101 volatile I2C_Buffer I2C_RxBuffer = { 0, 0, 0, I2C_RxBufferLength, (uint8_t*)I2C_RxBufferPtr };
102
103 LED_Buffer LED_pageBuffer;
104
105 /*
106 // A bit mask determining which LEDs are enabled in the ISSI chip
107 // All channel mask example
108 // 0x00 -> 0x11
109 const uint8_t LED_ledEnableMask[] = {
110 0xE8, // I2C address
111 0x00, // Starting register address
112 0xFF, 0xFF, // C1-1 -> C1-16
113 0xFF, 0xFF, // C2-1 -> C2-16
114 0xFF, 0xFF, // C3-1 -> C3-16
115 0xFF, 0xFF, // C4-1 -> C4-16
116 0xFF, 0xFF, // C5-1 -> C5-16
117 0xFF, 0xFF, // C6-1 -> C6-16
118 0xFF, 0xFF, // C7-1 -> C7-16
119 0xFF, 0xFF, // C8-1 -> C8-16
120 0xFF, 0xFF, // C9-1 -> C9-16
121 };
122 */
123
124 /*
125 // A bit mask determining which LEDs are enabled in the ISSI chip
126 // Infinity ErgoDox full mask
127 // 0x00 -> 0x11
128 const uint8_t LED_ledEnableMask[] = {
129 0xE8, // I2C address
130 0x00, // Starting register address
131 0xFC, 0xFC, // C1-1 -> C1-16
132 0xFB, 0xFB, // C2-1 -> C2-16
133 0xFF, 0xFF, // C3-1 -> C3-16
134 0xFE, 0xFE, // C4-1 -> C4-16
135 0x7F, 0x7F, // C5-1 -> C5-16
136 0xFF, 0xFF, // C6-1 -> C6-16
137 0xCF, 0xCF, // C7-1 -> C7-16
138 0xC7, 0xC7, // C8-1 -> C8-16
139 0x43, 0x43, // C9-1 -> C9-16
140 };
141 */
142 const uint8_t LED_ledEnableMask[] = {
143 0xE8, // I2C address
144 0x00, // Starting register address
145 0x00, 0x00, // C1-1 -> C1-16
146 //0xEC, 0xEC, // C1-1 -> C1-16
147 0x00, 0x00, // C2-1 -> C2-16
148 0x00, 0x00, // C3-1 -> C3-16
149 0x00, 0x00, // C4-1 -> C4-16
150 0x00, 0x00, // C5-1 -> C5-16
151 0x00, 0x00, // C6-1 -> C6-16
152 0x08, 0x08, // C7-1 -> C7-16
153 0x00, 0x00, // C8-1 -> C8-16
154 0x00, 0x00, // C9-1 -> C9-16
155 };
156
157
158 // XXX Pre-fill example of buffers
159 const uint8_t examplePage[] = {
160 0xE8, // I2C address
161 0x24, // Starting register address
162 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C1-1 -> C1-16
163 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C2-1 -> C2-16
164 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C3-1 -> C3-16
165 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C4-1 -> C4-16
166 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C5-1 -> C5-16
167 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C6-1 -> C6-16
168 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C7-1 -> C7-16
169 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C8-1 -> C8-16
170 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // C9-1 -> C9-16
171 };
172
173 /*
174 // XXX Pre-fill example of buffers
175 const uint8_t examplePage[] = {
176 0xE8, // I2C address
177 0x24, // Starting register address
178 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, // C1-1 -> C1-16
179 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1A, 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, // C2-1 -> C2-16
180 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2A, 0x2B, 0x2C, 0x2D, 0x2E, 0x2F, // C3-1 -> C3-16
181 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3A, 0x3B, 0x3C, 0x3D, 0x3E, 0x3F, // C4-1 -> C4-16
182 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, // C5-1 -> C5-16
183 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0x5B, 0x5C, 0x5D, 0x5E, 0x5F, // C6-1 -> C6-16
184 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F, // C7-1 -> C7-16
185 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7A, 0x7B, 0x7C, 0x7D, 0x7E, 0x7F, // C8-1 -> C8-16
186 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, // C9-1 -> C9-16
187 };
188 */
189
190
191
192 // ----- Interrupt Functions -----
193
194 void i2c0_isr()
195 {
196         cli(); // Disable Interrupts
197
198         uint8_t status = I2C0_S; // Read I2C Bus status
199
200         // Master Mode Transmit
201         if ( I2C0_C1 & I2C_C1_TX )
202         {
203                 // Check current use of the I2C bus
204                 // Currently sending data
205                 if ( I2C_TxBuffer.sequencePos > 0 )
206                 {
207                         // Make sure slave sent an ACK
208                         if ( status & I2C_S_RXAK )
209                         {
210                                 // NACK Detected, disable interrupt
211                                 erro_print("I2C NAK detected...");
212                                 I2C0_C1 = I2C_C1_IICEN;
213
214                                 // Abort Tx Buffer
215                                 I2C_TxBuffer.head = 0;
216                                 I2C_TxBuffer.tail = 0;
217                                 I2C_TxBuffer.sequencePos = 0;
218                         }
219                         else
220                         {
221                                 // Transmit byte
222                                 I2C0_D = I2C_TxBufferPop();
223                         }
224                 }
225                 // Receiving data
226                 else if ( I2C_RxBuffer.sequencePos > 0 )
227                 {
228                         // Master Receive, addr sent
229                         if ( status & I2C_S_ARBL )
230                         {
231                                 // Arbitration Lost
232                                 erro_print("Arbitration lost...");
233                                 // TODO Abort Rx
234
235                                 I2C0_C1 = I2C_C1_IICEN;
236                                 I2C0_S = I2C_S_ARBL | I2C_S_IICIF; // Clear ARBL flag and interrupt
237                         }
238                         if ( status & I2C_S_RXAK )
239                         {
240                                 // Slave Address NACK Detected, disable interrupt
241                                 erro_print("Slave Address I2C NAK detected...");
242                                 // TODO Abort Rx
243
244                                 I2C0_C1 = I2C_C1_IICEN;
245                         }
246                         else
247                         {
248                                 dbug_print("Attempting to read byte");
249                                 I2C0_C1 = I2C_RxBuffer.sequencePos == 1
250                                         ? I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TXAK // Single byte read
251                                         : I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST; // Multi-byte read
252                         }
253                 }
254                 else
255                 {
256                         /*
257                         dbug_msg("STOP - ");
258                         printHex( I2C_BufferLen( (I2C_Buffer*)&I2C_TxBuffer ) );
259                         print(NL);
260                         */
261
262                         // Delay around STOP to make sure it actually happens...
263                         delayMicroseconds( 1 );
264                         I2C0_C1 = I2C_C1_IICEN; // Send STOP
265                         delayMicroseconds( 7 );
266
267                         // If there is another sequence, start sending
268                         if ( I2C_BufferLen( (I2C_Buffer*)&I2C_TxBuffer ) < I2C_TxBuffer.size )
269                         {
270                                 // Clear status flags
271                                 I2C0_S = I2C_S_IICIF | I2C_S_ARBL;
272
273                                 // Wait...till the master dies
274                                 while ( I2C0_S & I2C_S_BUSY );
275
276                                 // Enable I2C interrupt
277                                 I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX;
278
279                                 // Transmit byte
280                                 I2C0_D = I2C_TxBufferPop();
281                         }
282                 }
283         }
284         // Master Mode Receive
285         else
286         {
287                 // XXX Do we need to handle 2nd last byte?
288                 //I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TXAK; // No STOP, Rx, NAK on recv
289
290                 // Last byte
291                 if ( I2C_TxBuffer.sequencePos <= 1 )
292                 {
293                         // Change to Tx mode
294                         I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX;
295
296                         // Grab last byte
297                         I2C_BufferPush( I2C0_D, (I2C_Buffer*)&I2C_RxBuffer );
298
299                         delayMicroseconds( 1 ); // Should be enough time before issuing the stop
300                         I2C0_C1 = I2C_C1_IICEN; // Send STOP
301                 }
302                 else
303                 {
304                         // Retrieve data
305                         I2C_BufferPush( I2C0_D, (I2C_Buffer*)&I2C_RxBuffer );
306                 }
307         }
308
309         I2C0_S = I2C_S_IICIF; // Clear interrupt
310
311         sei(); // Re-enable Interrupts
312 }
313
314
315
316 // ----- Functions -----
317
318 inline void I2C_setup()
319 {
320         // Enable I2C internal clock
321         SIM_SCGC4 |= SIM_SCGC4_I2C0; // Bus 0
322
323         // External pull-up resistor
324         PORTB_PCR0 = PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(2);
325         PORTB_PCR1 = PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(2);
326
327         // SCL Frequency Divider
328         // 400kHz -> 120 (0x85) @ 48 MHz F_BUS
329         I2C0_F = 0x85;
330         I2C0_FLT = 4;
331         I2C0_C1 = I2C_C1_IICEN;
332         I2C0_C2 = I2C_C2_HDRS; // High drive select
333
334         // Enable I2C Interrupt
335         NVIC_ENABLE_IRQ( IRQ_I2C0 );
336 }
337
338 void LED_zeroPages( uint8_t startPage, uint8_t numPages, uint8_t startReg, uint8_t endReg )
339 {
340         // Page Setup
341         uint8_t pageSetup[] = { 0xE8, 0xFD, 0x00 };
342
343         // Max length of a page + chip id + reg start
344         uint8_t fullPage[ 0xB4 + 2 ] = { 0 }; // Max size of page
345         fullPage[0] = 0xE8;     // Set chip id
346         fullPage[1] = startReg; // Set start reg
347
348         // Iterate through given pages, zero'ing out the given register regions
349         for ( uint8_t page = startPage; page < startPage + numPages; page++ )
350         {
351                 // Set page
352                 pageSetup[2] = page;
353
354                 // Setup page
355                 while ( I2C_Send( pageSetup, sizeof( pageSetup ), 0 ) == 0 )
356                         delay(1);
357
358                 // Zero out page
359                 while ( I2C_Send( fullPage, endReg - startReg + 2, 0 ) == 0 )
360                         delay(1);
361         }
362 }
363
364 void LED_sendPage( uint8_t *buffer, uint8_t len, uint8_t page )
365 {
366         // Page Setup
367         uint8_t pageSetup[] = { 0xE8, 0xFD, page };
368
369         // Setup page
370         while ( I2C_Send( pageSetup, sizeof( pageSetup ), 0 ) == 0 )
371                 delay(1);
372
373         // Write page to I2C Tx Buffer
374         while ( I2C_Send( buffer, len, 0 ) == 0 )
375                 delay(1);
376
377 }
378
379 void LED_readPage( uint8_t len, uint8_t page )
380 {
381         // Page Setup
382         uint8_t pageSetup[] = { 0xE8, 0xFD, page };
383
384         // Setup page
385         while ( I2C_Send( pageSetup, sizeof( pageSetup ), 0 ) == 0 )
386                 delay(1);
387
388         // Register Setup
389         uint8_t regSetup[] = { 0xE8, 0x00 };
390
391         // Setup starting register
392         while ( I2C_Send( regSetup, sizeof( regSetup ), 0 ) == 0 )
393                 delay(1);
394
395         // Register Read Command
396         uint8_t regReadCmd[] = { 0xE9 };
397
398         // Read each register in the page
399         for ( uint8_t reg = 0; reg < len; reg++ )
400         {
401                 // Request register data
402                 while ( I2C_Send( regReadCmd, sizeof( regReadCmd ), 0 ) == 0 )
403                         delay(1);
404         }
405 }
406
407 void LED_writeReg( uint8_t reg, uint8_t val, uint8_t page )
408 {
409         // Page Setup
410         uint8_t pageSetup[] = { 0xE8, 0xFD, page };
411
412         // Reg Write Setup
413         uint8_t writeData[] = { 0xE8, reg, val };
414
415         // Setup page
416         while ( I2C_Send( pageSetup, sizeof( pageSetup ), 0 ) == 0 )
417                 delay(1);
418
419         while ( I2C_Send( writeData, sizeof( writeData ), 0 ) == 0 )
420                 delay(1);
421 }
422
423 // Setup
424 inline void LED_setup()
425 {
426         // Register Scan CLI dictionary
427         CLI_registerDictionary( ledCLIDict, ledCLIDictName );
428
429         // Initialize I2C
430         I2C_setup();
431
432         /* TODO Make work
433         // Zero out Frame Registers
434         // This needs to be done before disabling the hardware shutdown (or the leds will do undefined things)
435         LED_zeroPages( 0x0B, 1, 0x00, 0x0C ); // Control Registers
436
437         // Disable Hardware shutdown of ISSI chip (pull high)
438         GPIOD_PDDR |= (1<<1);
439         PORTD_PCR1 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
440         GPIOD_PSOR |= (1<<1);
441
442         // Clear LED Pages
443         LED_zeroPages( 0x00, 8, 0x00, 0xB4 ); // LED Registers
444
445         // Enable LEDs based upon mask
446         LED_sendPage( (uint8_t*)LED_ledEnableMask, sizeof( LED_ledEnableMask ), 0 );
447
448         // Disable Software shutdown of ISSI chip
449         LED_writeReg( 0x0A, 0x01, 0x0B );
450         */
451 }
452
453
454 inline uint8_t I2C_BufferCopy( uint8_t *data, uint8_t sendLen, uint8_t recvLen, I2C_Buffer *buffer )
455 {
456         uint8_t reTurn = 0;
457
458         // If sendLen is greater than buffer fail right away
459         if ( sendLen > buffer->size )
460                 return 0;
461
462         // Calculate new tail to determine if buffer has enough space
463         // The first element specifies the expected number of bytes from the slave (+1)
464         // The second element in the new buffer is the length of the buffer sequence (+1)
465         uint16_t newTail = buffer->tail + sendLen + 2;
466         if ( newTail >= buffer->size )
467                 newTail -= buffer->size;
468
469         if ( I2C_BufferLen( buffer ) < sendLen + 2 )
470                 return 0;
471
472 /*
473         print("|");
474         printHex( sendLen + 2 );
475         print("|");
476         printHex( *tail );
477         print("@");
478         printHex( newTail );
479         print("@");
480 */
481
482         // If buffer is clean, return 1, otherwise 2
483         reTurn = buffer->head == buffer->tail ? 1 : 2;
484
485         // Add to buffer, already know there is enough room (simplifies adding logic)
486         uint8_t bufferHeaderPos = 0;
487         for ( uint16_t c = 0; c < sendLen; c++ )
488         {
489                 // Add data to buffer
490                 switch ( bufferHeaderPos )
491                 {
492                 case 0:
493                         buffer->buffer[ buffer->tail ] = recvLen;
494                         bufferHeaderPos++;
495                         c--;
496                         break;
497
498                 case 1:
499                         buffer->buffer[ buffer->tail ] = sendLen;
500                         bufferHeaderPos++;
501                         c--;
502                         break;
503
504                 default:
505                         buffer->buffer[ buffer->tail ] = data[ c ];
506                         break;
507                 }
508
509                 // Check for wrap-around case
510                 if ( buffer->tail + 1 >= buffer->size )
511                 {
512                         buffer->tail = 0;
513                 }
514                 // Normal case
515                 else
516                 {
517                         buffer->tail++;
518                 }
519         }
520
521         return reTurn;
522 }
523
524
525 inline uint16_t I2C_BufferLen( I2C_Buffer *buffer )
526 {
527         // Tail >= Head
528         if ( buffer->tail >= buffer->head )
529                 return buffer->head + buffer->size - buffer->tail;
530
531         // Head > Tail
532         return buffer->head - buffer->tail;
533 }
534
535
536 void I2C_BufferPush( uint8_t byte, I2C_Buffer *buffer )
537 {
538         dbug_msg("DATA: ");
539         printHex( byte );
540
541         // Make sure buffer isn't full
542         if ( buffer->tail + 1 == buffer->head || ( buffer->head > buffer->tail && buffer->tail + 1 - buffer->size == buffer->head ) )
543         {
544                 warn_msg("I2C_BufferPush failed, buffer full: ");
545                 printHex( byte );
546                 print( NL );
547                 return;
548         }
549
550         // Check for wrap-around case
551         if ( buffer->tail + 1 >= buffer->size )
552         {
553                 buffer->tail = 0;
554         }
555         // Normal case
556         else
557         {
558                 buffer->tail++;
559         }
560
561         // Add byte to buffer
562         buffer->buffer[ buffer->tail ] = byte;
563 }
564
565
566 uint8_t I2C_TxBufferPop()
567 {
568         // Return 0xFF if no buffer left (do not rely on this)
569         if ( I2C_BufferLen( (I2C_Buffer*)&I2C_TxBuffer ) >= I2C_TxBuffer.size )
570         {
571                 erro_msg("No buffer to pop an entry from... ");
572                 printHex( I2C_TxBuffer.head );
573                 print(" ");
574                 printHex( I2C_TxBuffer.tail );
575                 print(" ");
576                 printHex( I2C_TxBuffer.sequencePos );
577                 print(NL);
578                 return 0xFF;
579         }
580
581         // If there is currently no sequence being sent, the first entry in the RingBuffer is the length
582         if ( I2C_TxBuffer.sequencePos == 0 )
583         {
584                 I2C_TxBuffer.sequencePos = 0xFF; // So this doesn't become an infinite loop
585                 I2C_RxBuffer.sequencePos = I2C_TxBufferPop();
586                 I2C_TxBuffer.sequencePos = I2C_TxBufferPop();
587         }
588
589         uint8_t data = I2C_TxBuffer.buffer[ I2C_TxBuffer.head ];
590
591         // Prune head
592         I2C_TxBuffer.head++;
593
594         // Wrap-around case
595         if ( I2C_TxBuffer.head >= I2C_TxBuffer.size )
596                 I2C_TxBuffer.head = 0;
597
598         // Decrement buffer sequence (until next stop will be sent)
599         I2C_TxBuffer.sequencePos--;
600
601         /*
602         dbug_msg("Popping: ");
603         printHex( data );
604         print(" ");
605         printHex( I2C_TxBuffer.head );
606         print(" ");
607         printHex( I2C_TxBuffer.tail );
608         print(" ");
609         printHex( I2C_TxBuffer.sequencePos );
610         print(NL);
611         */
612         return data;
613 }
614
615
616 uint8_t I2C_Send( uint8_t *data, uint8_t sendLen, uint8_t recvLen )
617 {
618         // Check head and tail pointers
619         // If full, return 0
620         // If empty, start up I2C Master Tx
621         // If buffer is non-empty and non-full, just append to the buffer
622         switch ( I2C_BufferCopy( data, sendLen, recvLen, (I2C_Buffer*)&I2C_TxBuffer ) )
623         {
624         // Not enough buffer space...
625         case 0:
626                 /*
627                 erro_msg("Not enough Tx buffer space... ");
628                 printHex( I2C_TxBuffer.head );
629                 print(":");
630                 printHex( I2C_TxBuffer.tail );
631                 print("+");
632                 printHex( sendLen );
633                 print("|");
634                 printHex( I2C_TxBuffer.size );
635                 print( NL );
636                 */
637                 return 0;
638
639         // Empty buffer, initialize I2C
640         case 1:
641                 // Clear status flags
642                 I2C0_S = I2C_S_IICIF | I2C_S_ARBL;
643
644                 // Check to see if we already have control of the bus
645                 if ( I2C0_C1 & I2C_C1_MST )
646                 {
647                         // Already the master (ah yeah), send a repeated start
648                         I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_RSTA | I2C_C1_TX;
649                 }
650                 // Otherwise, seize control
651                 else
652                 {
653                         // Wait...till the master dies
654                         while ( I2C0_S & I2C_S_BUSY );
655
656                         // Now we're the master (ah yisss), get ready to send stuffs
657                         I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX;
658                 }
659
660                 // Enable I2C interrupt
661                 I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX;
662
663                 // Depending on what type of transfer, the first byte is configured for R or W
664                 I2C0_D = I2C_TxBufferPop();
665
666                 return 1;
667         }
668
669         // Dirty buffer, I2C already initialized
670         return 2;
671 }
672
673
674
675 // LED State processing loop
676 inline uint8_t LED_scan()
677 {
678
679         // I2C Busy
680         // S & I2C_S_BUSY
681         //I2C_S_BUSY
682
683         return 0;
684 }
685
686
687
688 // ----- CLI Command Functions -----
689
690 void cliFunc_i2cSend( char* args )
691 {
692         char* curArgs;
693         char* arg1Ptr;
694         char* arg2Ptr = args;
695
696         // Buffer used after interpretting the args, will be sent to I2C functions
697         // NOTE: Limited to 8 bytes currently (can be increased if necessary
698         #define i2cSend_BuffLenMax 8
699         uint8_t buffer[ i2cSend_BuffLenMax ];
700         uint8_t bufferLen = 0;
701
702         // No \r\n by default after the command is entered
703         print( NL );
704         info_msg("Sending: ");
705
706         // Parse args until a \0 is found
707         while ( bufferLen < i2cSend_BuffLenMax )
708         {
709                 curArgs = arg2Ptr; // Use the previous 2nd arg pointer to separate the next arg from the list
710                 CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
711
712                 // Stop processing args if no more are found
713                 if ( *arg1Ptr == '\0' )
714                         break;
715
716                 // If | is found, end sequence and start new one
717                 if ( *arg1Ptr == '|' )
718                 {
719                         print("| ");
720                         I2C_Send( buffer, bufferLen, 0 );
721                         bufferLen = 0;
722                         continue;
723                 }
724
725                 // Interpret the argument
726                 buffer[ bufferLen++ ] = (uint8_t)numToInt( arg1Ptr );
727
728                 // Print out the arg
729                 dPrint( arg1Ptr );
730                 print(" ");
731         }
732
733         print( NL );
734
735         I2C_Send( buffer, bufferLen, 0 );
736 }
737
738 void cliFunc_i2cRecv( char* args )
739 {
740         char* curArgs;
741         char* arg1Ptr;
742         char* arg2Ptr = args;
743
744         // Buffer used after interpretting the args, will be sent to I2C functions
745         // NOTE: Limited to 8 bytes currently (can be increased if necessary
746         #define i2cSend_BuffLenMax 8
747         uint8_t buffer[ i2cSend_BuffLenMax ];
748         uint8_t bufferLen = 0;
749
750         // No \r\n by default after the command is entered
751         print( NL );
752         info_msg("Sending: ");
753
754         // Parse args until a \0 is found
755         while ( bufferLen < i2cSend_BuffLenMax )
756         {
757                 curArgs = arg2Ptr; // Use the previous 2nd arg pointer to separate the next arg from the list
758                 CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
759
760                 // Stop processing args if no more are found
761                 if ( *arg1Ptr == '\0' )
762                         break;
763
764                 // If | is found, end sequence and start new one
765                 if ( *arg1Ptr == '|' )
766                 {
767                         print("| ");
768                         I2C_Send( buffer, bufferLen, 0 );
769                         bufferLen = 0;
770                         continue;
771                 }
772
773                 // Interpret the argument
774                 buffer[ bufferLen++ ] = (uint8_t)numToInt( arg1Ptr );
775
776                 // Print out the arg
777                 dPrint( arg1Ptr );
778                 print(" ");
779         }
780
781         print( NL );
782
783         I2C_Send( buffer, bufferLen, 1 ); // Only 1 byte is ever read at a time with the ISSI chip
784 }
785
786 void cliFunc_ledPage( char* args )
787 {
788         // Parse number from argument
789         //  NOTE: Only first argument is used
790         char* arg1Ptr;
791         char* arg2Ptr;
792         CLI_argumentIsolation( args, &arg1Ptr, &arg2Ptr );
793
794         // Default to 0 if no argument is given
795         uint8_t page = 0;
796
797         if ( arg1Ptr[0] != '\0' )
798         {
799                  page = (uint8_t)numToInt( arg1Ptr );
800         }
801
802         // No \r\n by default after the command is entered
803         print( NL );
804
805         LED_readPage( 0xB4, page );
806 }
807
808 void cliFunc_ledStart( char* args )
809 {
810         print( NL ); // No \r\n by default after the command is entered
811         LED_zeroPages( 0x0B, 1, 0x00, 0x0C ); // Control Registers
812         //LED_zeroPages( 0x00, 8, 0x00, 0xB4 ); // LED Registers
813         LED_writeReg( 0x0A, 0x01, 0x0B );
814         LED_sendPage( (uint8_t*)LED_ledEnableMask, sizeof( LED_ledEnableMask ), 0 );
815
816 }
817
818 void cliFunc_ledTest( char* args )
819 {
820         print( NL ); // No \r\n by default after the command is entered
821         LED_sendPage( (uint8_t*)examplePage, sizeof( examplePage ), 0 );
822 }
823
824 void cliFunc_ledZero( char* args )
825 {
826         print( NL ); // No \r\n by default after the command is entered
827         LED_zeroPages( 0x00, 8, 0x24, 0xB4 ); // Only PWMs
828 }
829