Difference Analysis Generated by HtmlDiff on 11/10/2004 5:09 PM  

Base file: C:\CY4632_RDK_1_3\Firmware\Source Code\RDK Keyboard\keyboard.c

Modified file: C:\CY4632_RDK_1_31\Firmware\Source Code\RDK Keyboard\keyboard.c

//--------------------------------------------------------------------------
//
// LS RDK KBM Keyboard application
//
//--------------------------------------------------------------------------
// $Archive: /WirelessUSB/WUSB Kits/CY4632 LS KBM RDK/DocSrc/CD_Root/Firmware/Source Code/RDK Keyboard/keyboard.c $
// $Modtime: 9/30/04 12:01p4/28/04 9:28a $
// $Revision: 91.42 $
//--------------------------------------------------------------------------
//
// Copyright 2003-2004, Cypress Semiconductor Corporation.
//
// This software is owned by Cypress Semiconductor Corporation (Cypress)
// and is protected by and subject to worldwide patent protection (United
// States and foreign), United States copyright laws and international 
// treaty provisions. Cypress hereby grants to licensee a personal, 
// non-exclusive, non-transferable license to copy, use, modify, create 
// derivative works of, and compile the Cypress Source Code and derivative 
// works for the sole purpose of creating custom software in support of 
// licensee product to be used only in conjunction with a Cypress integrated 
// circuit as specified in the applicable agreement. Any reproduction, 
// modification, translation, compilation, or representation of this 
// software except as specified above is prohibited without the express 
// written permission of Cypress.
//
// Disclaimer: CYPRESS MAKES NO WARRANTY OF ANY KIND,EXPRESS OR IMPLIED, 
// WITH REGARD TO THIS MATERIAL, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
// Cypress reserves the right to make changes without further notice to the
// materials described herein. Cypress does not assume any liability arising
// out of the application or use of any product or circuit described herein.
// Cypress does not authorize its products for use as critical components in
// life-support systems where a malfunction or failure may reasonably be
// expected to result in significant injury to the user. The inclusion of
// Cypress’ product in a life-support systems application implies that the
// manufacturer assumes all risk of such use and in doing so indemnifies
// Cypress against all charges.
//
// Use may be limited by and subject to the applicable Cypress software
// license agreement.
//
//--------------------------------------------------------------------------

/*
Device Class Definition for Human Interface Devices (HID) Version 1.11
Page 62 (72 absolute). Appendix C: Keyboard Implementation
- Reports must contain a list of keys currently pressed and not make/break codes (relative data).
- If two or more keys are reported in one report, their order is indeterminate.
*/


#include "ls_config.h"
#include "m8c.h"
#include "kdefs.h"
#include "protocol.h"
#include "bind.h"
#include "radio.h"
#include "battery.h"

// Keyboard structure
HID_APP hid;

// Report packet pointer
APP_TX_PACKET *report_packet;

// Timestamps
TIME_STAMP      ts;
TIME_STAMP      last_transfer_ts;

#ifdef KEYBOARD_TEST_MODES
TEST_STATE test_mode = TEST_OFF;
UINT8   sentence_table_index = 0;
#else
#ifdef MFG_ENTER_BY_KEY_NOT_PIN
#ifndef MFG_ENTER_BY_PIN
TEST_STATE test_mode = TEST_OFF;
#endif // MFG_ENTER_BY_KEY_NOT_PIN
#endif // KEYBOARD_TEST_MODES

#ifdef MOUSE_EMULATION_MODE
UINT8  mouse_emulation = FALSE;
#endif // MOUSE_EMULATION_MODE


//--------------------------------------------------------------------------
//                                                           bind_button_isr
//--------------------------------------------------------------------------

void bind_button_isr(void)
{
#ifndef BIND_BASIC
    if (SW1_MASK & ~RADIO_PORT)
    {
        hid.status |= BIND_BUTTON;

        // Wait for button to be released.
        while (SW1_MASK & ~RADIO_PORT)
        {
            RADIO_PORT |= SW1_MASK;         
        }
    }
#endif // BIND_BASIC

    RADIO_PORT |= SW1_MASK;
}


//--------------------------------------------------------------------------
//                                                              keyboard_isr
//--------------------------------------------------------------------------

void keyboard_isr(void)
{
    UINT8 temp;
    
    // Read to clear interrupt
    temp = KB_ROW_PORT;

    // Indicate wakeup
    hid.status &= ~KEYBOARD_SLEEP;
}


//--------------------------------------------------------------------------
//                                                            key_queue_init
//--------------------------------------------------------------------------
void
key_queue_init()
{
    UINT8 i;

    hid.status &= ~(GENERATE_STD_REPORT | GENERATE_HOT_REPORT | GENERATE_PWR_REPORT);

    for (i = 0; i < KEY_QUEUE_LEN; ++i)
    {
        hid.key_queue[i].index = INVALID_INDEX;
    }
}


//--------------------------------------------------------------------------
//                                                   add_or_update_key_queue
// Returns TRUE is key was added or updated; otherwise, FALSE for overflow
//--------------------------------------------------------------------------
BOOL
add_or_update_key_queue(KEY key)
{
    UINT8 i;
    
    if (key.state & (KEY_STATE_UP | KEY_STATE_MOD_UP))
    {
        // Check for update
        for (i = 0; i < KEY_QUEUE_LEN; ++i)
        {
            if ((hid.key_queue[i].index == key.index) &&
                !(hid.key_queue[i].state & (KEY_STATE_UP | KEY_STATE_MOD_UP | KEY_STATE_REMOVE)))
            {
                //Update state
                hid.key_queue[i].state |= key.state;

                if (key.state & KEY_STATE_MOD_UP)
                {
                    // Need to add the up key as a separate key entry
                    break;
                }

                return TRUE;
            }
        }

        // Update modifier key state
        if (key.state & KEY_STATE_MOD_UP)
        {
            key.state = KEY_STATE_UP;
        }
    }

    // Add key to queue
    for (i = 0; i < KEY_QUEUE_LEN; ++i)
    {
        if (hid.key_queue[i].index == INVALID_INDEX)
        {
            // Add key
            hid.key_queue[i].index = key.index;
            hid.key_queue[i].state = key.state;
            return TRUE;
        }
    }

    // Key queue is full
    return FALSE;
}


//--------------------------------------------------------------------------
//                                                            sort_key_queue
//--------------------------------------------------------------------------
void
sort_key_queue(void)
{
    UINT8 i;
    UINT8 j;
    UINT8 index;
    UINT8 device;
    UINT8 state;
    UINT8 std_count = 0;
    UINT8 hot_count = 0;
    UINT8 pwr_count = 0;
    
    // Shift key entry(s) to beginning of the key queue
    for (i = 0; i < KEY_QUEUE_LEN; ++i)
    {
        // Remove completed keys
        if ((hid.key_queue[i].index != INVALID_INDEX) && 
            (hid.key_queue[i].state & KEY_STATE_REMOVE))
        {
            hid.key_queue[i].index = INVALID_INDEX;
        }

        // Search for replacement entry if invalid
        if (hid.key_queue[i].index == INVALID_INDEX)
        {
            for (j = (i+1); j < KEY_QUEUE_LEN; ++j)
            {
                // Check for valid key entry
                if ((hid.key_queue[j].index != INVALID_INDEX) &&
                    (hid.key_queue[j].state != KEY_STATE_REMOVE))
                {
                    // Move key entry
                    hid.key_queue[i].index = hid.key_queue[j].index;
                    hid.key_queue[i].state = hid.key_queue[j].state;
                    
                    // Remove original entry
                    hid.key_queue[j].index = INVALID_INDEX;
                    
                    break;
                }
            }
        }
        
        index = hid.key_queue[i].index;
        device = default_keyboard_scan_table[index].device & DEVICE_MASK;
        state = hid.key_queue[i].state;

        // Check for pending keys that can be sent
        if (index != INVALID_INDEX)
        {
#ifndef MOUSE_EMULATION_MODE
            if (device == DEVICE_1)
#else
            if ((device == DEVICE_1) ||
                (device == DEVICE_4) ||
                (device == DEVICE_5))
#endif // MOUSE_EMULATION_MODE
            {
                if (state != KEY_STATE_UP)
                {
                    ++std_count;
                }

                if (((std_count <= KEYBOARD_REPORT_NUM_KEYCODES) && (state & KEY_STATE_DOWN)) ||
                    (state & (KEY_STATE_UP | KEY_STATE_MOD_UP)))
                {
                    hid.status |= GENERATE_STD_REPORT;
                }
            }
    
#ifdef KEYBOARD_MULTIMEDIA_SUPPORT
            else if (device == DEVICE_2)
            {
                if (state != KEY_STATE_UP)
                {
                    ++hot_count;
                }

                if (((hot_count <= KEYBOARD_REPORT_NUM_HOTCODES) && (state & KEY_STATE_DOWN)) ||
                    (state == KEY_STATE_UP))
                {
                    hid.status |= GENERATE_HOT_REPORT;
                }
            }
            else if (device == DEVICE_3)
            {
                if (state != KEY_STATE_UP)
                {
                    ++ pwr_count;
                }

                if (((pwr_count <= KEYBOARD_REPORT_NUM_PWRCODES) && (state & KEY_STATE_DOWN)) ||
                    (state == KEY_STATE_UP))
                {
                    hid.status |= GENERATE_PWR_REPORT;
                }
            }
#endif // KEYBOARD_MULTIMEDIA_SUPPORT
        }
    }
}


//--------------------------------------------------------------------------
//                                                             debounce_init
//--------------------------------------------------------------------------
void
debounce_init(void)
{
    UINT8 i;

    for (i = 0; i < (DEBOUNCE_QUEUE_LENGTH); ++i)
    {
        hid.debounce[i].value = 0x00;
        hid.debounce[i].index = INVALID_INDEX;
    }
}


//--------------------------------------------------------------------------
//                                                        age_debounce_queue
//--------------------------------------------------------------------------
void
age_debounce_queue(void)
{
    UINT8 i;
    UINT8 value;

    for (i = 0; i < (DEBOUNCE_QUEUE_LENGTH); ++i)
    {
        value = hid.debounce[i].value;

        if (0x00 < value)
        {
            // Decrement debounce value
            hid.debounce[i].value = --value;

            // If value reaches 0x00 ignore the key
            if (value == 0x00)
            {
                // Remove index
                hid.debounce[i].index = INVALID_INDEX;
            }
        }
    }
}


//--------------------------------------------------------------------------
//                                                                  debounce
//--------------------------------------------------------------------------
BOOL
debounce(UINT8 index)
{
    UINT8 i;

    // Check for index
    for (i = 0; i < (DEBOUNCE_QUEUE_LENGTH); ++i)
    {
        if (index == hid.debounce[i].index)
        {
#ifdef DEBOUNCE_BEFORE_REPORT
            if (hid.debounce[i].value <= 0x1)
                return TRUE;
            else
                return FALSE;
#else
            return FALSE;
#endif
        }
    }

    // Add index (if space)
    for (i = 0; i < (DEBOUNCE_QUEUE_LENGTH); ++i)
    {
        if (hid.debounce[i].index == INVALID_INDEX)
        {
            // Add index to first available entry
            hid.debounce[i].index = index;
            hid.debounce[i].value = KEYBOARD_DEBOUNCE_COUNT;
#ifdef DEBOUNCE_BEFORE_REPORT
            return FALSE;
#else
            return TRUE;
#endif
        }
    }

    // No free entry
    return FALSE;
}


//--------------------------------------------------------------------------
//                                                                     ghost
// look for more than 1 active row.
// if a column has more than 1 active row and the current
//    active row matches, return FALSE
//--------------------------------------------------------------------------
BOOL
ghost(KEY_STATE state, UINT8 column_index, UINT8 this_column, UINT8 this_row_bit, UINT8 * current_key_state_ptr)
{
    UINT8 num_down_keys;
    UINT8 column_state;
    UINT8 mask;
    UINT8 col, row;
    UINT8 combined;

    if (state & (KEY_STATE_UP | KEY_STATE_MOD_UP))
    {
        return TRUE; // ignore up key events
    }

    for (col = 0; col < COLUMNS; ++col)
    {
        if (col != column_index) // exclude currently selected column
        {
            num_down_keys = 0;

            column_state = *(current_key_state_ptr + col);

            combined = column_state & this_column;

            if (combined)
            {
                // There are key downs in the same row
                // Now we need to count.
                // If more than 2 than we've got a ghost key.

                for (row = 0; row < ROWS; ++row)
                {
                    mask = 0x01 << row;

                    if (column_state & mask)
                    {
                        num_down_keys++; // count the number of down keys
                    }
                }
            }

            if (1 < num_down_keys ) // more than 1 key down in this column.
            {
                // Now we need to figure out if the key in question is in the ghost situation.

                mask = 0x01 << this_row_bit;  // look for any match with the asserted (key down) row
                if (combined & mask) // If it's one of the ghost keys
                {                   
                    return FALSE;
                }
            }
        }
    }

    return TRUE;
}


//--------------------------------------------------------------------------
//                                                      send_keyboard_report
//--------------------------------------------------------------------------
void
send_keyboard_report(UINT8 report_size)
{
    UINT8 keyboard_report[sizeof(APP_TX_PACKET)];
    UINT8 i;

    // Save Keyboard report
    if (report_size == 0x0)
    {
#ifdef NULL_PACKET_DATA
        // Handle NULL Packets
        keyboard_report[0x0] = *((UINT8 *) report_packet);
#else
        // Nothing to send
        return;
#endif
    }
    else
    {
#ifdef ENCRYPT_DATA 
        // Do not encrypt battery reports, keep alive, or up-key only packets
        if ((((*((UINT8 *) report_packet) != KEYBOARD_BATT_REPORT_TYPE) &&
               (*((UINT8 *) report_packet) != KEYBOARD_ALIVE_REPORT_TYPE)) &&
              !((*((UINT8 *) report_packet) == 0x00) && (report_size == 0x1))
            ))
        {
#ifdef MOUSE_EMULATION_MODE
            if (protocol_device_type != MOUSE_DEVICE_TYPE)
#endif // MOUSE_EMULATION_MODE
            {
                // Encrypt data packet
                report_size = encrypt_data(report_size);
            }
        }
#endif //ENCRYPT_DATA

        // Store Keyboard report
        for (i = 0; i < report_size; i++)
        {           
            keyboard_report[i] =  *((UINT8 *) report_packet + i);
        }
    }

    // Send Keyboard Report
#ifdef KEYBOARD_TEST_MODES
    // Set status to skip the test mode during scanning in this loop
    hid.status |= SKIP_TEST_MODE;

    while (!(hid.status & BIND_BUTTON) &&
           (!timer_time_elapsed(ts, KEYBOARD_TX_TIMEOUT) ||
           ((test_mode != TEST_OFF) && !(test_mode & TEST_QUIT))))
#else
    while (!(hid.status & BIND_BUTTON) &&
           !timer_time_elapsed(ts, KEYBOARD_TX_TIMEOUT))
#endif
    {
        // Clear Watchdog and Sleep
        M8C_ClearWDTAndSleep;

        // Transmit Keyboard Report
        i = protocol_send_packet(report_size);

        // Check for timeout or reconnect
        if (i == TX_TIMEOUT_ERR)
        {
            // Note: A reconnect destroys the content of the original report
            
            // Restore Keyboard report
            if (report_size == 0x0)
            {
                // Handle NULL Packets
                *((UINT8 *) report_packet) = keyboard_report[0x0];
            }
            else
            {
                // Restore Keyboard report
                for (i = 0; i < report_size; i++)
                {           
                    *((UINT8 *) report_packet + i) = keyboard_report[i];
                }
            }

#ifdef TIMER_CAL
            // Disable bind interrupt
            ISR_DISABLE(GPIO_ISR_BIND_IE_PORT, GPIO_ISR_BIND_INT);

            // Calibrate the tick timer (Assumes a reconnect)
            timer_calibrate_timer(TRUE);

            // Enable bind interrupt
            ISR_ENABLE(GPIO_ISR_BIND_IE_PORT, GPIO_ISR_BIND_INT);
#endif
        } 

        if (i == ACK_DATA)
        {
#ifdef KEYBOARD_BATTERY_VOLTAGE_SUPPORT
            // Set Send Battery Report 
            hid.status |= BATT_REPORT_REQ;
#endif
            break;
        }

        if (i == DATA_SENT)
        {
            break;
        }
    }

#ifdef KEYBOARD_TEST_MODES
    // Clear status to skip the test mode
    hid.status &= ~SKIP_TEST_MODE;
#endif
}


//--------------------------------------------------------------------------
//                                                          gen_alive_packet
//--------------------------------------------------------------------------
void
generate_alive_packet(void)
{
#ifdef NULL_PACKET_DATA
    // Indicate that is a keep alive packet
    report_packet->scan_report.modifier_keys = 0x02;

    // Send a keep alive report
    send_keyboard_report(0x0);
#else
    // Indicate that is a keep alive packet
    report_packet->scan_report.modifier_keys = KEYBOARD_ALIVE_REPORT_TYPE;

    // Send a keep alive report
    send_keyboard_report(0x1);
#endif
}

#ifdef KEYBOARD_MULTIMEDIA_SUPPORT
//--------------------------------------------------------------------------
//                                                       generate_pwr_report
//--------------------------------------------------------------------------
void
generate_pwr_report(void)
{
    UINT8   i;
    BOOL    send_report = FALSE;

    // Initialize report
    report_packet->pwr_report.report_type = KEYBOARD_PWR_REPORT_TYPE;

    for (i=0; i<KEYBOARD_REPORT_NUM_PWRCODES; i++)
    {
        report_packet->pwr_report.pwrcode[i] = 0;
    }

    {
        KEY     this_key;
        UINT8   device;
        UINT8   scan_code;
        UINT8   num_entries = 0;

        for (i = 0; i < KEY_QUEUE_LEN; ++i)
        {
            this_key.index = hid.key_queue[i].index;
    
            if (this_key.index == INVALID_INDEX)
            {
                continue; // don't do anything else this iteration.
            }
    
            device = default_keyboard_scan_table[this_key.index].device;

            if ((device & DEVICE_MASK) == DEVICE_3)
            {
                scan_code = 0;
                
                // Check for duplicate keys
                for (device = 0; device < i; device ++)
                {
                    if (this_key.index == hid.key_queue[device].index)
                    {
                        scan_code = 1;
                    }
                }
    
                // Exit loop if duplicate key
                if (scan_code == 1)
                {
                    break;
                }
    
                this_key.state = hid.key_queue[i].state;
                
                device   = default_keyboard_scan_table[this_key.index].device;
                scan_code = default_keyboard_scan_table[this_key.index].scan_code;
    
                // Valid Hot key
                send_report = TRUE;
    
                //---- Process Hot Keys ----------------------------------
                if (this_key.state == KEY_STATE_UP)
                {
                    hid.key_queue[i].state = KEY_STATE_REMOVE;
                }
                else // KEY_STATE_DOWN
                {
                    if (num_entries < KEYBOARD_REPORT_NUM_PWRCODES)
                    {
                        hid.key_queue[i].state &= ~KEY_STATE_DOWN;
                        report_packet->pwr_report.pwrcode[num_entries] = scan_code;
                        ++num_entries;
                    }
                }
            }
        }
        // Eliminate trailing zeros in the report count
        // Note:  Each entry is one byte and the report type is one byte

        i = num_entries + 1;
    }

    // Send report
    if (send_report)
    {
        // Send report
        send_keyboard_report(i);
    }
}



//--------------------------------------------------------------------------
//                                                       generate_hot_report
//--------------------------------------------------------------------------
void
generate_hot_report(void)
{
    UINT8   i;
    BOOL    send_report = FALSE;

    // Initialize report
    report_packet->hot_report.report_type = KEYBOARD_HOT_REPORT_TYPE;

    for (i=0; i<KEYBOARD_REPORT_NUM_HOTCODES; i++)
    {
        report_packet->hot_report.hotcode[i] = 0;
    }

    {
        KEY     this_key;
        UINT8   device;
        UINT8   scan_code;
        UINT8   num_entries = 0;

        for (i = 0; i < KEY_QUEUE_LEN; ++i)
        {
            this_key.index = hid.key_queue[i].index;
    
            if (this_key.index == INVALID_INDEX)
            {
                continue; // don't do anything else this iteration.
            }
    
            device = default_keyboard_scan_table[this_key.index].device;

            if ((device & DEVICE_MASK) == DEVICE_2)
            {
                scan_code = 0;
                
                // Check for duplicate keys
                for (device = 0; device < i; device ++)
                {
                    if (this_key.index == hid.key_queue[device].index)
                    {
                        scan_code = 1;
                    }
                }
    
                // Exit loop if duplicate key
                if (scan_code == 1)
                {
                    break;
                }
    
                this_key.state = hid.key_queue[i].state;
                
                device   = default_keyboard_scan_table[this_key.index].device;
                scan_code = default_keyboard_scan_table[this_key.index].scan_code;
    
                // Valid Hot key
                send_report = TRUE;
    
                //---- Process Hot Keys ----------------------------------
                if (this_key.state == KEY_STATE_UP)
                {
                    hid.key_queue[i].state = KEY_STATE_REMOVE;
                }
                else // KEY_STATE_DOWN
                {
                    if (num_entries < KEYBOARD_REPORT_NUM_HOTCODES)
                    {
                        hid.key_queue[i].state &= ~KEY_STATE_DOWN;
                        report_packet->hot_report.hotcode[num_entries] = device_2_keyboard_scan_table[scan_code];
                        ++num_entries;
                    }
                }
            }
        }
        // Eliminate trailing zeros in the report count
        // Note:  Each entry is two bytes and the report type is one byte

        i = (num_entries * 2) + 1;
    }

    // Send report
    if (send_report)
    {
        // Send report
        send_keyboard_report(i);
    }
}

#endif //KEYBOARD_MULTIMEDIA_SUPPORT

#ifdef KEYBOARD_BATTERY_VOLTAGE_SUPPORT
//--------------------------------------------------------------------------
//                                                      generate_batt_report
//--------------------------------------------------------------------------
void
generate_batt_report(void)
{
    // Battery Report Requested?
    if (hid.status & BATT_REPORT_REQ)
    {
        // Clear Battery Request
        hid.status &= ~BATT_REPORT_REQ;

        // Disable Bind interrupt
        ISR_DISABLE(GPIO_ISR_BIND_IE_PORT, GPIO_ISR_BIND_INT);

        // Initialize report
        report_packet->batt_report.report_type = KEYBOARD_BATT_REPORT_TYPE;

        // Set battery voltage level value
        report_packet->batt_report.battery_voltage_level = battery_status();

        // Enable bind interrupt
        ISR_ENABLE(GPIO_ISR_BIND_IE_PORT, GPIO_ISR_BIND_INT);

        // Transmit Keyboard Report
        send_keyboard_report(sizeof(KEYBOARD_BATT_REPORT));
    }
}

#endif //KEYBOARD_BATTERY_VOLTAGE_SUPPORT


//--------------------------------------------------------------------------
//                                                  generate_standard_report
//--------------------------------------------------------------------------
void
generate_standard_report()
{

    UINT8   i;
    BOOL    send_report = FALSE;

    // Initialize report
    report_packet->scan_report.modifier_keys = 0;

    for (i=0; i<KEYBOARD_REPORT_NUM_KEYCODES; i++)
    {
        report_packet->scan_report.keycode[i] = 0;
    }

    {
        KEY     this_key;
        UINT8   device;
        UINT8   scan_code;
        UINT8   num_entries = 0;
        UINT8   modifiers   = 0;

        for (i = 0; i < KEY_QUEUE_LEN; ++i)
        {
            this_key.index = hid.key_queue[i].index;

            if (this_key.index == INVALID_INDEX)
            {
                continue; // don't do anything else this iteration.
            }
    
            device = default_keyboard_scan_table[this_key.index].device;

            // Check for Standard 101 key
#ifndef MOUSE_EMULATION_MODE
            if ( (device & DEVICE_MASK) == DEVICE_1 )
#else
            if (((device & DEVICE_MASK) == DEVICE_1) ||
                (((device & DEVICE_MASK) == DEVICE_5) && !mouse_emulation))
#endif // MOUSE_EMULATION_MODE
            {

                //Check for down key entries before modifier key
                if ((0 < num_entries) && (device & MODIFIER_KEY))
                {
                    // Down key entries located before a modifier must be sent before a modifier change
                    break;
                }
    
                scan_code = 0;
                
                // Check for duplicate keys
                for (device = 0; device < i; device ++)
                {
                    if (this_key.index == hid.key_queue[device].index)
                    {
                        // Check for the same modifier up and down key
                        if (hid.key_queue[device].state & KEY_STATE_MOD_UP)
                        {
                            // Remove modifier down key
                            hid.key_queue[device].state = KEY_STATE_REMOVE;
                        }
    
                        scan_code = 1;
                        break;
                    }
                }
    
                // Exit loop if duplicate key
                if (scan_code == 1)
                {
                    break;
                }
        
                this_key.state = hid.key_queue[i].state;
                
                device = default_keyboard_scan_table[this_key.index].device;
                scan_code = default_keyboard_scan_table[this_key.index].scan_code;
    
                // Valid Standard 101 key
                send_report = TRUE;
    
                //---- Process Modifier List -----------------------------
                // check whether index is a modifier
                if (device & MODIFIER_KEY)
                {
#ifdef KEYBOARD_TEST_MODES
                    // Do not allow modifiers during tests
                    if (test_mode != TEST_OFF)
                    {
                        hid.key_queue[i].state = KEY_STATE_REMOVE;
                    }
                    else
#endif
                    {
                        if (this_key.state == KEY_STATE_UP)
                        {
                            modifiers &= ~scan_code;
                            hid.key_queue[i].state = KEY_STATE_REMOVE;
                        }
                        else // KEY_STATE_DOWN
                        {
                            hid.key_queue[i].state &= ~KEY_STATE_DOWN;
                            modifiers |= scan_code;
                        }
                    }
                    report_packet->scan_report.modifier_keys = modifiers;
                }
                else
                {
                    //---- Process Keyboard Scan -----------------------------
                    if (this_key.state == KEY_STATE_UP)
                    {
                        hid.key_queue[i].state = KEY_STATE_REMOVE;
                    }
                    else // KEY_STATE_DOWN
                    {
                        if (num_entries < KEYBOARD_REPORT_NUM_KEYCODES)
                        {
                            hid.key_queue[i].state &= ~KEY_STATE_DOWN;
                            report_packet->scan_report.keycode[num_entries] = scan_code;
                            ++num_entries;
                        }
                    }
                }
            }
        }
        // Swap Modifier and Scan Code 1 bytes
        // Note:  this assumes the most common down key is a single
        //        scan code without a modifier key.
        modifiers = report_packet->scan_report.modifier_keys;
        report_packet->scan_report.modifier_keys = report_packet->scan_report.keycode[0];
        report_packet->scan_report.keycode[0] = modifiers;

        // Eliminate trailing zeros from the report count
        if ((num_entries == 0) || (num_entries == 1))
        {
            i = num_entries;

            if (modifiers != 0x0)
            {
                i = 2;
            }           
        }
        else
        {
            i = num_entries + 1;
        }
    }

    // Send report
    if (send_report)
    {
#ifndef NULL_PACKET_DATA
        if (i == 0)
        {
            // Send a one byte packet (bytes is already 0x00)
            i = 1;
        }
#endif

        // Transmit Keyboard Report
        send_keyboard_report(i);
    }
}


#ifdef MOUSE_EMULATION_MODE
//--------------------------------------------------------------------------
//                                                     generate_mouse_report
//--------------------------------------------------------------------------
void
generate_mouse_report(void)
{
    UINT8   i;
    BOOL    send_report = FALSE;

    // Initialize report
    report_packet->mouse_report.x = 0;
    report_packet->mouse_report.y = 0;
    report_packet->mouse_report.combi = 0;

    {
        KEY     this_key;
        UINT8   device;
        UINT8   scan_code;
        INT8    scroll_value = 0;

        for (i = 0; i < KEY_QUEUE_LEN; ++i)
        {
            this_key.index = hid.key_queue[i].index;
    
            if (this_key.index == INVALID_INDEX)
            {
                continue; // don't do anything else this iteration.
            }
    
            this_key.state = hid.key_queue[i].state;
            device   = default_keyboard_scan_table[this_key.index].device;
            scan_code = default_keyboard_scan_table[this_key.index].scan_code;
    
            // Check for Scroll lock (the only DEVICE_4 key) to toggle mouse emulation mode
            if ((device & DEVICE_MASK) == DEVICE_4)
            {
                // Only change state once on a down key
                if (this_key.state == KEY_STATE_UP)
                {
                    hid.key_queue[i].state = KEY_STATE_REMOVE;
                }
                else if (this_key.state == KEY_STATE_DOWN)
                {
                    // Toggle mouse emulation mode
                    mouse_emulation = !mouse_emulation;

                    hid.key_queue[i].state &= ~KEY_STATE_DOWN;  
                }
            }
    
            // Check for valid mouse "keys"
            if (((device & DEVICE_MASK) == DEVICE_5) && (mouse_emulation))
            {
                // Valid mouse "key"
                send_report = TRUE;
    
                //---- Process Mouse "Keys" ----------------------------------
                if (this_key.state == KEY_STATE_UP)
                {
                    hid.key_queue[i].state = KEY_STATE_REMOVE;
                }
                else // KEY_STATE_DOWN
                {
                    hid.key_queue[i].state &= ~KEY_STATE_DOWN;

                    switch(scan_code)
                    {
                        case UP_ARROW_KEY:
                            // Subtract Y movement
                            report_packet->mouse_report.y -= 1;
                        break;

                        case DOWN_ARROW_KEY:
                            // Accumulate Y movement
                            report_packet->mouse_report.y += 1;
                        break;

                        case LEFT_ARROW_KEY:
                            // Subtract X movement
                            report_packet->mouse_report.x -= 1;
                        break;

                        case RIGHT_ARROW_KEY:
                            // Accumulate X movement
                            report_packet->mouse_report.x += 1;
                        break;

                        case PAGE_UP_KEY:
                            // Scroll Up
                            ++scroll_value;
                        break;

                        case PAGE_DOWN_KEY:
                            // Scroll Down
                            --scroll_value;
                        break;

                        case DELETE_KEY:
                            // Buttons
                            report_packet->mouse_report.combi |= MOUSE_LEFT_BUTTON;
                        break;

                        case END_KEY:
                            // Buttons
                            report_packet->mouse_report.combi |= MOUSE_RIGHT_BUTTON;
                        break;

                        default:
                            // Remove Unknown key
                            hid.key_queue[i].state = KEY_STATE_REMOVE;
                        break;
                    }
                }
            }
        }
        if ((scroll_value != 0x00) || (report_packet->mouse_report.combi != 0x00))
        {
            report_packet->mouse_report.combi |= scroll_value & 0x1F;

            // Set report length to 3
            i = 3;
        }
        else
        {
            // Set report length to 2
            i = 2;
        }
    }

    // Send report
    if (send_report)
    {
        // Update timestamp
        last_transfer_ts = ts;

        // Change Device Type to Mouse
        protocol_device_type = MOUSE_DEVICE_TYPE;

        // Send report
        send_keyboard_report(i);

        // Change Device Type to Keyboard
        protocol_device_type = KEYBOARD_DEVICE_TYPE;
    }

    // Sort the key queue
    sort_key_queue();
}
#endif // MOUSE_EMULATION_MODE


//--------------------------------------------------------------------------
//                                                          generate_reports
//--------------------------------------------------------------------------
void
generate_reports(void)
{
#ifdef MOUSE_EMULATION_MODE
    // Build and send mouse report
    generate_mouse_report();
#endif // MOUSE_EMULATION_MODE

    // Check for keyboard reports
    if (hid.status & (GENERATE_STD_REPORT | GENERATE_HOT_REPORT | GENERATE_PWR_REPORT))
    {
        // Update timestamp
        last_transfer_ts = ts;

        if (hid.status & GENERATE_STD_REPORT)
        {
            // Reset generate standard report flag
            hid.status &= ~GENERATE_STD_REPORT;

            // Build and send Standard 101 report
            generate_standard_report();
        }

#ifdef KEYBOARD_MULTIMEDIA_SUPPORT
        if (hid.status & GENERATE_HOT_REPORT)
        {
            // Reset generate hot report flag
            hid.status &= ~GENERATE_HOT_REPORT;

            // Build and send Hot report
            generate_hot_report();
        }

        if (hid.status & GENERATE_PWR_REPORT)
        {
            // Reset generate power report flag
            hid.status &= ~GENERATE_PWR_REPORT;

            // Build and send Power report
            generate_pwr_report();
        }
#endif // KEYBOARD_MULTIMEDIA_SUPPORT

#ifdef KEYBOARD_BATTERY_VOLTAGE_SUPPORT
        // Build and send Battery Voltage report
        generate_batt_report();
#endif // KEYBOARD_BATTERY_VOLTAGE_SUPPORT

        // Sort the key queue
        sort_key_queue();

//      return TRUE;
    }

//  return FALSE;
}


//--------------------------------------------------------------------------
//                                                            process_column
//--------------------------------------------------------------------------
void
process_column(UINT8 column_index, UINT8 * current_key_state_ptr)
{
    UINT8 row;
    UINT8 last_row;
    UINT8 row_bit;
    UINT8 mask;
    KEY   key;
    UINT8 device;

    row      = *(current_key_state_ptr + column_index);
    last_row = hid.prior_key_state[column_index];

    if (row == last_row)
    {
        return;
    }

    for (mask = 0x01, row_bit = 0; row_bit < 8; ++row_bit, mask <<= 1)
    {
        if ((row & mask) == (last_row & mask))
        {
            continue; // No change
        }

        // Key change
        hid.status &= ~KEYBOARD_SLEEP;

        key.index = (column_index * 8) + row_bit; // calculate the index

        device = default_keyboard_scan_table[key.index].device;

        if (row & mask) // down key
        {
            key.state = KEY_STATE_DOWN;
        }
        else // up key
        {
            if (device & MODIFIER_KEY)
            {
                key.state = KEY_STATE_MOD_UP;
            }
            else
            {
                key.state = KEY_STATE_UP;
            }
        }

#ifndef KEYBOARD_MULTIMEDIA_SUPPORT
        // Ignore HOT and Power keys
        if (((device & DEVICE_MASK) == DEVICE_2) ||
            ((device & DEVICE_MASK) == DEVICE_3) ||
            ((device & DEVICE_MASK) == NO_DEVICE))
        {
            // Ignore Hot and Power keys
            continue;
        }
#else
        // Ignore No Device keys
        if ((device & DEVICE_MASK) == NO_DEVICE)
        {
            continue;
        }
#endif

        if (!debounce(key.index))
        {
            continue;
        }

        if (!ghost(key.state, column_index, row, row_bit, current_key_state_ptr))
        {
            continue;
        }

        if (!add_or_update_key_queue(key))
        {
            continue;
        }
        
        // only update the state if everthing ok
        
        if (key.state & KEY_STATE_DOWN)
        {
            last_row |= mask;
        }
        else // KEY_STATE_UP
        {
            last_row &= ~mask;
        }

#ifndef MOUSE_EMULATION_MODE
        if ((device & DEVICE_MASK) == DEVICE_1)
#else
        if (((device & DEVICE_MASK) == DEVICE_1) ||
            ((device & DEVICE_MASK) == DEVICE_4) ||
            ((device & DEVICE_MASK) == DEVICE_5))
#endif // MOUSE_EMULATION_MODE
        {
            hid.status |= GENERATE_STD_REPORT;
        }

#ifdef KEYBOARD_MULTIMEDIA_SUPPORT
        else if ((device & DEVICE_MASK) == DEVICE_2)
        {
            hid.status |= GENERATE_HOT_REPORT;
        }
        else if ((device & DEVICE_MASK) == DEVICE_3)
        {
            hid.status |= GENERATE_PWR_REPORT;
        }
#endif

        hid.prior_key_state[column_index] = last_row;
    
    } // for
}


#ifdef KEYBOARD_TEST_MODES
//--------------------------------------------------------------------------
//                                                                test_modes
//--------------------------------------------------------------------------
UINT8
test_modes(void)
{
    KEY             key;

    if (test_mode != TEST_OFF)
    {
        if (!(hid.status & SKIP_TEST_MODE))
        {
            // Do not let keyboard sleep
            hid.status &= ~KEYBOARD_SLEEP;
    
            // We need to process each character twice. Once as a down
            // key and once as an up key.
            if (test_mode & TEST_PANGRAM)
                key.index = sentence_table[sentence_table_index >> 1];
            else
                key.index = X_INDEX;
    
            if (sentence_table_index & 0x01)
            {
                hid.status &= ~KEY_DOWN;
                key.state = KEY_STATE_UP;
            }
            else
            {
                hid.status |= KEY_DOWN;
                key.state = KEY_STATE_DOWN;
            }
    
            // Make sure a key is not down before stopping a test mode
            if (( test_mode & TEST_QUIT ) && ( hid.status & KEY_DOWN ))
            {
                test_mode = TEST_OFF;
                sentence_table_index = 0;
            }
            else
            {
                add_or_update_key_queue(key);
    
                // Increment and store the index (handle wrap if necessary)
                sentence_table_index = (++sentence_table_index == (sizeof(sentence_table) * 2)) ? 0 : sentence_table_index;
    
                hid.status |= GENERATE_STD_REPORT;
            }
        }
        return 1;
    }
    else
    {
        return 0;
    }
}
#endif // KEYBOARD_TEST_MODES


//--------------------------------------------------------------------------
//                                                             scan_keyboard
//--------------------------------------------------------------------------
void
scan_keyboard(void)
{
    UINT8 mask;
    UINT8 column_index;
    UINT8 current_key_state[COLUMNS];

#ifdef KEYBOARD_FAST_SCAN
    UINT8 lo_col = 0x00;
    UINT8 mid_col = 0x00;
    UINT8 hi_col = 0x00;

    // Drive the KB Rows low
    KB_ROW_PORT = 0x00;

    // Set the KB Columns high (pull-up Resistor)
    KB_LOW_COL_PORT = COL1_MASK | COL2_MASK | COL3_MASK | COL4_MASK |
                      COL5_MASK | COL6_MASK | COL7_MASK | COL8_MASK;
    KB_MID_COL_PORT =  COL9_MASK | COL10_MASK | COL11_MASK | COL12_MASK |
                      COL13_MASK | COL14_MASK | COL15_MASK | COL16_MASK;
    KB_HI_COL_PORT = COL17_MASK | COL18_MASK;
    
    // Wait 10uS
    timer_delay_10_usec();

    // Read Columns
    lo_col = ~KB_LOW_COL_PORT;
    mid_col = ~KB_MID_COL_PORT;
    hi_col = ~KB_HI_COL_PORT;

    // Set the KB Column values to low 
    KB_LOW_COL_PORT = 0;
    KB_MID_COL_PORT = 0;
    KB_HI_COL_PORT = 0;

    // Set the KB Rows high (pull-up Resistor)
    KB_ROW_PORT = 0xFF;
#endif

    // Change Columns to High-z
    KB_LOW_COL_PORT_DM0 = 0x0;
    KB_MID_COL_PORT_DM0 = 0x0;
    KB_HI_COL_PORT_DM0  = KB_HI_COL_PORT_DRV0 & ~(COL17_MASK | COL18_MASK);

    // Loop through Columns
    for (column_index = 0; column_index < COLUMNS; ++column_index)
    {
#ifdef KEYBOARD_FAST_SCAN
        current_key_state[column_index] = 0x00;
#endif
        if (column_index < 8)
        {
            // Columns 1 - 8
            mask = 0x1 << column_index;

#ifdef KEYBOARD_FAST_SCAN
            // Check prescan
            if (lo_col & mask)
#endif
            {
                // Drive Column low
                KB_LOW_COL_PORT_DM0 = mask;         
    
                // Wait 10uS
                timer_delay_10_usec();

                // Read Row
                current_key_state[column_index] = ~KB_ROW_PORT;
    
                // Change Column back to High-z
                KB_LOW_COL_PORT_DM0 = 0x0;
            }
        }
        else if (column_index < 16)
        {
            // Columns 9 - 16
            mask = 0x1 << (column_index - 8);

#ifdef KEYBOARD_FAST_SCAN
            // Check prescan
            if (mid_col & mask)
#endif
            {
                // Drive Column low
                KB_MID_COL_PORT_DM0 = mask;         
    
                // Wait 10uS
                timer_delay_10_usec();

                // Read Row
                current_key_state[column_index] = ~KB_ROW_PORT;
    
                // Change Column back to High-z
                KB_MID_COL_PORT_DM0 = 0x0;
            }
        }
        else
        {
            // Columns 17 and 18
            mask = 0x1 << (column_index - 16);

#ifdef KEYBOARD_FAST_SCAN
            // Check prescan
            if (hi_col & mask)
#endif
            {
                // Drive Column low
                KB_HI_COL_PORT_DM0 = mask;          
    
                // Wait 10uS
                timer_delay_10_usec();

                // Read Row
                current_key_state[column_index] = ~KB_ROW_PORT;
    
                // Change Column back to High-z
                KB_HI_COL_PORT_DM0  = KB_HI_COL_PORT_DRV0 & ~(COL17_MASK | COL18_MASK);
            }
        }
    }   

    // Change Columns back to resistive pullup
    KB_LOW_COL_PORT_DM0 = KB_LOW_COL_PORT_DRV0;
    KB_MID_COL_PORT_DM0 = KB_MID_COL_PORT_DRV0;
    KB_HI_COL_PORT_DM0  = KB_HI_COL_PORT_DRV0;

    mask = KB_ROW_PORT;

#ifdef KEYBOARD_TEST_MODES
    // Check for both right and left CTRL and ALT keys
    if (((current_key_state[ALT_COL] & ALT_ROW_MASK) == ALT_ROW_MASK) &&
        ((current_key_state[CTRL_COL] & CTRL_ROW_MASK) == CTRL_ROW_MASK))
    {
        // Check for "F1" to enable the pangram test mode
        if (current_key_state[F1_COL] & F1_ROW_MASK)
        {
            if (test_mode == TEST_OFF)
            {
                // Turn pangram test mode on
                test_mode = TEST_PANGRAM;
            }

            // Clear key
            current_key_state[F1_COL] &= ~F1_ROW_MASK;
        }
    
        // Check for "F3" to enable the fixed character test mode
        if (current_key_state[F3_COL] & F3_ROW_MASK)
        {
            if (test_mode == TEST_OFF)
            {
                // Turn fixed character test mode on
                test_mode = TEST_FIXED_CHAR;
            }

            // Clear key
            current_key_state[F3_COL] &= ~F3_ROW_MASK;
        }

        // Check for "F2" key to disable the test modes
        if (current_key_state[F2_COL] & F2_ROW_MASK)
        {
            // Turn test modes off
            test_mode |= TEST_QUIT;
    
            // Clear key
            current_key_state[F2_COL] &= ~F2_ROW_MASK;
        }
    }

    // Check for "Escape" key to disable the test modes
    if (test_mode != TEST_OFF)
    {
        if (current_key_state[ESC_COL] & ESC_ROW_MASK)
        {
            // Turn test modes off
            test_mode |= TEST_QUIT;
    
            // Clear key
            current_key_state[ESC_COL] &= ~ESC_ROW_MASK;
        }
    }   

    // Process the newly read key map
    if (!test_modes())
#endif //KEYBOARD_TEST_MODES
    {
        for (column_index = 0; column_index < COLUMNS; ++column_index)
        {
            process_column(column_index, &current_key_state[0]);

            if (hid.prior_key_state[column_index] != 0x00)
            {
                hid.status |= KEY_DOWN;
                hid.status &= ~KEYBOARD_SLEEP;
            }
        }
    }
}


//--------------------------------------------------------------------------
//                                                             keyboard_init
//--------------------------------------------------------------------------
void
keyboard_init(void)
{
    UINT8   col;

    // Initialize isr routine
    isr_init();
    
    // Initialize tick timer
    timer_init();
    
    // Initialize Bind button
    RADIO_PORT |= SW1_MASK;

    // Set the KB Rows high (pull-up Resistor)
    KB_ROW_PORT = ROW1_MASK | ROW2_MASK | ROW3_MASK | ROW4_MASK |
                  ROW5_MASK | ROW6_MASK | ROW7_MASK | ROW8_MASK;
    
    // Drive the KB Columns low 
    KB_LOW_COL_PORT = 0;
    KB_MID_COL_PORT = 0;
    KB_HI_COL_PORT = 0;

    // reset the saved state
    for (col = 0; col < COLUMNS; ++col)
    {
        hid.prior_key_state[col] = 0x00;
    }
    
    //---- Setup keyboard initial state --------------------------
    // intialize keyboard locals
    key_queue_init();

    // Initialize debounce queue    
    debounce_init();

    // Initialize keyboard status
    hid.status = 0x0;

    // Initialize Protocol
    protocol_init();

    // Get transfer packet
    report_packet = (APP_TX_PACKET *)protocol_get_tx_pkt();

#ifdef MFG_ENTER_BY_KEY_NOT_PINTEST_CODE
#ifdef MFG_ENTER_BY_PIN

    // Check for Manufacturing Pin
    MFG_PIN_CHECK();
#else
    // Change Columns to High-z
    KB_LOW_COL_PORT_DM0 = 0x0;
    KB_MID_COL_PORT_DM0 = 0x0;
    KB_HI_COL_PORT_DM0  = KB_HI_COL_PORT_DRV0 & ~(COL17_MASK | COL18_MASK);

    col = SLEEP_COL;

    // Check for system sleep key
    if (col < 8)
    {
        // Drive Column low
        KB_LOW_COL_PORT_DM0 = 0x1 << col;

        // Wait 10uS
        timer_delay_10_usec();

        // Read Row
        col = ~KB_ROW_PORT;

        // Change Column back to High-z
        KB_LOW_COL_PORT_DM0 = 0x0;
    }
    else if (col < 16)
    {
        // Drive Column low
        KB_MID_COL_PORT_DM0 = 0x1 << (col - 8);

        // Wait 10uS
        timer_delay_10_usec();
    
        // Read Row
        col = ~KB_ROW_PORT;
    
        // Change Column back to High-z
        KB_MID_COL_PORT_DM0 = 0x0;
    }
    else
    {
        // Drive Column low
        KB_HI_COL_PORT_DM0 = 0x1 << (col - 16);

        // Wait 10uS
        timer_delay_10_usec();

        // Read Row
        col = ~KB_ROW_PORT;

        // Change Column back to High-z
        KB_HI_COL_PORT_DM0  = KB_HI_COL_PORT_DRV0 & ~(COL17_MASK | COL18_MASK);
    }

    // Change Columns back to resistive pullup
    KB_LOW_COL_PORT_DM0 = KB_LOW_COL_PORT_DRV0;
    KB_MID_COL_PORT_DM0 = KB_MID_COL_PORT_DRV0;
    KB_HI_COL_PORT_DM0  = KB_HI_COL_PORT_DRV0;

    // Check for bind button and system sleep key on power up
    if ((SW1_MASK & ~RADIO_PORT) && (col & SLEEP_ROW_MASK))
    {
        // Manufacturing test (Does not return)
        MFG_TEST();
    }

#else
    // Check for Manufacturing Pin
    MFG_PIN_CHECK();
#endif //MFG_ENTER_BY_PIN
#endif //MFG_TEST_CODE

#ifdef KEYBOARD_POWER_ON_BIND
    {
        SYS_PARAMETERS systmp;

        NVRAM_READ( &systmp, sizeof(SYS_PARAMETERS) );

        if (systmp.networkId.signature != SIGNATURE_BYTE) 
        {
            hid.status |= BIND_BUTTON;
        }
    }
#endif

    // Enable bind interrupt
    ISR_ENABLE(GPIO_ISR_BIND_IE_PORT, GPIO_ISR_BIND_INT);
}


//--------------------------------------------------------------------------
//                                                                    main
//--------------------------------------------------------------------------

void
main(void)
{
    // Keyboard Initialization
    keyboard_init();

    // Initialize last transfer time stamp
    last_transfer_ts = timer_get_time_stamp();

    // Main loop
    for(;;)
    {
        // Disable key interrupt
        ISR_DISABLE(GPIO_ISR_KEYS_IE_PORT, GPIO_ISR_KEYS_INT);

        // Disable Sleep interrupt mask
        M8C_DisableIntMask(INT_MSK0, INT_MSK0_SLEEP);

        // Clear Watchdog and Sleep
        M8C_ClearWDTAndSleep;

        hid.status &= ~KEY_DOWN;
        hid.status |= KEYBOARD_SLEEP;

        // Get current timestamp
        ts = timer_get_time_stamp();

#ifndef BIND_BASIC
        // Check for bind button
        if ( hid.status & BIND_BUTTON )
        {
            // Call protocol bind
            // Note:  This routine can take 5 or more seconds.
            protocol_bind();

            // Clear bind flag
            hid.status &= ~BIND_BUTTON;
        }
#endif // BIND_BASIC

        // Scan Keyboard
        scan_keyboard();

        //---------------------------------------- Generate Report
        generate_reports();
#if 0
        if( generate_reports() )
        {
            // Set last transfer time stamp
            last_transfer_ts = timer_get_time_stamp();
        }
#endif
        
        //--------------------------------------------- Keep Alive
        if ( hid.status & KEY_DOWN )
        {
            // Determine if it is necessary to send a Keep Alive
            if (timer_time_elapsed(last_transfer_ts, KEYBOARD_KEEP_ALIVE_TIMEOUT))
            {
                // Generate keep alive
                generate_alive_packet();
    
#ifdef KEYBOARD_BATTERY_VOLTAGE_SUPPORT
    
                // Build and send Battery Voltage report
                generate_batt_report();
    
#endif // KEYBOARD_BATTERY_VOLTAGE_SUPPORT
    
                // Prevent "Tick" rollover by turning the timer on/off
                ts = 0;
                last_transfer_ts = 0;
                timer_timer_off();
                timer_timer_on();
            }
        }

        // age the debounce queue
        age_debounce_queue();

        // Enable Sleep interrupt mask
        M8C_EnableIntMask(INT_MSK0, INT_MSK0_SLEEP);

        // Enable key interrupt before trying to sleep
        ISR_ENABLE(GPIO_ISR_KEYS_IE_PORT, GPIO_ISR_KEYS_INT);

        // Try to sleep between down keys
        if (( hid.status & KEYBOARD_SLEEP ) && 
            !( hid.status & (GENERATE_STD_REPORT | GENERATE_HOT_REPORT | GENERATE_PWR_REPORT) ))
        {
            // Disable timer
            timer_timer_off();

            // Clear transfer time stamp
            last_transfer_ts = 0;

            // Sleep until an interrupt (key press)
            while ( hid.status & KEYBOARD_SLEEP)
            {
                // Clear Watchdog and Sleep
                M8C_ClearWDTAndSleep;

                // Sleep
                M8C_Sleep;
                asm("nop");
            }

            // Enable timer
            timer_timer_on();
        }
        else
        {
#ifdef KEYBOARD_TEST_MODES
            if (test_mode != TEST_OFF)
            {
                // Sleep until sample period expires
                timer_delay_incremental( ts, KEYBOARD_TEST_MODE_PERIOD );

                // Prevent "Tick" rollover by turning the timer on/off
                last_transfer_ts = 0;
                timer_timer_off();
                timer_timer_on();
            }
            else
#endif //KEYBOARD_TEST_MODES
            {
                // Sleep until sample period expires
                timer_delay_incremental( ts, KEY_DOWN_DELAY_SAMPLE_PERIOD );
            }
        }
    }
}