/****************************************************************************

seatalk_wireless_remote_tx_1.c

This program is a remote control transmitter that sends a RxCx
number in an eight-byte message sentence with checksum.

Message protocol to the wireless receiver
* Each 9600 baud message contains a command and checksum:
   0xff    // wake up the transmitter and receiver
   0xff    // wake up the transmitter and receiver
   0xff    // wake up the transmitter and receiver
   'J'     // character
   'S'     // character
   'F'     // character
   cMsgCode   // which key was pressed
   'J' + 'S' + 'F' + cMsgCode   // equals checksum

                    +5
                    |
                    14
                ----------
      R4 ----6-| B0    A0 |-17-- out to Parallax 433MHz transmitter
      R3 ----7-| B1    A1 |-18-- out to LED
      R2 ----8-| B2       |
      R1 ----9-| B3       |
      C3 ---13-| B7       |
      C2 ---12-| B6       |
      C1 ---11-| B5       |
               |          |
 10MHz XTAL-15-|  16F628  |
       XTAL-16-|          |
                ----------
                     5
                     |
                    Gnd


          KEYBOARD ASSIGNMENTS
            C1      C2      C3
        +------------------------+
    R1  |      (cable here)      |
        |                        |
    R2  |                        |
        |                        |
    R3  |                        |
        |                        |
    R4  |                        |
        +------------------------+


***************************************************************************/

#include <16F628.h>
#include 

#fuses HS, NOPROTECT, PUT, BROWNOUT, NOMCLR, NOLVP, WDT, NOCPD

#use fast_io ( A )
#use fast_io ( B )
#use delay ( clock = 10MHZ, restart_wdt )
#use rs232 ( baud = 9600, xmit = PIN_A0 )

#byte PORT_A   = 5
#byte PORT_B   = 6
#bit  LED      = PORT_A.1
#bit  TX_PWR   = PORT_A.2

#define KEY_NONE       0
#define KEY_C1_R1      1
#define KEY_C1_R2      2
#define KEY_C1_R3      3
#define KEY_C1_R4      4
#define KEY_C2_R1      5
#define KEY_C2_R2      6
#define KEY_C2_R3      7
#define KEY_C2_R4      8
#define KEY_C3_R1      9
#define KEY_C3_R2      10
#define KEY_C3_R3      11
#define KEY_C3_R4      12

void SendMsg ( char cMsgCode );
char GetKey ( void );
void DelayMs ( int cCount );

void main ( void )
        {
        char cKey, cCnt, cX;

        set_tris_a ( 0b11111000 );          // A0, A1, A2 are outputs
        set_tris_b ( 0b00011111 );          // Columns are outputs, rows are inputs, RB4 is input (LVP)
        TX_PWR = OFF;
        setup_counters ( RTCC_INTERNAL, WDT_36MS );   // 256 * 4uS = 1.024mS timer wrap
        port_b_pullups ( TRUE );
        disable_interrupts ( GLOBAL );
        cCnt = 0;                         // preset LED flash

        for ( cX = 0; cX < 20; cX++ )       // 2 second power up flash
            {
            LED = HIGH;
            DelayMs ( 50 );
            LED=LOW;
            DelayMs ( 50 );
            }

        while ( TRUE )      // do forever
            {
            sleep();                   // stop here, wait for WDT every 36mS
            if ( cCnt++ >= 138 )       // flash LED once every 5 seconds @ 36mS WDT
                {
                LED = HIGH;
                DelayMs ( 10 );
                LED = LOW;
                cCnt = 0;
                }
            cKey = GetKey();
            if ( cKey != KEY_NONE )
                {
                switch ( cKey )
                    {
                    case KEY_C1_R1:
                        {
                        SendMsg ( KEY_C1_R1 );
                        break;
                        }
                    case KEY_C1_R2:
                        {
                        SendMsg ( KEY_C1_R2 );
                        break;
                        }
                    case KEY_C1_R3:
                        {
                        SendMsg ( KEY_C1_R3 );
                        break;
                        }
                    case KEY_C1_R4:
                        {
                        SendMsg ( KEY_C1_R4 );
                        break;
                        }
                    case KEY_C2_R1:
                        {
                        SendMsg ( KEY_C2_R1 );
                        break;
                        }
                    case KEY_C2_R2:
                        {
                        SendMsg ( KEY_C2_R2 );
                        break;
                        }
                    case KEY_C2_R3:
                        {
                        SendMsg ( KEY_C2_R3 );
                        break;
                        }
                    case KEY_C2_R4:
                        {
                        SendMsg ( KEY_C2_R4 );
                        break;
                        }
                    case KEY_C3_R1:
                        {
                        SendMsg ( KEY_C3_R1 );
                        break;
                        }
                    case KEY_C3_R2:
                        {
                        SendMsg ( KEY_C3_R2 );
                        break;
                        }
                    case KEY_C3_R3:
                        {
                        SendMsg ( KEY_C3_R3 );
                        break;
                        }
                    case KEY_C3_R4:
                        {
                        SendMsg ( KEY_C3_R4 );
                        break;
                        }
                    }
                }
            }
        }

GetKey ( void )
    {
    char cKey, cPortBIn;

    restart_wdt();
    cKey = KEY_NONE;                            // default is invalidated key
    PORT_B = 0b00011111;                        // make all three columns low
    delay_us ( 500 );                           // wait for row lines to settle (was 5mS, lowered to consume less avg pwr)
    if ( ( PORT_B & 0x0F ) != 0x0F )            // if any row line is low
        {
        DelayMs ( 5 );                         // debounce
        PORT_B = 0b01111111;                    // make C3 low
        delay_us ( 10 );                        // wait 10uS to settle
        cPortBIn = PORT_B;                      // get port B contents
        if ( ( cPortBIn & 0x0F ) == 0b00001110 )  // check rows
            {
            cKey = KEY_C3_R4;
            }
        if ( ( cPortBIn & 0x0F ) == 0b00001101 )
            {
            cKey = KEY_C3_R3;
            }
        if ( ( cPortBIn & 0x0F ) == 0b00001011 )
            {
            cKey = KEY_C3_R2;
            }
        if ( ( cPortBIn & 0x0F ) == 0b00000111 )
            {
            cKey = KEY_C3_R1;
            }
        PORT_B = 0b10111111;                    // make C2 low
        delay_us ( 10 );                        // wait 10uS to settle
        cPortBIn = PORT_B;                      // get port B contents
        if ( ( cPortBIn & 0x0F ) == 0b00001110 )  // check rows
            {
            cKey = KEY_C2_R4;
            }
        if ( ( cPortBIn & 0x0F ) == 0b00001101 )
            {
            cKey = KEY_C2_R3;
            }
        if ( ( cPortBIn & 0x0F ) == 0b00001011 )
            {
            cKey = KEY_C2_R2;
            }
        if ( ( cPortBIn & 0x0F ) == 0b00000111 )
            {
            cKey = KEY_C2_R1;
            }
        PORT_B = 0b11011111;                    // make C1 low
        delay_us ( 10 );                        // wait 10uS to settle
        cPortBIn = PORT_B;                      // get port B contents
        if ( ( cPortBIn & 0x0F ) == 0b00001110 )  // check rows
            {
            cKey = KEY_C1_R4;
            }
        if ( ( cPortBIn & 0x0F ) == 0b00001101 )
            {
            cKey = KEY_C1_R3;
            }
        if ( ( cPortBIn & 0x0F ) == 0b00001011 )
            {
            cKey = KEY_C1_R2;
            }
        if ( ( cPortBIn & 0x0F ) == 0b00000111 )
            {
            cKey = KEY_C1_R1;
            }
        DelayMs ( 5 );
        PORT_B = 0b00011111;                    // make all three columns low
        delay_us ( 10 );                        // wait 10uS to settle
        while ( ( PORT_B & 0x0F ) != 0x0F )     // wait until all rows are high (no keys pressed )
           {
           DelayMs ( 5 );
           }
        }
    PORT_B = 0b11111111;                       // make all three columns high
    return ( cKey );
    }

void SendMsg ( char cMsgCode )
   {
   TX_PWR = ON;
   LED = HIGH;
   DelayMs ( 10 );  // power on time for transmitter (at least 4mS)
   putc ( 0x00 );    // wake up the receiver
   putc ( 0x00 );    // wake up the receiver
   putc ( 0x00 );    // wake up the receiver
   putc ( 'J' );
   putc ( 'S' );
   putc ( 'F' );
   putc ( cMsgCode );
   putc ( 'J' + 'S' + 'F' + cMsgCode );   // checksum
   restart_wdt();
   LED = LOW;
   TX_PWR = OFF;
   }

void DelayMs ( int cCount )
    {
    int cX;

    for ( cX = 0; cX < cCount; cX++ )
        {
        delay_ms ( 1 );
        restart_wdt();
        }
    }