]> git.donarmstrong.com Git - kiibohd-controller.git/blob - Scan/MD2/scan_loop.c
Merge branch 'master' of github.com:kiibohd/controller
[kiibohd-controller.git] / Scan / MD2 / scan_loop.c
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
22 // ----- Includes -----
23
24 // Compiler Includes
25 #include <Lib/ScanLib.h>
26
27 // Project Includes
28 #include <cli.h>
29 #include <led.h>
30 #include <print.h>
31 #include <matrix_scan.h>
32
33 // Local Includes
34 #include "scan_loop.h"
35 #include "macro.h"
36
37
38
39
40 typedef struct I2C_Buffer {
41         uint16_t  head;
42         uint16_t  tail;
43         uint8_t   sequencePos;
44         uint16_t  size;
45         uint8_t  *buffer;
46 } I2C_Buffer;
47
48 // ----- Function Declarations -----
49
50 // CLI Functions
51 void cliFunc_echo( char* args );
52 void cliFunc_i2cRecv( char* args );
53 void cliFunc_i2cSend( char* args );
54 void cliFunc_ledZero( char* args );
55
56 uint8_t I2C_TxBufferPop();
57 void I2C_BufferPush( uint8_t byte, I2C_Buffer *buffer );
58 uint16_t I2C_BufferLen( I2C_Buffer *buffer );
59 uint8_t I2C_Send( uint8_t *data, uint8_t sendLen, uint8_t recvLen );
60
61
62
63 // ----- Variables -----
64
65 // Scan Module command dictionary
66 CLIDict_Entry( echo,        "Example command, echos the arguments." );
67 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." );
68 CLIDict_Entry( i2cSend,     "Send I2C sequence of bytes. Use |'s to split sequences with a stop." );
69 CLIDict_Entry( ledZero,     "Zero out LED register pages (non-configuration)." );
70
71 CLIDict_Def( scanCLIDict, "Scan Module Commands" ) = {
72         CLIDict_Item( echo ),
73         CLIDict_Item( i2cRecv ),
74         CLIDict_Item( i2cSend ),
75         CLIDict_Item( ledZero ),
76         { 0, 0, 0 } // Null entry for dictionary end
77 };
78
79 // Number of scans since the last USB send
80 uint16_t Scan_scanCount = 0;
81
82
83
84 // Before sending the sequence, I2C_TxBuffer_CurLen is assigned and as each byte is sent, it is decremented
85 // Once I2C_TxBuffer_CurLen reaches zero, a STOP on the I2C bus is sent
86 #define I2C_TxBufferLength 300
87 #define I2C_RxBufferLength 8
88 volatile uint8_t I2C_TxBufferPtr[ I2C_TxBufferLength ];
89 volatile uint8_t I2C_RxBufferPtr[ I2C_TxBufferLength ];
90
91 volatile I2C_Buffer I2C_TxBuffer = { 0, 0, 0, I2C_TxBufferLength, (uint8_t*)I2C_TxBufferPtr };
92 volatile I2C_Buffer I2C_RxBuffer = { 0, 0, 0, I2C_RxBufferLength, (uint8_t*)I2C_RxBufferPtr };
93
94 void I2C_setup()
95 {
96         // Enable I2C internal clock
97         SIM_SCGC4 |= SIM_SCGC4_I2C0; // Bus 0
98
99         // External pull-up resistor
100         PORTB_PCR0 = PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(2);
101         PORTB_PCR1 = PORT_PCR_ODE | PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(2);
102
103         // SCL Frequency Divider
104         // 400kHz -> 120 (0x85) @ 48 MHz F_BUS
105         I2C0_F = 0x85;
106         I2C0_FLT = 4;
107         I2C0_C1 = I2C_C1_IICEN;
108         I2C0_C2 = I2C_C2_HDRS; // High drive select
109
110         // Enable I2C Interrupt
111         NVIC_ENABLE_IRQ( IRQ_I2C0 );
112 }
113
114
115
116 // ----- Interrupt Functions -----
117
118 void i2c0_isr()
119 {
120         cli(); // Disable Interrupts
121
122         uint8_t status = I2C0_S; // Read I2C Bus status
123
124         // Master Mode Transmit
125         if ( I2C0_C1 & I2C_C1_TX )
126         {
127                 // Check current use of the I2C bus
128                 // Currently sending data
129                 if ( I2C_TxBuffer.sequencePos > 0 )
130                 {
131                         // Make sure slave sent an ACK
132                         if ( status & I2C_S_RXAK )
133                         {
134                                 // NACK Detected, disable interrupt
135                                 erro_print("I2C NAK detected...");
136                                 I2C0_C1 = I2C_C1_IICEN;
137
138                                 // Abort Tx Buffer
139                                 I2C_TxBuffer.head = 0;
140                                 I2C_TxBuffer.tail = 0;
141                                 I2C_TxBuffer.sequencePos = 0;
142                         }
143                         else
144                         {
145                                 // Transmit byte
146                                 I2C0_D = I2C_TxBufferPop();
147                         }
148                 }
149                 // Receiving data
150                 else if ( I2C_RxBuffer.sequencePos > 0 )
151                 {
152                         // Master Receive, addr sent
153                         if ( status & I2C_S_ARBL )
154                         {
155                                 // Arbitration Lost
156                                 erro_print("Arbitration lost...");
157                                 // TODO Abort Rx
158
159                                 I2C0_C1 = I2C_C1_IICEN;
160                                 I2C0_S = I2C_S_ARBL | I2C_S_IICIF; // Clear ARBL flag and interrupt
161                         }
162                         if ( status & I2C_S_RXAK )
163                         {
164                                 // Slave Address NACK Detected, disable interrupt
165                                 erro_print("Slave Address I2C NAK detected...");
166                                 // TODO Abort Rx
167
168                                 I2C0_C1 = I2C_C1_IICEN;
169                         }
170                         else
171                         {
172                                 dbug_print("Attempting to read byte");
173                                 I2C0_C1 = I2C_RxBuffer.sequencePos == 1
174                                         ? I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TXAK // Single byte read
175                                         : I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST; // Multi-byte read
176                         }
177                 }
178                 else
179                 {
180                         /*
181                         dbug_msg("STOP - ");
182                         printHex( I2C_BufferLen( (I2C_Buffer*)&I2C_TxBuffer ) );
183                         print(NL);
184                         */
185
186                         // Delay around STOP to make sure it actually happens...
187                         delayMicroseconds( 1 );
188                         I2C0_C1 = I2C_C1_IICEN; // Send STOP
189                         delayMicroseconds( 7 );
190
191                         // If there is another sequence, start sending
192                         if ( I2C_BufferLen( (I2C_Buffer*)&I2C_TxBuffer ) < I2C_TxBuffer.size )
193                         {
194                                 // Clear status flags
195                                 I2C0_S = I2C_S_IICIF | I2C_S_ARBL;
196
197                                 // Wait...till the master dies
198                                 while ( I2C0_S & I2C_S_BUSY );
199
200                                 // Enable I2C interrupt
201                                 I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX;
202
203                                 // Transmit byte
204                                 I2C0_D = I2C_TxBufferPop();
205                         }
206                 }
207         }
208         // Master Mode Receive
209         else
210         {
211                 // XXX Do we need to handle 2nd last byte?
212                 //I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TXAK; // No STOP, Rx, NAK on recv
213
214                 // Last byte
215                 if ( I2C_TxBuffer.sequencePos <= 1 )
216                 {
217                         // Change to Tx mode
218                         I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX;
219
220                         // Grab last byte
221                         I2C_BufferPush( I2C0_D, (I2C_Buffer*)&I2C_RxBuffer );
222
223                         delayMicroseconds( 1 ); // Should be enough time before issuing the stop
224                         I2C0_C1 = I2C_C1_IICEN; // Send STOP
225                 }
226                 else
227                 {
228                         // Retrieve data
229                         I2C_BufferPush( I2C0_D, (I2C_Buffer*)&I2C_RxBuffer );
230                 }
231         }
232
233         I2C0_S = I2C_S_IICIF; // Clear interrupt
234
235         sei(); // Re-enable Interrupts
236 }
237
238
239
240 // ----- Functions -----
241
242 void LED_zeroPages( uint8_t startPage, uint8_t numPages, uint8_t pageLen )
243 {
244         // Page Setup
245         uint8_t pageSetup[] = { 0xE8, 0xFD, 0x00 };
246
247         // Max length of a page + chip id + reg start
248         uint8_t fullPage[ 0xB3 + 2 ] = { 0 };
249         fullPage[0] = 0xE8; // Set chip id, starting reg is already 0x00
250
251         // Iterate through given pages, zero'ing out the given register regions
252         for ( uint8_t page = startPage; page < startPage + numPages; page++ )
253         {
254                 // Set page
255                 pageSetup[2] = page;
256
257                 // Setup page
258                 while ( I2C_Send( pageSetup, sizeof( pageSetup ), 0 ) == 0 )
259                         delay(1);
260
261                 // Zero out page
262                 while ( I2C_Send( fullPage, pageLen + 2, 0 ) == 0 )
263                         delay(1);
264         }
265 }
266
267
268 // Setup
269 inline void LED_setup()
270 {
271         I2C_setup();
272
273         // Zero out Frame Registers
274         LED_zeroPages( 0x00, 8, 0xB3 ); // LED Registers
275         LED_zeroPages( 0x0B, 1, 0x0C ); // Control Registers
276
277         // Disable Hardware shutdown of ISSI chip (pull high)
278         GPIOD_PDDR |= (1<<1);
279         PORTD_PCR1 = PORT_PCR_SRE | PORT_PCR_DSE | PORT_PCR_MUX(1);
280         GPIOD_PSOR |= (1<<1);
281 }
282
283
284 inline uint8_t I2C_BufferCopy( uint8_t *data, uint8_t sendLen, uint8_t recvLen, I2C_Buffer *buffer )
285 {
286         uint8_t reTurn = 0;
287
288         // If sendLen is greater than buffer fail right away
289         if ( sendLen > buffer->size )
290                 return 0;
291
292         // Calculate new tail to determine if buffer has enough space
293         // The first element specifies the expected number of bytes from the slave (+1)
294         // The second element in the new buffer is the length of the buffer sequence (+1)
295         uint16_t newTail = buffer->tail + sendLen + 2;
296         if ( newTail >= buffer->size )
297                 newTail -= buffer->size;
298
299         if ( I2C_BufferLen( buffer ) < sendLen + 2 )
300                 return 0;
301
302 /*
303         print("|");
304         printHex( sendLen + 2 );
305         print("|");
306         printHex( *tail );
307         print("@");
308         printHex( newTail );
309         print("@");
310 */
311
312         // If buffer is clean, return 1, otherwise 2
313         reTurn = buffer->head == buffer->tail ? 1 : 2;
314
315         // Add to buffer, already know there is enough room (simplifies adding logic)
316         uint8_t bufferHeaderPos = 0;
317         for ( uint16_t c = 0; c < sendLen; c++ )
318         {
319                 // Add data to buffer
320                 switch ( bufferHeaderPos )
321                 {
322                 case 0:
323                         buffer->buffer[ buffer->tail ] = recvLen;
324                         bufferHeaderPos++;
325                         c--;
326                         break;
327
328                 case 1:
329                         buffer->buffer[ buffer->tail ] = sendLen;
330                         bufferHeaderPos++;
331                         c--;
332                         break;
333
334                 default:
335                         buffer->buffer[ buffer->tail ] = data[ c ];
336                         break;
337                 }
338
339                 // Check for wrap-around case
340                 if ( buffer->tail + 1 >= buffer->size )
341                 {
342                         buffer->tail = 0;
343                 }
344                 // Normal case
345                 else
346                 {
347                         buffer->tail++;
348                 }
349         }
350
351         return reTurn;
352 }
353
354
355 inline uint16_t I2C_BufferLen( I2C_Buffer *buffer )
356 {
357         // Tail >= Head
358         if ( buffer->tail >= buffer->head )
359                 return buffer->head + buffer->size - buffer->tail;
360
361         // Head > Tail
362         return buffer->head - buffer->tail;
363 }
364
365
366 void I2C_BufferPush( uint8_t byte, I2C_Buffer *buffer )
367 {
368         // Make sure buffer isn't full
369         if ( buffer->tail + 1 == buffer->head || ( buffer->head > buffer->tail && buffer->tail + 1 - buffer->size == buffer->head ) )
370         {
371                 warn_msg("I2C_BufferPush failed, buffer full: ");
372                 printHex( byte );
373                 print( NL );
374                 return;
375         }
376
377         // Check for wrap-around case
378         if ( buffer->tail + 1 >= buffer->size )
379         {
380                 buffer->tail = 0;
381         }
382         // Normal case
383         else
384         {
385                 buffer->tail++;
386         }
387
388         // Add byte to buffer
389         buffer->buffer[ buffer->tail ] = byte;
390 }
391
392
393 uint8_t I2C_TxBufferPop()
394 {
395         // Return 0xFF if no buffer left (do not rely on this)
396         if ( I2C_BufferLen( (I2C_Buffer*)&I2C_TxBuffer ) >= I2C_TxBuffer.size )
397         {
398                 erro_msg("No buffer to pop an entry from... ");
399                 printHex( I2C_TxBuffer.head );
400                 print(" ");
401                 printHex( I2C_TxBuffer.tail );
402                 print(" ");
403                 printHex( I2C_TxBuffer.sequencePos );
404                 print(NL);
405                 return 0xFF;
406         }
407
408         // If there is currently no sequence being sent, the first entry in the RingBuffer is the length
409         if ( I2C_TxBuffer.sequencePos == 0 )
410         {
411                 I2C_TxBuffer.sequencePos = 0xFF; // So this doesn't become an infinite loop
412                 I2C_RxBuffer.sequencePos = I2C_TxBufferPop();
413                 I2C_TxBuffer.sequencePos = I2C_TxBufferPop();
414         }
415
416         uint8_t data = I2C_TxBuffer.buffer[ I2C_TxBuffer.head ];
417
418         // Prune head
419         I2C_TxBuffer.head++;
420
421         // Wrap-around case
422         if ( I2C_TxBuffer.head >= I2C_TxBuffer.size )
423                 I2C_TxBuffer.head = 0;
424
425         // Decrement buffer sequence (until next stop will be sent)
426         I2C_TxBuffer.sequencePos--;
427
428         /*
429         dbug_msg("Popping: ");
430         printHex( data );
431         print(" ");
432         printHex( I2C_TxBuffer.head );
433         print(" ");
434         printHex( I2C_TxBuffer.tail );
435         print(" ");
436         printHex( I2C_TxBuffer.sequencePos );
437         print(NL);
438         */
439         return data;
440 }
441
442
443 uint8_t I2C_Send( uint8_t *data, uint8_t sendLen, uint8_t recvLen )
444 {
445         // Check head and tail pointers
446         // If full, return 0
447         // If empty, start up I2C Master Tx
448         // If buffer is non-empty and non-full, just append to the buffer
449         switch ( I2C_BufferCopy( data, sendLen, recvLen, (I2C_Buffer*)&I2C_TxBuffer ) )
450         {
451         // Not enough buffer space...
452         case 0:
453                 /*
454                 erro_msg("Not enough Tx buffer space... ");
455                 printHex( I2C_TxBuffer.head );
456                 print(":");
457                 printHex( I2C_TxBuffer.tail );
458                 print("+");
459                 printHex( sendLen );
460                 print("|");
461                 printHex( I2C_TxBuffer.size );
462                 print( NL );
463                 */
464                 return 0;
465
466         // Empty buffer, initialize I2C
467         case 1:
468                 // Clear status flags
469                 I2C0_S = I2C_S_IICIF | I2C_S_ARBL;
470
471                 // Check to see if we already have control of the bus
472                 if ( I2C0_C1 & I2C_C1_MST )
473                 {
474                         // Already the master (ah yeah), send a repeated start
475                         I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_RSTA | I2C_C1_TX;
476                 }
477                 // Otherwise, seize control
478                 else
479                 {
480                         // Wait...till the master dies
481                         while ( I2C0_S & I2C_S_BUSY );
482
483                         // Now we're the master (ah yisss), get ready to send stuffs
484                         I2C0_C1 = I2C_C1_IICEN | I2C_C1_MST | I2C_C1_TX;
485                 }
486
487                 // Enable I2C interrupt
488                 I2C0_C1 = I2C_C1_IICEN | I2C_C1_IICIE | I2C_C1_MST | I2C_C1_TX;
489
490                 // Depending on what type of transfer, the first byte is configured for R or W
491                 I2C0_D = I2C_TxBufferPop();
492
493                 return 1;
494         }
495
496         // Dirty buffer, I2C already initialized
497         return 2;
498 }
499
500
501
502 // LED State processing loop
503 inline uint8_t LED_loop()
504 {
505
506         // I2C Busy
507         // S & I2C_S_BUSY
508         //I2C_S_BUSY
509 }
510
511
512
513 // Setup
514 inline void Scan_setup()
515 {
516         // Register Scan CLI dictionary
517         CLI_registerDictionary( scanCLIDict, scanCLIDictName );
518
519         // Setup GPIO pins for matrix scanning
520         //Matrix_setup();
521
522         // Reset scan count
523         Scan_scanCount = 0;
524
525         // Setup LED Drivers
526         LED_setup();
527 }
528
529
530 // Main Detection Loop
531 inline uint8_t Scan_loop()
532 {
533         //Matrix_scan( Scan_scanCount++ );
534         //LED_scan();
535
536         return 0;
537 }
538
539
540 // Signal from Macro Module that all keys have been processed (that it knows about)
541 inline void Scan_finishedWithMacro( uint8_t sentKeys )
542 {
543 }
544
545
546 // Signal from Output Module that all keys have been processed (that it knows about)
547 inline void Scan_finishedWithOutput( uint8_t sentKeys )
548 {
549         // Reset scan loop indicator (resets each key debounce state)
550         // TODO should this occur after USB send or Macro processing?
551         Scan_scanCount = 0;
552 }
553
554
555 // ----- CLI Command Functions -----
556
557 // XXX Just an example command showing how to parse arguments (more complex than generally needed)
558 void cliFunc_echo( char* args )
559 {
560         char* curArgs;
561         char* arg1Ptr;
562         char* arg2Ptr = args;
563
564         // Parse args until a \0 is found
565         while ( 1 )
566         {
567                 print( NL ); // No \r\n by default after the command is entered
568
569                 curArgs = arg2Ptr; // Use the previous 2nd arg pointer to separate the next arg from the list
570                 CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
571
572                 // Stop processing args if no more are found
573                 if ( *arg1Ptr == '\0' )
574                         break;
575
576                 // Print out the arg
577                 dPrint( arg1Ptr );
578         }
579 }
580
581 void cliFunc_i2cSend( char* args )
582 {
583         char* curArgs;
584         char* arg1Ptr;
585         char* arg2Ptr = args;
586
587         // Buffer used after interpretting the args, will be sent to I2C functions
588         // NOTE: Limited to 8 bytes currently (can be increased if necessary
589         #define i2cSend_BuffLenMax 8
590         uint8_t buffer[ i2cSend_BuffLenMax ];
591         uint8_t bufferLen = 0;
592
593         // No \r\n by default after the command is entered
594         print( NL );
595         info_msg("Sending: ");
596
597         // Parse args until a \0 is found
598         while ( bufferLen < i2cSend_BuffLenMax )
599         {
600                 curArgs = arg2Ptr; // Use the previous 2nd arg pointer to separate the next arg from the list
601                 CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
602
603                 // Stop processing args if no more are found
604                 if ( *arg1Ptr == '\0' )
605                         break;
606
607                 // If | is found, end sequence and start new one
608                 if ( *arg1Ptr == '|' )
609                 {
610                         print("| ");
611                         I2C_Send( buffer, bufferLen, 0 );
612                         bufferLen = 0;
613                         continue;
614                 }
615
616                 // Interpret the argument
617                 buffer[ bufferLen++ ] = (uint8_t)numToInt( arg1Ptr );
618
619                 // Print out the arg
620                 dPrint( arg1Ptr );
621                 print(" ");
622         }
623
624         print( NL );
625
626         I2C_Send( buffer, bufferLen, 0 );
627 }
628
629 void cliFunc_i2cRecv( char* args )
630 {
631         char* curArgs;
632         char* arg1Ptr;
633         char* arg2Ptr = args;
634
635         // Buffer used after interpretting the args, will be sent to I2C functions
636         // NOTE: Limited to 8 bytes currently (can be increased if necessary
637         #define i2cSend_BuffLenMax 8
638         uint8_t buffer[ i2cSend_BuffLenMax ];
639         uint8_t bufferLen = 0;
640
641         // No \r\n by default after the command is entered
642         print( NL );
643         info_msg("Sending: ");
644
645         // Parse args until a \0 is found
646         while ( bufferLen < i2cSend_BuffLenMax )
647         {
648                 curArgs = arg2Ptr; // Use the previous 2nd arg pointer to separate the next arg from the list
649                 CLI_argumentIsolation( curArgs, &arg1Ptr, &arg2Ptr );
650
651                 // Stop processing args if no more are found
652                 if ( *arg1Ptr == '\0' )
653                         break;
654
655                 // If | is found, end sequence and start new one
656                 if ( *arg1Ptr == '|' )
657                 {
658                         print("| ");
659                         I2C_Send( buffer, bufferLen, 0 );
660                         bufferLen = 0;
661                         continue;
662                 }
663
664                 // Interpret the argument
665                 buffer[ bufferLen++ ] = (uint8_t)numToInt( arg1Ptr );
666
667                 // Print out the arg
668                 dPrint( arg1Ptr );
669                 print(" ");
670         }
671
672         print( NL );
673
674         I2C_Send( buffer, bufferLen, 1 ); // Only 1 byte is ever read at a time with the ISSI chip
675 }
676
677 void cliFunc_ledZero( char* args )
678 {
679         print( NL ); // No \r\n by default after the command is entered
680         LED_zeroPages( 0x00, 8, 0xB3 );
681 }
682