//***************************************************************************** // // keyboard_ui.c - The DK-TM4C129X USB keyboard application UI. // // Copyright (c) 2013-2014 Texas Instruments Incorporated. All rights reserved. // Software License Agreement // // Texas Instruments (TI) is supplying this software for use solely and // exclusively on TI's microcontroller products. The software is owned by // TI and/or its suppliers, and is protected under applicable copyright // laws. You may not combine this software with "viral" open-source // software in order to form a larger program. // // THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS. // NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT // NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR // A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY // CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL // DAMAGES, FOR ANY REASON WHATSOEVER. // // This is part of revision 2.1.0.12573 of the DK-TM4C129X Firmware Package. // //***************************************************************************** #include #include #include #include "grlib/grlib.h" #include "usblib/usblib.h" #include "usblib/usbhid.h" #include "usblib/host/usbhost.h" #include "drivers/frame.h" #include "drivers/kentec320x240x16_ssd2119.h" #include "keyboard_ui.h" //***************************************************************************** // // These defines are used to define the screen constraints to the application. // //***************************************************************************** #define DISPLAY_BANNER_HEIGHT 18 #define DISPLAY_TEXT_BORDER 8 #define DISPLAY_TEXT_BORDER_H 8 #define BUTTON_HEIGHT 18 //***************************************************************************** // // This is the number of characters that will fit on a line in the text area. // //***************************************************************************** uint32_t g_ui32CharsPerLine; //***************************************************************************** // // This is the number of lines that will fit in the text area. // //***************************************************************************** uint32_t g_ui32LinesPerScreen; //***************************************************************************** // // This is the current column for printing in the text area. // //***************************************************************************** uint32_t g_ui32Column; //***************************************************************************** // // Define the maximum number of lines and columns in the command windows. // //***************************************************************************** #define MAX_LINES 23 #define MAX_COLUMNS 60 //***************************************************************************** // // The variables that are used to allow the screen to scroll. // //***************************************************************************** static char g_ppcLines[MAX_LINES][MAX_COLUMNS]; static uint32_t g_ui32CurrentLine; uint32_t g_ui32EntryLine; //***************************************************************************** // // Graphics context used to show text on the CSTN display. // //***************************************************************************** tContext g_sContext; //***************************************************************************** // // Draws the prompt for each new line. // //***************************************************************************** static void DrawPrompt(void) { int32_t i32Idx; g_ppcLines[g_ui32CurrentLine][0] = '>'; for(i32Idx = 1; i32Idx < MAX_COLUMNS - 1; i32Idx++) { g_ppcLines[g_ui32CurrentLine][i32Idx] = ' '; } g_ppcLines[g_ui32CurrentLine][i32Idx] = 0; GrStringDraw(&g_sContext, g_ppcLines[g_ui32CurrentLine], MAX_COLUMNS, DISPLAY_TEXT_BORDER_H + (GrFontMaxWidthGet(g_psFontFixed6x8) * g_ui32Column), DISPLAY_BANNER_HEIGHT + DISPLAY_TEXT_BORDER + (g_ui32EntryLine * GrFontHeightGet(g_psFontFixed6x8)), true); g_ui32Column = 2; } //***************************************************************************** // // Initialize the application interface. // //***************************************************************************** void UIInit(uint32_t ui32SysClock) { // // Initialize the display driver. // Kentec320x240x16_SSD2119Init(ui32SysClock); // // Initialize the graphics context. // GrContextInit(&g_sContext, &g_sKentec320x240x16_SSD2119); // // Draw the application frame. // FrameDraw(&g_sContext, "usb-host-keyboard"); // // Set the font for the application. // GrContextFontSet(&g_sContext, g_psFontFixed6x8); // // Calculate the number of characters that will fit on a line. // Make sure to leave a small border for the text box. // g_ui32CharsPerLine = (GrContextDpyWidthGet(&g_sContext) - 16) / GrFontMaxWidthGet(g_psFontFixed6x8); // // Calculate the number of lines per usable text screen. This requires // taking off space for the top and bottom banners and adding a small bit // for a border. // g_ui32LinesPerScreen = (GrContextDpyHeightGet(&g_sContext) - (2*(DISPLAY_BANNER_HEIGHT + 1)) - BUTTON_HEIGHT) / GrFontHeightGet(g_psFontFixed6x8); // // Set up the text scrolling variables. // g_ui32CurrentLine = 0; g_ui32EntryLine = 0; // // Draw the initial prompt on the screen. // DrawPrompt(); // // Initial update of the screen. // UIUpdateStatus(); } //***************************************************************************** // // Handles scrolling the text on the screen. // //***************************************************************************** static void ScrollText(void) { int32_t i32Idx; uint32_t ui32Line, ui32Start; ui32Line = 0; // // Skip the oldest entry in the circular list. // if(g_ui32CurrentLine == (MAX_LINES - 1)) { // // If at the end of the list wrap to entry 1. // ui32Start = 1; } else { // // The oldest is 1 in front of the most recent. // ui32Start = g_ui32CurrentLine + 2; } // // Print lines from the current position down first. // for(i32Idx = ui32Start; i32Idx < MAX_LINES; i32Idx++) { GrStringDraw(&g_sContext, g_ppcLines[i32Idx], strlen(g_ppcLines[i32Idx]), DISPLAY_TEXT_BORDER_H, DISPLAY_BANNER_HEIGHT + DISPLAY_TEXT_BORDER + (ui32Line * GrFontHeightGet(g_psFontFixed6x8)), 1); ui32Line++; } // // If not the special case of the last line where everything has already // printed, print the remaining lines. // if(g_ui32CurrentLine != (MAX_LINES - 1)) { for(i32Idx = 0; i32Idx <= g_ui32CurrentLine; i32Idx++) { GrStringDraw(&g_sContext, g_ppcLines[i32Idx], strlen(g_ppcLines[i32Idx]), DISPLAY_TEXT_BORDER_H, DISPLAY_BANNER_HEIGHT + DISPLAY_TEXT_BORDER + (ui32Line * GrFontHeightGet(g_psFontFixed6x8)), 1); ui32Line++; } } // // Reset the column to zero. // g_ui32Column = 0; } //***************************************************************************** // // This function prints the character out the screen and into the command // buffer. // // ucChar is the character to print out. // // This function handles all of the detail of printing a character to the // screen and into the command line buffer. // // No return value. // //***************************************************************************** void UIPrintChar(const char cChar) { bool bNewLine; int32_t i32Idx; GrContextForegroundSet(&g_sContext, ClrWhite); bNewLine = true; // // Allow new lines to cause the column to go back to zero. // if(cChar != '\n') { // // Handle when receiving a backspace character. // if(cChar != ASCII_BACKSPACE) { // // This is not a backspace so print the character to the screen. // GrStringDraw(&g_sContext, &cChar, 1, DISPLAY_TEXT_BORDER_H + (GrFontMaxWidthGet(g_psFontFixed6x8) * g_ui32Column), DISPLAY_BANNER_HEIGHT + DISPLAY_TEXT_BORDER + (g_ui32EntryLine * GrFontHeightGet(g_psFontFixed6x8)), 1); g_ppcLines[g_ui32CurrentLine][g_ui32Column] = cChar; if(g_ui32Column < g_ui32CharsPerLine) { // // No line wrap yet so move one column over. // g_ui32Column++; bNewLine = false; } } else { // // We got a backspace. If we are at the top left of the screen, // return since we don't need to do anything. // if(g_ui32Column || g_ui32EntryLine) { // // Adjust the cursor position to erase the last character. // if(g_ui32Column > 2) { g_ui32Column--; } // // Print a space at this position then return without fixing up // the cursor again. // GrStringDraw(&g_sContext, " ", 1, DISPLAY_TEXT_BORDER_H + (GrFontMaxWidthGet(g_psFontFixed6x8) * g_ui32Column), DISPLAY_BANNER_HEIGHT + DISPLAY_TEXT_BORDER + (g_ui32EntryLine * GrFontHeightGet(g_psFontFixed6x8)), true); g_ppcLines[g_ui32CurrentLine][g_ui32Column] = ' '; } bNewLine = false; } } // // . // if(bNewLine) { g_ui32Column = 0; if(g_ui32EntryLine < (MAX_LINES - 1)) { g_ui32EntryLine++; } else { ScrollText(); } g_ui32CurrentLine++; // // The line has gone past the end so go back to the first line. // if(g_ui32CurrentLine >= MAX_LINES) { g_ui32CurrentLine = 0; } // // Add a prompt to the new line. // if(cChar == '\n') { DrawPrompt(); } else { // // Clear out the current line. // for(i32Idx = 0; i32Idx < MAX_COLUMNS - 1; i32Idx++) { g_ppcLines[g_ui32CurrentLine][i32Idx] = ' '; } g_ppcLines[g_ui32CurrentLine][i32Idx] = 0; GrStringDraw(&g_sContext, g_ppcLines[g_ui32CurrentLine], strlen(g_ppcLines[g_ui32CurrentLine]), DISPLAY_TEXT_BORDER_H, DISPLAY_BANNER_HEIGHT + DISPLAY_TEXT_BORDER + (g_ui32EntryLine * GrFontHeightGet(g_psFontFixed6x8)), 1); } } } //***************************************************************************** // // Update one of the status boxes at the bottom of the screen. // //***************************************************************************** static void UpdateStatusBox(const tRectangle *psRect, const char *pcString, bool bActive) { uint32_t ui32TextColor; // // Change the status box to green for active devices. // if(bActive) { GrContextForegroundSet(&g_sContext, ClrOrange); ui32TextColor = ClrBlack; } else { GrContextForegroundSet(&g_sContext, ClrBlack); ui32TextColor = ClrWhite; } // // Draw the background box. // GrRectFill(&g_sContext, psRect); // // Put a white box around the banner. // GrContextForegroundSet(&g_sContext, ClrWhite); // // Draw the box border. // GrRectDraw(&g_sContext, psRect); // // Put a white box around the banner. // GrContextForegroundSet(&g_sContext, ui32TextColor); // // Unknown device is currently connected. // GrStringDrawCentered(&g_sContext, pcString, -1, psRect->i16XMin + ((psRect->i16XMax - psRect->i16XMin) / 2), psRect->i16YMin + (BUTTON_HEIGHT / 2), false); } //***************************************************************************** // // This function updates the status area of the screen. It uses the current // state of the application to print the status bar. // //***************************************************************************** void UIUpdateStatus(void) { uint8_t ui8DevClass, ui8DevProtocol; static const tRectangle psRect[4] = { { DISPLAY_TEXT_BORDER_H, 240 - 10 - BUTTON_HEIGHT, DISPLAY_TEXT_BORDER_H + 124, 240 - 10 }, { DISPLAY_TEXT_BORDER_H + 124, 240 - 10 - BUTTON_HEIGHT, DISPLAY_TEXT_BORDER_H + 184, 240 - 10 }, { DISPLAY_TEXT_BORDER_H + 184, 240 - 10 - BUTTON_HEIGHT, DISPLAY_TEXT_BORDER_H + 244, 240 - 10 }, { DISPLAY_TEXT_BORDER_H + 244, 240 - 10 - BUTTON_HEIGHT, DISPLAY_TEXT_BORDER_H + 303, 240 - 10 }, }; // // Put the application name in the middle of the banner. // GrContextFontSet(&g_sContext, g_psFontFixed6x8); // // Default the protocol to none so that non-HID devices do not update // the keyboard modifiers. // ui8DevProtocol = USB_HID_PROTOCOL_NONE; if(g_sStatus.bConnected) { ui8DevClass = USBHCDDevClass(g_sStatus.ui32Instance, 0); ui8DevProtocol = USBHCDDevProtocol(g_sStatus.ui32Instance, 0); if(ui8DevClass == USB_CLASS_HID) { if(ui8DevProtocol == USB_HID_PROTOCOL_MOUSE) { // // Mouse is currently connected. // UpdateStatusBox(&psRect[0], "Mouse", true); } else if(ui8DevProtocol == USB_HID_PROTOCOL_KEYB) { // // Keyboard is currently connected. // UpdateStatusBox(&psRect[0], "Keyboard", true); } else { // // Unknown device is currently connected. // UpdateStatusBox(&psRect[0], "Unknown", true); } } else if(ui8DevClass == USB_CLASS_MASS_STORAGE) { // // MSC device is currently connected. // UpdateStatusBox(&psRect[0], "Mass Storage", true); } else if(ui8DevClass == USB_CLASS_HUB) { // // MSC device is currently connected. // UpdateStatusBox(&psRect[0], "Hub", true); } else { // // Unknown device is currently connected. // UpdateStatusBox(&psRect[0], "Unknown", true); } } else { // // Unknown device is currently connected. // UpdateStatusBox(&psRect[0], "No Device", false); } if(ui8DevProtocol == USB_HID_PROTOCOL_KEYB) { if(g_sStatus.ui32Modifiers & HID_KEYB_CAPS_LOCK) { UpdateStatusBox(&psRect[1], "CAPS", true); } else { UpdateStatusBox(&psRect[1], "caps", false); } if(g_sStatus.ui32Modifiers & HID_KEYB_SCROLL_LOCK) { UpdateStatusBox(&psRect[2], "SCROLL", true); } else { UpdateStatusBox(&psRect[2], "scroll", false); } if(g_sStatus.ui32Modifiers & HID_KEYB_NUM_LOCK) { UpdateStatusBox(&psRect[3], "NUM", true); } else { UpdateStatusBox(&psRect[3], "num", false); } } else { UpdateStatusBox(&psRect[1], "caps", false); UpdateStatusBox(&psRect[2], "scroll", false); UpdateStatusBox(&psRect[3], "num", false); } }