From c3e4c9a25c2910d2d66d52215b3406b13d5b23d5 Mon Sep 17 00:00:00 2001 From: Yuval Adam Date: Sun, 29 Jun 2014 12:34:32 +0300 Subject: Add more board models --- boards/ek-lm4f232/drivers/buttons.c | 186 ++++ boards/ek-lm4f232/drivers/buttons.h | 103 ++ boards/ek-lm4f232/drivers/cfal96x64x16.c | 816 +++++++++++++++ boards/ek-lm4f232/drivers/cfal96x64x16.h | 37 + boards/ek-lm4f232/drivers/slidemenuwidget.c | 1424 ++++++++++++++++++++++++++ boards/ek-lm4f232/drivers/slidemenuwidget.h | 457 +++++++++ boards/ek-lm4f232/drivers/stripchartwidget.c | 672 ++++++++++++ boards/ek-lm4f232/drivers/stripchartwidget.h | 392 +++++++ boards/ek-lm4f232/drivers/usb_sound.c | 804 +++++++++++++++ boards/ek-lm4f232/drivers/usb_sound.h | 81 ++ 10 files changed, 4972 insertions(+) create mode 100644 boards/ek-lm4f232/drivers/buttons.c create mode 100644 boards/ek-lm4f232/drivers/buttons.h create mode 100644 boards/ek-lm4f232/drivers/cfal96x64x16.c create mode 100644 boards/ek-lm4f232/drivers/cfal96x64x16.h create mode 100644 boards/ek-lm4f232/drivers/slidemenuwidget.c create mode 100644 boards/ek-lm4f232/drivers/slidemenuwidget.h create mode 100644 boards/ek-lm4f232/drivers/stripchartwidget.c create mode 100644 boards/ek-lm4f232/drivers/stripchartwidget.h create mode 100644 boards/ek-lm4f232/drivers/usb_sound.c create mode 100644 boards/ek-lm4f232/drivers/usb_sound.h (limited to 'boards/ek-lm4f232/drivers') diff --git a/boards/ek-lm4f232/drivers/buttons.c b/boards/ek-lm4f232/drivers/buttons.c new file mode 100644 index 0000000..9dc9ce9 --- /dev/null +++ b/boards/ek-lm4f232/drivers/buttons.c @@ -0,0 +1,186 @@ +//***************************************************************************** +// +// buttons.c - Evaluation board driver for push buttons. +// +// Copyright (c) 2011-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 EK-LM4F232 Firmware Package. +// +//***************************************************************************** + +#include +#include +#include +#include "driverlib/gpio.h" +#include "driverlib/pin_map.h" +#include "driverlib/rom_map.h" +#include "driverlib/sysctl.h" +#include "inc/hw_types.h" +#include "inc/hw_memmap.h" +#include "buttons.h" + +//***************************************************************************** +// +//! \addtogroup buttons_api +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// Holds the current, debounced state of each button. A 0 in a bit indicates +// that that button is currently pressed, otherwise it is released. +// We assume that we start with all the buttons released (though if one is +// pressed when the application starts, this will be detected). +// +//***************************************************************************** +static uint8_t g_ui8ButtonStates = ALL_BUTTONS; + +//***************************************************************************** +// +//! Polls the current state of the buttons and determines which have changed. +//! +//! \param pui8Delta points to a character that will be written to indicate +//! which button states changed since the last time this function was called. +//! This value is derived from the debounced state of the buttons. +//! \param pui8RawState points to a location where the raw button state will +//! be stored. +//! +//! This function should be called periodically by the application to poll the +//! pushbuttons. It determines both the current debounced state of the buttons +//! and also which buttons have changed state since the last time the function +//! was called. +//! +//! In order for button debouncing to work properly, this function should be +//! caled at a regular interval, even if the state of the buttons is not needed +//! that often. +//! +//! If button debouncing is not required, the the caller can pass a pointer +//! for the \e pui8RawState parameter in order to get the raw state of the +//! buttons. The value returned in \e pui8RawState will be a bit mask where +//! a 1 indicates the buttons is pressed. +//! +//! \return Returns the current debounced state of the buttons where a 1 in the +//! button ID's position indicates that the button is pressed and a 0 +//! indicates that it is released. +// +//***************************************************************************** +uint8_t +ButtonsPoll(uint8_t *pui8Delta, uint8_t *pui8RawState) +{ + uint32_t ui32Delta; + uint32_t ui32Data; + static uint8_t ui8SwitchClockA = 0; + static uint8_t ui8SwitchClockB = 0; + + // + // Read the raw state of the push buttons. Save the raw state + // (inverting the bit sense) if the caller supplied storage for the + // raw value. + // + ui32Data = (MAP_GPIOPinRead(BUTTONS_GPIO_BASE, ALL_BUTTONS)); + if(pui8RawState) + { + *pui8RawState = (uint8_t)~ui32Data; + } + + // + // Determine the switches that are at a different state than the debounced + // state. + // + ui32Delta = ui32Data ^ g_ui8ButtonStates; + + // + // Increment the clocks by one. + // + ui8SwitchClockA ^= ui8SwitchClockB; + ui8SwitchClockB = ~ui8SwitchClockB; + + // + // Reset the clocks corresponding to switches that have not changed state. + // + ui8SwitchClockA &= ui32Delta; + ui8SwitchClockB &= ui32Delta; + + // + // Get the new debounced switch state. + // + g_ui8ButtonStates &= ui8SwitchClockA | ui8SwitchClockB; + g_ui8ButtonStates |= (~(ui8SwitchClockA | ui8SwitchClockB)) & ui32Data; + + // + // Determine the switches that just changed debounced state. + // + ui32Delta ^= (ui8SwitchClockA | ui8SwitchClockB); + + // + // Store the bit mask for the buttons that have changed for return to + // caller. + // + if(pui8Delta) + { + *pui8Delta = (uint8_t)ui32Delta; + } + + // + // Return the debounced buttons states to the caller. Invert the bit + // sense so that a '1' indicates the button is pressed, which is a + // sensible way to interpret the return value. + // + return(~g_ui8ButtonStates); +} + +//***************************************************************************** +// +//! Initializes the GPIO pins used by the board pushbuttons. +//! +//! This function must be called during application initialization to +//! configure the GPIO pins to which the pushbuttons are attached. It enables +//! the port used by the buttons and configures each button GPIO as an input +//! with a weak pull-up. +//! +//! \return None. +// +//***************************************************************************** +void +ButtonsInit(void) +{ + // + // Enable the GPIO port to which the pushbuttons are connected. + // + MAP_SysCtlPeripheralEnable(BUTTONS_GPIO_PERIPH); + + // + // Set each of the button GPIO pins as an input with a pull-up. + // + MAP_GPIODirModeSet(BUTTONS_GPIO_BASE, ALL_BUTTONS, GPIO_DIR_MODE_IN); + MAP_GPIOPadConfigSet(BUTTONS_GPIO_BASE, ALL_BUTTONS, + GPIO_STRENGTH_2MA, GPIO_PIN_TYPE_STD_WPU); + + // + // Initialize the debounced button state with the current state read from + // the GPIO bank. + // + g_ui8ButtonStates = MAP_GPIOPinRead(BUTTONS_GPIO_BASE, ALL_BUTTONS); +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/boards/ek-lm4f232/drivers/buttons.h b/boards/ek-lm4f232/drivers/buttons.h new file mode 100644 index 0000000..fa52fa4 --- /dev/null +++ b/boards/ek-lm4f232/drivers/buttons.h @@ -0,0 +1,103 @@ +//***************************************************************************** +// +// buttons.h - Prototypes for the evaluation board buttons driver. +// +// Copyright (c) 2011-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 EK-LM4F232 Firmware Package. +// +//***************************************************************************** + +#ifndef __BUTTONS_H__ +#define __BUTTONS_H__ + +//***************************************************************************** +// +// Defines for the hardware resources used by the pushbuttons. +// +// The switches are on the following ports/pins: +// +// PM0 - Up +// PM1 - Down +// PM2 - Left +// PM3 - Right +// PM4 - Select/Wake +// +// The switches tie the GPIO to ground, so the GPIOs need to be configured +// with pull-ups, and a value of 0 means the switch is pressed. +// +//***************************************************************************** +#define BUTTONS_GPIO_PERIPH SYSCTL_PERIPH_GPIOM +#define BUTTONS_GPIO_BASE GPIO_PORTM_BASE + +#define NUM_BUTTONS 5 +#define UP_BUTTON GPIO_PIN_0 +#define DOWN_BUTTON GPIO_PIN_1 +#define LEFT_BUTTON GPIO_PIN_2 +#define RIGHT_BUTTON GPIO_PIN_3 +#define SELECT_BUTTON GPIO_PIN_4 + +#define ALL_BUTTONS (LEFT_BUTTON | RIGHT_BUTTON | UP_BUTTON | \ + DOWN_BUTTON | SELECT_BUTTON) + +//***************************************************************************** +// +// Useful macros for detecting button events. +// +//***************************************************************************** +#define BUTTON_PRESSED(button, buttons, changed) \ + (((button) & (changed)) && ((button) & (buttons))) + +#define BUTTON_RELEASED(button, buttons, changed) \ + (((button) & (changed)) && !((button) & (buttons))) + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +// Functions exported from buttons.c +// +//***************************************************************************** +extern void ButtonsInit(void); +extern uint8_t ButtonsPoll(uint8_t *pui8Delta, + uint8_t *pui8Raw); + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +//***************************************************************************** +// +// Prototypes for the globals exported by this driver. +// +//***************************************************************************** + +#endif // __BUTTONS_H__ diff --git a/boards/ek-lm4f232/drivers/cfal96x64x16.c b/boards/ek-lm4f232/drivers/cfal96x64x16.c new file mode 100644 index 0000000..1036643 --- /dev/null +++ b/boards/ek-lm4f232/drivers/cfal96x64x16.c @@ -0,0 +1,816 @@ +//***************************************************************************** +// +// cfal96x64x16.c - Display driver for the Crystalfontz CFAL9664-F-B1 OLED +// display with an SSD1332. This version uses an SSI +// interface to the display controller. +// +// Copyright (c) 2011-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 EK-LM4F232 Firmware Package. +// +//***************************************************************************** + +//***************************************************************************** +// +//! \addtogroup display_api +//! @{ +// +//***************************************************************************** + +#include +#include +#include "inc/hw_memmap.h" +#include "driverlib/gpio.h" +#include "driverlib/ssi.h" +#include "driverlib/sysctl.h" +#include "driverlib/rom.h" +#include "driverlib/pin_map.h" +#include "grlib/grlib.h" +#include "drivers/cfal96x64x16.h" + +//***************************************************************************** +// +// Defines the SSI and GPIO peripherals that are used for this display. +// +//***************************************************************************** +#define DISPLAY_SSI_PERIPH SYSCTL_PERIPH_SSI2 +#define DISPLAY_SSI_GPIO_PERIPH SYSCTL_PERIPH_GPIOH +#define DISPLAY_RST_GPIO_PERIPH SYSCTL_PERIPH_GPIOG + +//***************************************************************************** +// +// Defines the GPIO pin configuration macros for the pins that are used for +// the SSI function. +// +//***************************************************************************** +#define DISPLAY_PINCFG_SSICLK GPIO_PH4_SSI2CLK +#define DISPLAY_PINCFG_SSIFSS GPIO_PH5_SSI2FSS +#define DISPLAY_PINCFG_SSITX GPIO_PH7_SSI2TX + +//***************************************************************************** +// +// Defines the port and pins for the SSI peripheral. +// +//***************************************************************************** +#define DISPLAY_SSI_PORT GPIO_PORTH_BASE +#define DISPLAY_SSI_PINS (GPIO_PIN_4 | GPIO_PIN_5 | GPIO_PIN_7) + +//***************************************************************************** +// +// Defines the port and pins for the display voltage enable signal. +// +//***************************************************************************** +#define DISPLAY_ENV_PORT GPIO_PORTG_BASE +#define DISPLAY_ENV_PIN GPIO_PIN_0 + +//***************************************************************************** +// +// Defines the port and pins for the display reset signal. +// +//***************************************************************************** +#define DISPLAY_RST_PORT GPIO_PORTG_BASE +#define DISPLAY_RST_PIN GPIO_PIN_1 + +//***************************************************************************** +// +// Defines the port and pins for the display Data/Command (D/C) signal. +// +//***************************************************************************** +#define DISPLAY_D_C_PORT GPIO_PORTH_BASE +#define DISPLAY_D_C_PIN GPIO_PIN_6 + +//***************************************************************************** +// +// Defines the SSI peripheral used and the data speed. +// +//***************************************************************************** +#define DISPLAY_SSI_BASE SSI2_BASE // SSI2 +#define DISPLAY_SSI_CLOCK 4000000 + +//***************************************************************************** +// +// An array that holds a set of commands that are sent to the display when +// it is initialized. +// +//***************************************************************************** +static +uint8_t g_ui8DisplayInitCommands[] = +{ +// 0xAE, // display off + 0x87, 0x07, // master control current 7/16 + 0x81, 0xA0, // contrast A control + 0x82, 0x60, // contrast B control + 0x83, 0xB0, // contrast C control + 0xA0, 0x20,//00 // remap and data format - use 8-bit color mode + 0xBB, 0x1F, // Vpa + 0xBC, 0x1F, // Vpb + 0xBD, 0x1F, // Vpc +// 0xAD, 0x8E, // internal Vp, external supply + 0x26, 0x01, // rectangle fill enabled + 0xAF // display on +}; +#define NUM_INIT_BYTES sizeof(g_ui8DisplayInitCommands) + +//***************************************************************************** +// +// Translates a 24-bit RGB color to a display driver-specific color. +// +// \param c is the 24-bit RGB color. The least-significant byte is the blue +// channel, the next byte is the green channel, and the third byte is the red +// channel. +// +// This macro translates a 24-bit RGB color into a value that can be written +// into the display's frame buffer in order to reproduce that color, or the +// closest possible approximation of that color. +// +// \return Returns the display-driver specific color. +// +// 24-bit format: XXXX XXXX RRRR RRRR GGGG GGGG BBBB BBBB +// 16-bit format: ---- ---- ---- ---- RRRR RGGG GGGB BBBB +// 8-bit format: ---- ---- ---- ---- ---- ---- RRRG GGBB +// +// +//***************************************************************************** +#define DPYCOLORTRANSLATE16(c) ((((c) & 0x00f80000) >> 8) | \ + (((c) & 0x0000fc00) >> 5) | \ + (((c) & 0x000000f8) >> 3)) +#define DPYCOLORTRANSLATE8(c) ((((c) & 0x00e00000) >> 16) | \ + (((c) & 0x0000e000) >> 11) | \ + (((c) & 0x000000c0) >> 6)) +#define DPYCOLORTRANSLATE DPYCOLORTRANSLATE8 + +//***************************************************************************** +// +//! Write a set of command bytes to the display controller. +// +//! \param pi8Cmd is a pointer to a set of command bytes. +//! \param ui32Count is the count of command bytes. +//! +//! This function provides a way to send multiple command bytes to the display +//! controller. It can be used for single commands, or multiple commands +//! chained together in a buffer. It will wait for any previous operation to +//! finish, and then copy all the command bytes to the controller. It will +//! not return until the last command byte has been written to the SSI FIFO, +//! but data could still be shifting out to the display controller when this +//! function returns. +//! +//! \return None. +// +//***************************************************************************** +static void +CFAL96x64x16WriteCommand(const uint8_t *pi8Cmd, uint32_t ui32Count) +{ + // + // Wait for any previous SSI operation to finish. + // + while(ROM_SSIBusy(DISPLAY_SSI_BASE)) + { + } + + // + // Set the D/C pin low to indicate command + // + ROM_GPIOPinWrite(DISPLAY_D_C_PORT, DISPLAY_D_C_PIN, 0); + + // + // Send all the command bytes to the display + // + while(ui32Count--) + { + ROM_SSIDataPut(DISPLAY_SSI_BASE, *pi8Cmd); + pi8Cmd++; + } +} + +//***************************************************************************** +// +//! Write a set of data bytes to the display controller. +// +//! \param pi8Data is a pointer to a set of data bytes, containing pixel data. +//! \param ui32Count is the count of command bytes. +//! +//! This function provides a way to send a set of pixel data to the display. +//! The data will draw pixels according to whatever the most recent col, row +//! settings are for the display. It will wait for any previous operation to +//! finish, and then copy all the data bytes to the controller. It will +//! not return until the last data byte has been written to the SSI FIFO, +//! but data could still be shifting out to the display controller when this +//! function returns. +//! +//! \return None. +// +//***************************************************************************** +static void +CFAL96x64x16WriteData(const uint8_t *pi8Data, uint32_t ui32Count) +{ + // + // Wait for any previous SSI operation to finish. + // + while(ROM_SSIBusy(DISPLAY_SSI_BASE)) + { + } + + // + // Set the D/C pin high to indicate data + // + ROM_GPIOPinWrite(DISPLAY_D_C_PORT, DISPLAY_D_C_PIN, DISPLAY_D_C_PIN); + + // + // Send all the data bytes to the display + // + while(ui32Count--) + { + ROM_SSIDataPut(DISPLAY_SSI_BASE, *pi8Data); + pi8Data++; + } +} + +//***************************************************************************** +// +//! Draws a pixel on the screen. +//! +//! \param pvDisplayData is a pointer to the driver-specific data for this +//! display driver. +//! \param i32X is the X coordinate of the pixel. +//! \param i32Y is the Y coordinate of the pixel. +//! \param ui32Value is the color of the pixel. +//! +//! This function sets the given pixel to a particular color. The coordinates +//! of the pixel are assumed to be within the extents of the display. +//! +//! \return None. +// +//***************************************************************************** +static void +CFAL96x64x16PixelDraw(void *pvDisplayData, int32_t i32X, int32_t i32Y, + uint32_t ui32Value) +{ + uint8_t ui8Cmd[8]; + + // + // Load column command, start and end column + // + ui8Cmd[0] = 0x15; + ui8Cmd[1] = (uint8_t)i32X; + ui8Cmd[2] = (uint8_t)i32X; + + // + // Load row command, start and end row + // + ui8Cmd[3] = 0x75; + ui8Cmd[4] = (uint8_t)i32Y; + ui8Cmd[5] = (uint8_t)i32Y; + + // + // Send the column, row commands to the display + // + CFAL96x64x16WriteCommand(ui8Cmd, 6); + + // + // Send the data value representing the pixel to the display + // + CFAL96x64x16WriteData((uint8_t *)&ui32Value, 1); +} + +//***************************************************************************** +// +//! Draws a horizontal sequence of pixels on the screen. +//! +//! \param pvDisplayData is a pointer to the driver-specific data for this +//! display driver. +//! \param i32X is the X coordinate of the first pixel. +//! \param i32Y is the Y coordinate of the first pixel. +//! \param i32X0 is sub-pixel offset within the pixel data, which is valid for 1 +//! or 4 bit per pixel formats. +//! \param i32Count is the number of pixels to draw. +//! \param i32BPP is the number of bits per pixel; must be 1, 4, or 8 optionally +//! ORed with various flags unused by this driver. +//! \param pui8Data is a pointer to the pixel data. For 1 and 4 bit per pixel +//! formats, the most significant bit(s) represent the left-most pixel. +//! \param pui8Palette is a pointer to the palette used to draw the pixels. +//! +//! This function draws a horizontal sequence of pixels on the screen, using +//! the supplied palette. For 1 bit per pixel format, the palette contains +//! pre-translated colors; for 4 and 8 bit per pixel formats, the palette +//! contains 24-bit RGB values that must be translated before being written to +//! the display. +//! +//! \return None. +// +//***************************************************************************** +static void +CFAL96x64x16PixelDrawMultiple(void *pvDisplayData, int32_t i32X, int32_t i32Y, int32_t i32X0, + int32_t i32Count, int32_t i32BPP, + const uint8_t *pui8Data, + const uint8_t *pui8Palette) +{ + uint32_t ui32Byte; + uint8_t ui8Cmd[8]; + + // + // Load column command. Use the specified X for the start and just set + // the end to the rightmost column since we dont know where the data ends. + // + ui8Cmd[0] = 0x15; + ui8Cmd[1] = (uint8_t)i32X; + ui8Cmd[2] = 95; + + // + // Load row command. Use the specified Y for the start row and just set + // the end row to the bottom row since we dont know where the data ends. + // + ui8Cmd[3] = 0x75; + ui8Cmd[4] = (uint8_t)i32Y; + ui8Cmd[5] = 63; + + // + // Send the column, row commands to the display + // + CFAL96x64x16WriteCommand(ui8Cmd, 6); + + // + // Determine how to interpret the pixel data based on the number of bits + // per pixel. + // + switch(i32BPP & 0xFF) + { + // + // The pixel data is in 1 bit per pixel format. + // + case 1: + { + // + // Loop while there are more pixels to draw. + // + while(i32Count) + { + // + // Get the next byte of image data. + // + ui32Byte = *pui8Data++; + + // + // Loop through the pixels in this byte of image data. + // + for(; (i32X0 < 8) && i32Count; i32X0++, i32Count--) + { + // + // Draw this pixel in the appropriate color. + // + uint8_t ui8BPP = ((uint32_t *)pui8Palette) + [(ui32Byte >> (7 - i32X0)) & 1]; + CFAL96x64x16WriteData(&ui8BPP, 1); + } + + // + // Start at the beginning of the next byte of image data. + // + i32X0 = 0; + } + + // + // The image data has been drawn. + // + break; + } + + // + // The pixel data is in 4 bit per pixel format. + // + case 4: + { + // + // Loop while there are more pixels to draw. "Duff's device" is + // used to jump into the middle of the loop if the first nibble of + // the pixel data should not be used. Duff's device makes use of + // the fact that a case statement is legal anywhere within a + // sub-block of a switch statement. See + // http://en.wikipedia.org/wiki/Duff's_device for detailed + // information about Duff's device. + // + switch(i32X0 & 1) + { + case 0: + while(i32Count) + { + uint8_t ui8Color; + + // + // Get the upper nibble of the next byte of pixel data + // and extract the corresponding entry from the + // palette. + // + ui32Byte = (*pui8Data >> 4) * 3; + ui32Byte = (*(uint32_t *)(pui8Palette + ui32Byte) & + 0x00ffffff); + + // + // Translate this palette entry and write it to the + // screen. + // + ui8Color = DPYCOLORTRANSLATE(ui32Byte); + CFAL96x64x16WriteData(&ui8Color, 1); + + // + // Decrement the count of pixels to draw. + // + i32Count--; + + // + // See if there is another pixel to draw. + // + if(i32Count) + { + case 1: + // + // Get the lower nibble of the next byte of pixel + // data and extract the corresponding entry from + // the palette. + // + ui32Byte = (*pui8Data++ & 15) * 3; + ui32Byte = (*(uint32_t *)(pui8Palette + ui32Byte) & + 0x00ffffff); + + // + // Translate this palette entry and write it to the + // screen. + // + ui8Color = DPYCOLORTRANSLATE(ui32Byte); + CFAL96x64x16WriteData(&ui8Color, 1); + + // + // Decrement the count of pixels to draw. + // + i32Count--; + } + } + } + + // + // The image data has been drawn. + // + break; + } + + // + // The pixel data is in 8 bit per pixel format. + // + case 8: + { + // + // Loop while there are more pixels to draw. + // + while(i32Count--) + { + uint8_t ui8Color; + + // + // Get the next byte of pixel data and extract the + // corresponding entry from the palette. + // + ui32Byte = *pui8Data++ * 3; + ui32Byte = *(uint32_t *)(pui8Palette + ui32Byte) & 0x00ffffff; + + // + // Translate this palette entry and write it to the screen. + // + ui8Color = DPYCOLORTRANSLATE(ui32Byte); + CFAL96x64x16WriteData(&ui8Color, 1); + } + + // + // The image data has been drawn. + // + break; + } + } +} + +//***************************************************************************** +// +//! Draws a horizontal line. +//! +//! \param pvDisplayData is a pointer to the driver-specific data for this +//! display driver. +//! \param i32X1 is the X coordinate of the start of the line. +//! \param i32X2 is the X coordinate of the end of the line. +//! \param i32Y is the Y coordinate of the line. +//! \param ui32Value is the color of the line. +//! +//! This function draws a horizontal line on the display. The coordinates of +//! the line are assumed to be within the extents of the display. +//! +//! \return None. +// +//***************************************************************************** +static void +CFAL96x64x16LineDrawH(void *pvDisplayData, int32_t i32X1, int32_t i32X2, int32_t i32Y, + uint32_t ui32Value) +{ + uint8_t ui8LineBuf[16]; + unsigned int uIdx; + + // + // Send command for starting row and column + // + ui8LineBuf[0] = 0x15; + ui8LineBuf[1] = i32X1 < i32X2 ? i32X1 : i32X2; + ui8LineBuf[2] = 95; + ui8LineBuf[3] = 0x75; + ui8LineBuf[4] = i32Y; + ui8LineBuf[5] = 63; + CFAL96x64x16WriteCommand(ui8LineBuf, 6); + + // + // Use buffer of pixels to draw line, so multiple bytes can be sent at + // one time. Fill the buffer with the line color. + // + for(uIdx = 0; uIdx < sizeof(ui8LineBuf); uIdx++) + { + ui8LineBuf[uIdx] = ui32Value; + } + + uIdx = (i32X1 < i32X2) ? (i32X2 - i32X1) : (i32X1 - i32X2); + uIdx += 1; + while(uIdx) + { + CFAL96x64x16WriteData(ui8LineBuf, (uIdx < 16) ? uIdx : 16); + uIdx -= (uIdx < 16) ? uIdx : 16; + } +} + +//***************************************************************************** +// +//! Draws a vertical line. +//! +//! \param pvDisplayData is a pointer to the driver-specific data for this +//! display driver. +//! \param i32X is the X coordinate of the line. +//! \param i32Y1 is the Y coordinate of the start of the line. +//! \param i32Y2 is the Y coordinate of the end of the line. +//! \param ui32Value is the color of the line. +//! +//! This function draws a vertical line on the display. The coordinates of the +//! line are assumed to be within the extents of the display. +//! +//! \return None. +// +//***************************************************************************** +static void +CFAL96x64x16LineDrawV(void *pvDisplayData, int32_t i32X, int32_t i32Y1, int32_t i32Y2, + uint32_t ui32Value) +{ + uint8_t ui8LineBuf[16]; + unsigned int uIdx; + + // + // Send command for starting row and column. Also, set vertical + // address increment. + // + ui8LineBuf[0] = 0x15; + ui8LineBuf[1] = i32X; + ui8LineBuf[2] = 95; + ui8LineBuf[3] = 0x75; + ui8LineBuf[4] = i32Y1 < i32Y2 ? i32Y1 : i32Y2; + ui8LineBuf[5] = 63; + ui8LineBuf[6] = 0xA0; + ui8LineBuf[7] = 0x21; + CFAL96x64x16WriteCommand(ui8LineBuf, 8); + + // + // Use buffer of pixels to draw line, so multiple bytes can be sent at + // one time. Fill the buffer with the line color. + // + for(uIdx = 0; uIdx < sizeof(ui8LineBuf); uIdx++) + { + ui8LineBuf[uIdx] = ui32Value; + } + + uIdx = (i32Y1 < i32Y2) ? (i32Y2 - i32Y1) : (i32Y1 - i32Y2); + uIdx += 1; + while(uIdx) + { + CFAL96x64x16WriteData(ui8LineBuf, (uIdx < 16) ? uIdx : 16); + uIdx -= (uIdx < 16) ? uIdx : 16; + } + + // + // Restore horizontal address increment + // + ui8LineBuf[0] = 0xA0; + ui8LineBuf[1] = 0x20; + CFAL96x64x16WriteCommand(ui8LineBuf, 2); +} + +//***************************************************************************** +// +//! Fills a rectangle. +//! +//! \param pvDisplayData is a pointer to the driver-specific data for this +//! display driver. +//! \param pRect is a pointer to the structure describing the rectangle. +//! \param ui32Value is the color of the rectangle. +//! +//! This function fills a rectangle on the display. The coordinates of the +//! rectangle are assumed to be within the extents of the display, and the +//! rectangle specification is fully inclusive (in other words, both i16XMin and +//! i16XMax are drawn, aint32_t with i16YMin and i16YMax). +//! +//! \return None. +// +//***************************************************************************** +static void +CFAL96x64x16RectFill(void *pvDisplayData, const tRectangle *pRect, + uint32_t ui32Value) +{ + unsigned int uY; + + for(uY = pRect->i16YMin; uY <= pRect->i16YMax; uY++) + { + CFAL96x64x16LineDrawH(0, pRect->i16XMin, pRect->i16XMax, uY, ui32Value); + } +} + +//***************************************************************************** +// +//! Translates a 24-bit RGB color to a display driver-specific color. +//! +//! \param pvDisplayData is a pointer to the driver-specific data for this +//! display driver. +//! \param ui32Value is the 24-bit RGB color. The least-significant byte is the +//! blue channel, the next byte is the green channel, and the third byte is the +//! red channel. +//! +//! This function translates a 24-bit RGB color into a value that can be +//! written into the display's frame buffer in order to reproduce that color, +//! or the closest possible approximation of that color. +//! +//! \return Returns the display-driver specific color. +// +//***************************************************************************** +static uint32_t +CFAL96x64x16ColorTranslate(void *pvDisplayData, uint32_t ui32Value) +{ + // + // Translate from a 24-bit RGB color to a 3-3-2 RGB color. + // + return(DPYCOLORTRANSLATE(ui32Value)); +} + +//***************************************************************************** +// +//! Flushes any cached drawing operations. +//! +//! \param pvDisplayData is a pointer to the driver-specific data for this +//! display driver. +//! +//! This functions flushes any cached drawing operations to the display. This +//! is useful when a local frame buffer is used for drawing operations, and the +//! flush would copy the local frame buffer to the display. Since no memory +//! based frame buffer is used for this driver, the flush is a no operation. +//! +//! \return None. +// +//***************************************************************************** +static void +CFAL96x64x16Flush(void *pvDisplayData) +{ + // + // There is nothing to be done. + // +} + +//***************************************************************************** +// +//! The display structure that describes the driver for the Crystalfontz +//! CFAL9664-F-B1 OLED panel with SSD 1332 controller. +// +//***************************************************************************** +const tDisplay g_sCFAL96x64x16 = +{ + sizeof(tDisplay), + 0, + 96, + 64, + CFAL96x64x16PixelDraw, + CFAL96x64x16PixelDrawMultiple, + CFAL96x64x16LineDrawH, + CFAL96x64x16LineDrawV, + CFAL96x64x16RectFill, + CFAL96x64x16ColorTranslate, + CFAL96x64x16Flush +}; + +//***************************************************************************** +// +//! Initializes the display driver. +//! +//! This function initializes the SSD1332 display controller on the panel, +//! preparing it to display data. +//! +//! \return None. +// +//***************************************************************************** +void +CFAL96x64x16Init(void) +{ + tRectangle sRect; + + // + // Enable the peripherals used by this driver + // + ROM_SysCtlPeripheralEnable(DISPLAY_SSI_PERIPH); + ROM_SysCtlPeripheralEnable(DISPLAY_SSI_GPIO_PERIPH); + ROM_SysCtlPeripheralEnable(DISPLAY_RST_GPIO_PERIPH); + + // + // Select the SSI function for the appropriate pins + // + ROM_GPIOPinConfigure(DISPLAY_PINCFG_SSICLK); + ROM_GPIOPinConfigure(DISPLAY_PINCFG_SSIFSS); + ROM_GPIOPinConfigure(DISPLAY_PINCFG_SSITX); + + + // + // Configure the pins for the SSI function + // + ROM_GPIOPinTypeSSI(DISPLAY_SSI_PORT, DISPLAY_SSI_PINS); + + // + // Configure display control pins as GPIO output + // + ROM_GPIOPinTypeGPIOOutput(DISPLAY_RST_PORT, DISPLAY_RST_PIN); + ROM_GPIOPinTypeGPIOOutput(DISPLAY_ENV_PORT, DISPLAY_ENV_PIN); + ROM_GPIOPinTypeGPIOOutput(DISPLAY_D_C_PORT, DISPLAY_D_C_PIN); + + // + // Reset pin high, power off + // + ROM_GPIOPinWrite(DISPLAY_RST_PORT, DISPLAY_RST_PIN, DISPLAY_RST_PIN); + ROM_GPIOPinWrite(DISPLAY_ENV_PORT, DISPLAY_ENV_PIN, 0); + ROM_SysCtlDelay(1000); + + // + // Drive the reset pin low while we do other stuff + // + ROM_GPIOPinWrite(DISPLAY_RST_PORT, DISPLAY_RST_PIN, 0); + + // + // Configure the SSI port + // + ROM_SSIDisable(DISPLAY_SSI_BASE); + ROM_SSIConfigSetExpClk(DISPLAY_SSI_BASE, ROM_SysCtlClockGet(), + SSI_FRF_MOTO_MODE_3, SSI_MODE_MASTER, + DISPLAY_SSI_CLOCK, 8); + ROM_SSIEnable(DISPLAY_SSI_BASE); + + // + // Take the display out of reset + // + ROM_SysCtlDelay(1000); + ROM_GPIOPinWrite(DISPLAY_RST_PORT, DISPLAY_RST_PIN, DISPLAY_RST_PIN); + ROM_SysCtlDelay(1000); + + // + // Enable display power supply + // + ROM_GPIOPinWrite(DISPLAY_ENV_PORT, DISPLAY_ENV_PIN, DISPLAY_ENV_PIN); + ROM_SysCtlDelay(1000); + + // + // Send the initial configuration command bytes to the display + // + CFAL96x64x16WriteCommand(g_ui8DisplayInitCommands, + sizeof(g_ui8DisplayInitCommands)); + ROM_SysCtlDelay(1000); + + // + // Fill the entire display with a black rectangle, to clear it. + // + sRect.i16XMin = 0; + sRect.i16XMax = 95; + sRect.i16YMin = 0; + sRect.i16YMax = 63; + CFAL96x64x16RectFill(0, &sRect, 0); +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/boards/ek-lm4f232/drivers/cfal96x64x16.h b/boards/ek-lm4f232/drivers/cfal96x64x16.h new file mode 100644 index 0000000..880be00 --- /dev/null +++ b/boards/ek-lm4f232/drivers/cfal96x64x16.h @@ -0,0 +1,37 @@ +//***************************************************************************** +// +// cfal96x64x16.h - Prototypes for the Crystalfontz CFAL9664-F-B1 OLED display +// with an SSD1332 controller. +// +// Copyright (c) 2011-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 EK-LM4F232 Firmware Package. +// +//***************************************************************************** + +#ifndef __CFAL96X64X16_H__ +#define __CFAL96X64X16_H__ + +//***************************************************************************** +// +// Prototypes for the globals exported by this driver. +// +//***************************************************************************** +extern void CFAL96x64x16Init(void); +extern const tDisplay g_sCFAL96x64x16; + +#endif // __CFAL96X64X16_H__ diff --git a/boards/ek-lm4f232/drivers/slidemenuwidget.c b/boards/ek-lm4f232/drivers/slidemenuwidget.c new file mode 100644 index 0000000..805b77b --- /dev/null +++ b/boards/ek-lm4f232/drivers/slidemenuwidget.c @@ -0,0 +1,1424 @@ +//***************************************************************************** +// +// slidemenuwidget.c - A sliding menu drawing widget. +// +// Copyright (c) 2011-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 EK-LM4F232 Firmware Package. +// +//***************************************************************************** + +#include +#include +#include +#include "inc/hw_types.h" +#include "driverlib/debug.h" +#include "utils/uartstdio.h" +#include "grlib/grlib.h" +#include "grlib/widget.h" +#include "slidemenuwidget.h" + +//***************************************************************************** +// +//! \addtogroup slidemenuwidget_api +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// This is a custom widget for drawing a menu system on the display. The +// widget presents the menus using a "sliding" animation. The menu items +// are shown in a vertical list, and as the user scrolls through the list +// of menu items, the menu slides up and down the display. When a menu item +// is selected to descend in the menu tree, the widget slides the old menu +// off the to left while the new menu slides in from the right. Likewise, +// going up in the menu tree, the higher level menu slides back onto the +// screen from the left. +// +// Additional structures are provided to implement a menu, and menu items. +// Each menu contains menu items, and each menu item can have a child menu. +// These structures can be used to build a menu tree. The menu widget will +// show one menu at any given time, the menu that is displayed on the screen. +// +// In addition to child menus, any menu item can have instead a child widget. +// If this is used, then when the user selects a menu item, a new widget can +// be activated to perform some function. When the function of the child +// widget completes, then the widget slides back off the screen (to the right) +// and the parent menu is displayed again. +// +// A given menu can have menu items that are individually selectable or +// multiple-selectable. For individually selectable menu items, the item +// is selected by leaving the menu with the focus on the selected item. For +// example navigating down to a submenu with choices A, B and C, and then +// navigating until the focus is on item B will cause item B to be selected. +// The menu will remember that item B was selected even when navigating away +// from that menu. +// +// If a menu is configured to be multiple-selectable, then each menu item has +// a check box that is checked by pressing the select button. When the item +// is selected the box will show an X. Any or all or none can be selected in +// this way. When a menu is configured to be multi-selectable, the menu items +// cannot have any child menus or widgets. +// +// The menu widget provides some visual clues to the user about how to +// navigate the menu tree. Whenever a menu item has a child menu or child +// widget, then a small right arrow is shown on the right side of the menu +// item that has the focus. This tells the user to press the "right" button +// to descend to the next menu or widget. When it is possible to go up a +// level in the menu tree (when showing a child menu), a small left arrow +// will be shown on the menu item with the focus. This is an indication to the +// user that they should press the "left" button. +// +// This widget is meant to work with key/button presses. It expects there +// to be up/down/left/right and select buttons. The widget will need to be +// modified in order to work with a pointer input. +// +// In order to perform the sliding animation, the menu widget requires that +// it be provided with two off-screen displays. The menu widget renders the +// two menus (the old and the new) into the two buffers, and then repeatedly +// paints both to the physical display while adjusting the coordinates as +// appropriate. This will cause the menus to appear animated and move across +// the display. When the menus are being animated, the menu widget is taking +// all the non-interrupt processor time in order to draw the buffers to the +// display. This operation occurs in response to the widget processing of the +// key/button events and will occur in the thread that calls +// WidgetMessageQueueProcess(). The programmer should be aware of this +// processing burden when designing an application that uses the sliding +// menu widget. +// +//***************************************************************************** + +//***************************************************************************** +// +// A graphics image of a small right arrow icon. +// +//***************************************************************************** +const uint8_t g_ui8RtArrow[] = +{ + IMAGE_FMT_1BPP_UNCOMP, + 4, 0, + 8, 0, + + 0x80, + 0xC0, + 0xE0, + 0xF0, + 0xE0, + 0xC0, + 0x80, + 0 +}; + +//***************************************************************************** +// +// A graphics image of a small left arrow icon. +// +//***************************************************************************** +const uint8_t g_ui8LtArrow[] = +{ + IMAGE_FMT_1BPP_UNCOMP, + 4, 0, + 8, 0, + + 0x10, + 0x30, + 0x70, + 0xF0, + 0x70, + 0x30, + 0x10, + 0 +}; + +//***************************************************************************** +// +// A graphics image of a small unchecked box icon. +// +//***************************************************************************** +const uint8_t g_ui8Unchecked[] = +{ + IMAGE_FMT_1BPP_UNCOMP, + 7, 0, + 8, 0, + + 0xFE, + 0x82, + 0x82, + 0x82, + 0x82, + 0x82, + 0xFE, + 0 +}; + +//***************************************************************************** +// +// A graphics image of a small checked box icon. +// +//***************************************************************************** +const uint8_t g_ui8Checked[] = +{ + IMAGE_FMT_1BPP_UNCOMP, + 7, 0, + 8, 0, + + 0xFE, + 0xC6, + 0xAA, + 0x92, + 0xAA, + 0xC6, + 0xFE, + 0 +}; + +//***************************************************************************** +// +//! Draws the current menu into a drawing context, off-screen buffer. +//! +//! \param psMenuWidget points at the SlideMenuWidget being processed. +//! \param psContext points to the context where all drawing should be done. +//! \param i32OffsetY is the Y offset for drawing the menu. +//! +//! This function renders a menu (set of menu items), into a drawing context. +//! It assumes that the drawing context is an off-screen buffer, and that +//! the entire buffer belongs to this widget. The vertical position of the +//! menu can be adjusted by using the parameter i32OffsetY. This value can be +//! positive or negative and can cause the menu to be rendered above or below +//! the normal position in the display. +//! +//! \return None. +// +//***************************************************************************** +void +SlideMenuDraw(tSlideMenuWidget *psMenuWidget, tContext *psContext, + int32_t i32OffsetY) +{ + tSlideMenu *psMenu; + uint32_t ui32Idx; + tRectangle sRect; + + // + // Check the arguments + // + ASSERT(psMenuWidget); + ASSERT(psContext); + + // + // Set the foreground color for the rectangle fill to match what we want + // as the menu background. + // + GrContextForegroundSet(psContext, psMenuWidget->ui32ColorBackground); + GrRectFill(psContext, &psContext->sClipRegion); + + // + // Get the current menu that is being displayed + // + psMenu = psMenuWidget->psSlideMenu; + + // + // Set the foreground to the color we want for the menu item boundaries + // and text color, text font. + // + GrContextForegroundSet(psContext, psMenuWidget->ui32ColorForeground); + GrContextFontSet(psContext, psMenuWidget->psFont); + + // + // Set the rectangle bounds for the first menu item. + // The starting Y value is calculated based on which menu item is currently + // centered. Y coordinates are subtracted to find the Y start location + // of the first menu item, which could even be off the display. + // + // Set the X coords of the menu item to the extents of the display + // + sRect.i16XMin = 0; + sRect.i16XMax = psContext->sClipRegion.i16XMax; + + // + // Find the Y coordinate of the centered menu item + // + sRect.i16YMin = (psContext->psDisplay->ui16Height / 2) - + (psMenuWidget->ui32MenuItemHeight / 2); + + // + // Adjust to find Y coordinate of first menu item + // + sRect.i16YMin -= psMenu->ui32CenterIndex * psMenuWidget->ui32MenuItemHeight; + + // + // Now adjust for the offset that was passed in by caller. This allows + // for drawing menu items above or below the main display. + // + sRect.i16YMin += i32OffsetY; + + // + // Find the ending Y coordinate of first menu item + // + sRect.i16YMax = sRect.i16YMin + psMenuWidget->ui32MenuItemHeight - 1; + + // + // Start the index at the first menu item. It is possible that this + // menu item is off the display. + // + ui32Idx = 0; + + // + // Loop through all menu items, drawing on the display. Note that some + // may not be on the screen, but they will be clipped. + // + while(ui32Idx < psMenu->ui32Items) + { + // + // If this index is the one that is highlighted, then change the + // background + // + if(ui32Idx == psMenu->ui32FocusIndex) + { + // + // Set the foreground to the highlight color, and fill the + // rectangle of the background of this menu item. + // + GrContextForegroundSet(psContext, psMenuWidget->ui32ColorHighlight); + GrRectFill(psContext, &sRect); + + // + // Set the new foreground to the normal foreground color, and + // set the background to the highlight color. This is so + // remaining drawing operations will have the correct background + // and foreground colors for this highlighted menu item cell. + // + GrContextForegroundSet(psContext, psMenuWidget->ui32ColorForeground); + GrContextBackgroundSet(psContext, psMenuWidget->ui32ColorHighlight); + + // + // If this menu has a parent, then draw a left arrow icon on the + // focused menu item. + // + if(psMenu->psParent) + { + GrImageDraw(psContext, g_ui8LtArrow, sRect.i16XMin + 4, + sRect.i16YMin + + (psMenuWidget->ui32MenuItemHeight / 2) - 4); + } + + // + // If this menu has a child menu or child widget, then draw a + // right arrow icon on the focused menu item. + // + if(psMenu->psSlideMenuItems[ui32Idx].psChildMenu || + psMenu->psSlideMenuItems[ui32Idx].psChildWidget) + { + GrImageDraw(psContext, g_ui8RtArrow, sRect.i16XMax - 8, + sRect.i16YMin + + (psMenuWidget->ui32MenuItemHeight / 2) - 4); + } + } + + // + // Otherwise this is a normal, non-highlighted menu item cell, + // so set the normal background color. + // + else + { + GrContextBackgroundSet(psContext, psMenuWidget->ui32ColorBackground); + } + + // + // If the current menu is multi-selectable, then draw a checkbox on + // the menu item. Draw a checked or unchecked box depending on whether + // the item has been selected. + // + if(psMenu->bMultiSelectable) + { + if(psMenu->ui32SelectedFlags & (1 << ui32Idx)) + { + GrImageDraw(psContext, g_ui8Checked, sRect.i16XMax - 12, + sRect.i16YMin + + (psMenuWidget->ui32MenuItemHeight / 2) - 4); + } + else + { + GrImageDraw(psContext, g_ui8Unchecked, sRect.i16XMax - 12, + sRect.i16YMin + + (psMenuWidget->ui32MenuItemHeight / 2) - 4); + } + + } + + // + // Draw the rectangle representing the menu item + // + GrRectDraw(psContext, &sRect); + + // + // Draw the text for this menu item in the middle of the menu item + // rectangle (cell). + // + GrStringDrawCentered(psContext, + psMenu->psSlideMenuItems[ui32Idx].pcText, + -1, + psMenuWidget->sBase.psDisplay->ui16Width / 2, + sRect.i16YMin + \ + (psMenuWidget->ui32MenuItemHeight / 2) - 1, 0); + + // + // Advance to the next menu item, and update the menu item rectangle + // bounds to the next position + // + ui32Idx++; + sRect.i16YMin += psMenuWidget->ui32MenuItemHeight; + sRect.i16YMax += psMenuWidget->ui32MenuItemHeight; + + // + // Note that this may attempt to render menu items that run off the + // bottom of the drawing area, but these will just be clipped and a + // little bit of processing time is wasted. + // + } +} + +//***************************************************************************** +// +//! Paints a menu, menu items on a display. +//! +//! \param psWidget is a pointer to the slide menu widget to be drawn. +//! +//! This function draws the contents of a slide menu on the display. This is +//! called in response to a \b WIDGET_MSG_PAINT message. +//! +//! \return None. +// +//***************************************************************************** +static void +SlideMenuPaint(tWidget *psWidget) +{ + tSlideMenuWidget *psMenuWidget; + tContext sContext; + + // + // Check the arguments. + // + ASSERT(psWidget); + + // + // If this widget has a child widget, that means that the menu has + // slid off the screen and the child widget is in control. Therefore + // there is nothing to paint here. Just exit and the child widget will + // be painted. + // + if(psWidget->psChild) + { + return; + } + + // + // Convert the generic widget pointer into a slide menu widget pointer, + // and get a pointer to its context. + // + psMenuWidget = (tSlideMenuWidget *)psWidget; + + // + // Initialize a context for the primary off-screen drawing buffer. + // Clip region is set to entire display by default, which is what we want. + // + GrContextInit(&sContext, psMenuWidget->psDisplayA); + + // + // Render the menu into the off-screen buffer, using normal vertical + // position. + // + SlideMenuDraw(psMenuWidget, &sContext, 0); + + // + // Initialize a drawing context for the display where the widget is to be + // drawn. This is the physical display, not an off-screen buffer. + // + GrContextInit(&sContext, psWidget->psDisplay); + + // + // Initialize the clipping region on the physical display, based on the + // extents of this widget. + // + GrContextClipRegionSet(&sContext, &(psWidget->sPosition)); + + // + // Now copy the rendered menu into the physical display. This will show + // the menu on the display. + // + GrImageDraw(&sContext, psMenuWidget->psDisplayA->pvDisplayData, + psWidget->sPosition.i16XMin, psWidget->sPosition.i16YMin); +} + +//***************************************************************************** +// +//! Performs the sliding menu operation, in response to the "down" button. +//! +//! \param psWidget is a pointer to the slide menu widget to move down. +//! +//! This function will respond to the "down" key/button event. The down +//! button is used to select the next menu item down the list, and the effect +//! is that the menu itself slides up, leaving the highlighted menu item +//! in the middle of the screen. +//! +//! This function repeatedly draws the menu onto the display until the sliding +//! animation is finished and will not return to the caller until then. This +//! function is usually called from the thread context of +//! WidgetMessageQueueProcess(). +//! +//! \return Returns a non-zero value if the menu was moved or was not moved +//! because it is already at the last position. If a child widget is active +//! then this function does nothing and returns a 0. +// +//***************************************************************************** +static int32_t +SlideMenuDown(tWidget *psWidget) +{ + tSlideMenuWidget *psMenuWidget; + tSlideMenu *psMenu; + tContext sContext; + uint32_t ui32MenuHeight; + uint32_t ui32Y; + + // + // If this menu widget has a child widget, that means the child widget + // is in control of the display, and there is nothing to do here. + // + if(psWidget->psChild) + { + return(0); + } + + // + // Get handy pointers to the menu widget, and the menu that is currently + // displayed. + // + psMenuWidget = (tSlideMenuWidget *)psWidget; + psMenu = psMenuWidget->psSlideMenu; + + // + // If we are already at the end of the list of menu items, then there + // is nothing else to do. + // + if(psMenu->ui32FocusIndex >= (psMenu->ui32Items - 1)) + { + return(1); + } + + // + // Increment focus menu item. This has the effect of selecting the next + // menu item in the list. + // + psMenu->ui32FocusIndex++; + + // + // Initialize a context for the primary off-screen drawing buffer. + // Clip region is set to entire display by default, which is what we want. + // + GrContextInit(&sContext, psMenuWidget->psDisplayA); + + // + // Render the menu into the off-screen buffer. This will be the same + // menu appearance as before, except the highlighted item has changed + // to the next menu item down. + // + SlideMenuDraw(psMenuWidget, &sContext, 0); + + // + // Draw a continuation of this menu in the second offscreen buffer. + // This is the part of the menu that would be drawn if the display were + // twice as tall. We are effectively creating a virtual display that is + // twice as tall as the physical display. + // + GrContextInit(&sContext, psMenuWidget->psDisplayB); + SlideMenuDraw(psMenuWidget, &sContext, -1 * + (psMenuWidget->sBase.sPosition.i16YMax - + psMenuWidget->sBase.sPosition.i16YMin)); + + // + // Initialize a drawing context for the display where the widget is to be + // drawn. This is the physical display, not an off-screen buffer. + // + GrContextInit(&sContext, psWidget->psDisplay); + + // + // Initialize the clipping region on the physical display, based on the + // extents of this widget. + // + GrContextClipRegionSet(&sContext, &(psWidget->sPosition)); + + // + // Get the height of the displayed part of the menu. + // + ui32MenuHeight = psMenuWidget->psDisplayA->ui16Height; + + // + // Now copy the rendered menu into the physical display + // + // Iterate over the Y displacement of one menu item cell. This loop + // will repeatedly draw both off screen buffers to the physical display, + // adjusting the position of each by one pixel each time it is drawn. Each + // time the offset is changed so that both buffers are drawn one higher + // than the previous time. This will have the effect of "sliding" the + // entire menu up by the height of one menu item cell. + // The speed of the animation is controlled entirely by the speed of the + // processor and the speed of the interface to the physical display. + // + for(ui32Y = 0; ui32Y <= psMenuWidget->ui32MenuItemHeight; ui32Y++) + { + GrImageDraw(&sContext, psMenuWidget->psDisplayA->pvDisplayData, + psWidget->sPosition.i16XMin, + psWidget->sPosition.i16YMin - ui32Y); + GrImageDraw(&sContext, psMenuWidget->psDisplayB->pvDisplayData, + psWidget->sPosition.i16XMin, + psWidget->sPosition.i16YMin + ui32MenuHeight - ui32Y); + } + + // + // Increment centered menu item. This will now match the menu item with + // the focus. When the menu is repainted again, the newly selected + // menu item will be centered and highlighted. + // + psMenu->ui32CenterIndex = psMenu->ui32FocusIndex; + + // + // Initialize a context for the primary off-screen drawing buffer. + // Clip region is set to entire display by default, which is what we want. + // + GrContextInit(&sContext, psMenuWidget->psDisplayA); + + // + // Render the menu into the off-screen buffer. This will be the same + // menu appearance as before, except the highlighted item has changed + // to the next menu item down. Now when a repaint occurs the menu + // will be redrawn with the newly highlighted menu item. + // + SlideMenuDraw(psMenuWidget, &sContext, 0); + + // + // Return indication that we handled the key event. + // + return(1); +} + +//***************************************************************************** +// +//! Performs the sliding menu operation, in response to the "up" button. +//! +//! \param psWidget is a pointer to the slide menu widget to move up. +//! +//! This function will respond to the "up" key/button event. The up +//! button is used to select the previous menu item down the list, and the +//! effect is that the menu itself slides down, leaving the highlighted menu +//! item in the middle of the screen. +//! +//! This function repeatedly draws the menu onto the display until the sliding +//! animation is finished and will not return to the caller until then. This +//! function is usually called from the thread context of +//! WidgetMessageQueueProcess(). +//! +//! \return Returns a non-zero value if the menu was moved or was not moved +//! because it is already at the first position. If a child widget is active +//! then this function does nothing and returns a 0. +// +//***************************************************************************** +static int32_t +SlideMenuUp(tWidget *psWidget) +{ + tSlideMenuWidget *psMenuWidget; + tSlideMenu *psMenu; + tContext sContext; + uint32_t ui32MenuHeight; + uint32_t ui32Y; + + // + // If this menu widget has a child widget, that means the child widget + // is in control of the display, and there is nothing to do here. + // + if(psWidget->psChild) + { + return(0); + } + + // + // Get handy pointers to the menu widget, and the menu that is currently + // displayed. + // + psMenuWidget = (tSlideMenuWidget *)psWidget; + psMenu = psMenuWidget->psSlideMenu; + + // + // If we are already at the start of the list of menu items, then there + // is nothing else to do. + // + if(psMenu->ui32FocusIndex == 0) + { + return(1); + } + + // + // Decrement the focus menu item. This has the effect of selecting the + // previous menu item in the list. + // + psMenu->ui32FocusIndex--; + + // + // Initialize a context for the primary off-screen drawing buffer. + // Clip region is set to entire display by default, which is what we want. + // + GrContextInit(&sContext, psMenuWidget->psDisplayA); + + // + // Render the menu into the off-screen buffer. This will be the same + // menu appearance as before, except the highlighted item has changed + // to the previous menu item up. + // + SlideMenuDraw(psMenuWidget, &sContext, 0); + + // + // Draw a continuation of this menu in the second offscreen buffer. + // This is the part of the menu that would be drawn above this menu if the + // display were twice as tall. We are effectively creating a virtual + // display that is twice as tall as the physical display. + // + GrContextInit(&sContext, psMenuWidget->psDisplayB); + SlideMenuDraw(psMenuWidget, &sContext, + (psMenuWidget->sBase.sPosition.i16YMax - + psMenuWidget->sBase.sPosition.i16YMin)); + + // + // Initialize a drawing context for the display where the widget is to be + // drawn. This is the physical display, not an off-screen buffer. + // + GrContextInit(&sContext, psWidget->psDisplay); + + // + // Initialize the clipping region on the physical display, based on the + // extents of this widget. + // + GrContextClipRegionSet(&sContext, &(psWidget->sPosition)); + + // + // Get the height of the displayed part of the menu. + // + ui32MenuHeight = psMenuWidget->psDisplayA->ui16Height; + + // + // Now copy the rendered menu into the physical display + // + // Iterate over the Y displacement of one menu item cell. This loop + // will repeatedly draw both off screen buffers to the physical display, + // adjusting the position of each by one pixel each time it is drawn. Each + // time the offset is changed so that both buffers are drawn one lower + // than the previous time. This will have the effect of "sliding" the + // entire menu down by the height of one menu item cell. + // The speed of the animation is controlled entirely by the speed of the + // processor and the speed of the interface to the physical display. + // + for(ui32Y = 0; ui32Y <= psMenuWidget->ui32MenuItemHeight; ui32Y++) + { + GrImageDraw(&sContext, psMenuWidget->psDisplayB->pvDisplayData, + psWidget->sPosition.i16XMin, + psWidget->sPosition.i16YMin + ui32Y - ui32MenuHeight); + GrImageDraw(&sContext, psMenuWidget->psDisplayA->pvDisplayData, + psWidget->sPosition.i16XMin, + psWidget->sPosition.i16YMin + ui32Y); + } + + // + // Decrement the centered menu item. This will now match the menu item + // with the focus. When the menu is repainted again, the newly selected + // menu item will be centered and highlighted. + // + psMenu->ui32CenterIndex = psMenu->ui32FocusIndex; + + // + // Initialize a context for the primary off-screen drawing buffer. + // Clip region is set to entire display by default, which is what we want. + // + GrContextInit(&sContext, psMenuWidget->psDisplayA); + + // + // Render the menu into the off-screen buffer. This will be the same + // menu appearance as before, except the highlighted item has changed + // to the next menu item up. Now when a repaint occurs the menu + // will be redrawn with the newly highlighted menu item. + // + SlideMenuDraw(psMenuWidget, &sContext, 0); + + // + // Return indication that we handled the key event. + // + return(1); +} + +//***************************************************************************** +// +//! Performs the sliding menu operation, in response to the "right" button. +//! +//! \param psWidget is a pointer to the slide menu widget to move to the right. +//! +//! This function will respond to the "right" key/button event. The right +//! button is used to select the next menu level below the current menu item, +//! or a widget that is activated by the menu item. The effect is that the +//! menu itself slides off to the left, and the new menu or widget slides in +//! from the right. +//! +//! This function repeatedly draws the menu onto the display until the sliding +//! animation is finished and will not return to the caller until then. This +//! function is usually called from the thread context of +//! WidgetMessageQueueProcess(). +//! +//! \return Returns a non-zero value if the menu was moved or was not moved +//! because it is already at the last position. If a child widget is active +//! then this function does nothing and returns a 0. +// +//***************************************************************************** +static int32_t +SlideMenuRight(tWidget *psWidget) +{ + tSlideMenuWidget *psMenuWidget; + tSlideMenu *psMenu; + tSlideMenu *psChildMenu; + tContext sContext; + tWidget *psChildWidget; + uint32_t ui32X; + uint32_t ui32MenuWidth; + + // + // If this menu widget has a child widget, that means the child widget + // is in control of the display, and there is nothing to do here. + // + if(psWidget->psChild) + { + return(0); + } + + // + // Get handy pointers to the menu widget, and the current menu, and the + // child menu and widget if they exist. + // + psMenuWidget = (tSlideMenuWidget *)psWidget; + psMenu = psMenuWidget->psSlideMenu; + psChildMenu = psMenu->psSlideMenuItems[psMenu->ui32FocusIndex].psChildMenu; + psChildWidget = psMenu->psSlideMenuItems[psMenu->ui32FocusIndex].psChildWidget; + + // + // Initialize a context for the secondary off-screen drawing buffer. + // Clip region is set to entire display by default, which is what we want. + // + GrContextInit(&sContext, psMenuWidget->psDisplayB); + + // + // Render the current menu into off-screen buffer B. This + // will be the same menu appearance as is already being shown. + // + SlideMenuDraw(psMenuWidget, &sContext, 0); + + // + // Now set up context for drawing into off-screen buffer A + // + GrContextInit(&sContext, psMenuWidget->psDisplayA); + + // + // Process child menu of this menu item + // + if(psChildMenu) + { + // + // Switch the active menu for this SlideMenuWidget to be the child + // menu + // + psMenuWidget->psSlideMenu = psChildMenu; + + // + // Draw the new (child) menu into off-screen buffer A + // + SlideMenuDraw(psMenuWidget, &sContext, 0); + } + + // + // Process child widget of this menu item. This only happens if there + // is no child menu. + // + else if(psChildWidget) + { + // + // Call the widget activated callback function. This will notify + // the application that a child widget has been activated by the + // menu system. + // + if(psMenuWidget->pfnActive) + { + psMenuWidget->pfnActive(psChildWidget, + &psMenu->psSlideMenuItems[psMenu->ui32FocusIndex], + 1); + } + + // + // Link the new child widget into this SlideMenuWidget so + // it appears as a child to this widget. Normally the menu widget + // has no child widget. + // + psWidget->psChild = psChildWidget; + psChildWidget->psParent = psWidget; + + // + // Fill a rectangle with the new child widget background color. + // This is done in off-screen buffer A. When the menu slides off, + // it will be replaced by a blank background that will then be + // controlled by the new child widget. + // + GrContextForegroundSet( + &sContext, + psMenu->psSlideMenuItems[psMenu->ui32FocusIndex].ui32ChildWidgetColor); + GrRectFill(&sContext, &sContext.sClipRegion); + + // + // Request a repaint for the child widget so it can draw itself once + // the menu slide is done. + // + WidgetPaint(psChildWidget); + } + + // + // There is no child menu or child widget, so there is nothing to change + // on the display. + // + else + { + return(1); + } + + // + // Initialize a drawing context for the display where the widget is to be + // drawn. This is the physical display, not an off-screen buffer. + // + GrContextInit(&sContext, psWidget->psDisplay); + + // + // Initialize the clipping region on the physical display, based on the + // extents of this widget. + // + GrContextClipRegionSet(&sContext, &(psWidget->sPosition)); + + // + // Get the width of the menu widget which is used in calculations below + // + ui32MenuWidth = psMenuWidget->psDisplayA->ui16Width; + + // + // The following loop draws the two off-screen buffers onto the physical + // display using a right-to-left-wipe. This will provide an appearance + // of sliding to the left. The new child menu, or child widget background + // will slide in from the right. The "old" menu is being held in + // off-screen buffer B and the new one is in buffer A. So when we are + // done, the correct image will be in buffer A. + // + for(ui32X = 0; ui32X <= ui32MenuWidth; ui32X += 8) + { + GrImageDraw(&sContext, psMenuWidget->psDisplayB->pvDisplayData, + psWidget->sPosition.i16XMin - ui32X, + psWidget->sPosition.i16YMin); + GrImageDraw(&sContext, psMenuWidget->psDisplayA->pvDisplayData, + psWidget->sPosition.i16XMin + ui32MenuWidth - ui32X, + psWidget->sPosition.i16YMin); + } + + // + // Return indication that we handled the key event. + // + return(1); +} + +//***************************************************************************** +// +//! Performs the sliding menu operation, in response to the "left" button. +//! +//! \param psWidget is a pointer to the slide menu widget to move to the left. +//! +//! This function will respond to the "left" key/button event. The left +//! button is used to ascend to the next menu up in the menu tree. The effect +//! is that the current menu, or active widget, slides off to the right, while +//! the parent menu slides in from the left. +//! +//! This function repeatedly draws the menu onto the display until the sliding +//! animation is finished and will not return to the caller until then. This +//! function is usually called from the thread context of +//! WidgetMessageQueueProcess(). +//! +//! \return Returns a non-zero value if the menu was moved or was not moved +//! because it is already at the last position. If a child widget is active +//! then this function does nothing and returns a 0. +// +//***************************************************************************** +static int32_t +SlideMenuLeft(tWidget *psWidget) +{ + tSlideMenuWidget *psMenuWidget; + tSlideMenu *psMenu; + tSlideMenu *psParentMenu; + tContext sContext; + uint32_t ui32X; + uint32_t ui32MenuWidth; + + // + // Get handy pointers to the menu widget and active menu, and the parent + // menu if there is one. + // + psMenuWidget = (tSlideMenuWidget *)psWidget; + psMenu = psMenuWidget->psSlideMenu; + psParentMenu = psMenu->psParent; + + // + // Initialize a context for the primary off-screen drawing buffer. + // Clip region is set to entire display by default, which is what we want. + // + GrContextInit(&sContext, psMenuWidget->psDisplayB); + + // + // If this widget has a child, that means that the child widget is in + // control, and we are requested to go back to the previous menu item. + // Process the child widget. + // + if(psWidget->psChild) + { + // + // Call the widget de-activated callback function. This notifies the + // application that the widget is being deactivated. + // + if(psMenuWidget->pfnActive) + { + psMenuWidget->pfnActive(psWidget->psChild, + &psMenu->psSlideMenuItems[psMenu->ui32FocusIndex], + 0); + } + + // + // Unlink the child widget from the slide menu widget. The menu + // widget will now no longer have a child widget. + // + psWidget->psChild->psParent = 0; + psWidget->psChild = 0; + + // + // Fill a rectangle with the child widget background color. This will + // erase everything else that is shown on the widget but leave the + // background, which will make the change visually less jarring. + // This is done in off-screen buffer B, which is the buffer that is + // going to be slid off the screen. + // + GrContextForegroundSet( + &sContext, + psMenu->psSlideMenuItems[psMenu->ui32FocusIndex].ui32ChildWidgetColor); + GrRectFill(&sContext, &sContext.sClipRegion); + } + + // + // Otherwise there is not a child widget in control, so process the parent + // menu, if there is one. + // + else if(psParentMenu) + { + // + // Render the current menu into the off-screen buffer B. This will be + // the same menu appearance that is currently on the display. + // + SlideMenuDraw(psMenuWidget, &sContext, 0); + + // + // Now switch the widget to the parent menu + // + psMenuWidget->psSlideMenu = psParentMenu; + } + + // + // Otherwise, we are already at the top level menu and there is nothing + // else to do. + // + else + { + return(1); + } + + // + // Draw the new menu in the second offscreen buffer. This is the menu + // that will be on the display when the animation is over. + // + GrContextInit(&sContext, psMenuWidget->psDisplayA); + SlideMenuDraw(psMenuWidget, &sContext, 0); + + // + // Initialize a drawing context for the display where the widget is to be + // drawn. This is the physical display, not an off-screen buffer. + // + GrContextInit(&sContext, psWidget->psDisplay); + + // + // Initialize the clipping region on the physical display, based on the + // extents of this widget. + // + GrContextClipRegionSet(&sContext, &(psWidget->sPosition)); + + // + // Get the width of the menu widget. + // + ui32MenuWidth = psMenuWidget->psDisplayA->ui16Width; + + // + // The following loop draws the two off-screen buffers onto the physical + // display using a left-to-right. This will provide an appearance + // of sliding to the right. The parent menu will slide in from the left. + // The "old" child menu is being held in off-screen buffer B and the new + // one is in buffer A. So when we are done, the correct image will be in + // buffer A. + // + for(ui32X = 0; ui32X <= ui32MenuWidth; ui32X += 8) + { + GrImageDraw(&sContext, psMenuWidget->psDisplayB->pvDisplayData, + psWidget->sPosition.i16XMin + ui32X, + psWidget->sPosition.i16YMin); + GrImageDraw(&sContext, psMenuWidget->psDisplayA->pvDisplayData, + psWidget->sPosition.i16XMin + ui32X - ui32MenuWidth, + psWidget->sPosition.i16YMin); + } + + // + // Return indication that we handled the key event. + // + return(1); +} + +//***************************************************************************** +// +//! Handles menu selection, in response to the "select" button. +//! +//! \param psWidget is a pointer to the slide menu widget to use for a +//! select operation. +//! +//! This function will allow for checking or unchecking multi-selectable +//! menu items. If the menu does not allow multiple selection, then it +//! treats it as a "right" button press. +//! +//! \return Returns a non-zero value if the key was handled. Returns 0 if the +//! key was not handled. +// +//***************************************************************************** +static int32_t +SlideMenuClick(tWidget *psWidget) +{ + tSlideMenuWidget *psMenuWidget; + tSlideMenu *psMenu; + + // + // If a child widget is in control then there is nothing to do. + // + if(psWidget->psChild) + { + return(0); + } + + // + // Get handy pointers to the menu widget and current menu. + // + psMenuWidget = (tSlideMenuWidget *)psWidget; + psMenu = psMenuWidget->psSlideMenu; + + // + // Check to see if this menu allows multiple selection. + // + if(psMenu->bMultiSelectable) + { + // + // Toggle the selection status of the currently highlighted menu + // item, and then repaint it. + // + psMenu->ui32SelectedFlags ^= 1 << psMenu->ui32FocusIndex; + SlideMenuPaint(psWidget); + + // + // We are done so return indication that we handled the key event. + // + return(1); + } + + // + // Otherwise, treat the select button the same as a right button. + // + return(SlideMenuRight(psWidget)); +} + +//***************************************************************************** +// +//! Process key/button event to decide how to move the sliding menu. +//! +//! \param psWidget is a pointer to the slide menu widget to process. +//! \param ui32Msg is the message containing the key event. +//! +//! This function is used to specifically handle key events destined for the +//! slide menu widget. It decides which menu movement function should be +//! called for each key event. +//! +//! \return Returns an indication if the key was handled. Non-zero if the +//! key event was handled or else 0. +// +//***************************************************************************** +static int32_t +SlideMenuMove(tWidget *psWidget, uint32_t ui32Msg) +{ + // + // Process the key event. + // + switch(ui32Msg) + { + // + // User presses select button. + // + case WIDGET_MSG_KEY_SELECT: + { + return(SlideMenuClick(psWidget)); + } + + // + // User presses up button. + // + case WIDGET_MSG_KEY_UP: + { + return(SlideMenuUp(psWidget)); + } + + // + // User presses down button. + // + case WIDGET_MSG_KEY_DOWN: + { + return(SlideMenuDown(psWidget)); + } + + // + // User presses left button. + // + case WIDGET_MSG_KEY_LEFT: + { + return(SlideMenuLeft(psWidget)); + } + + // + // User presses right button. + // + case WIDGET_MSG_KEY_RIGHT: + { + return(SlideMenuRight(psWidget)); + } + + // + // This is an unexpected event. Return an indication that the event + // was not handled. + // + default: + { + return(0); + } + } +} + +//***************************************************************************** +// +//! Handles messages for a slide menu widget. +//! +//! \param psWidget is a pointer to the slide menu widget. +//! \param ui32Msg is the message. +//! \param ui32Param1 is the first parameter to the message. +//! \param ui32Param2 is the second parameter to the message. +//! +//! This function receives messages intended for this slide menu widget and +//! processes them accordingly. The processing of the message varies based on +//! the message in question. +//! +//! Unrecognized messages are handled by calling WidgetDefaultMsgProc(). +//! +//! \return Returns a value appropriate to the supplied message. +// +//***************************************************************************** +int32_t +SlideMenuMsgProc(tWidget *psWidget, uint32_t ui32Msg, uint32_t ui32Param1, + uint32_t ui32Param2) +{ + // + // Check the arguments. + // + ASSERT(psWidget); + + // + // Determine which message is being sent. + // + switch(ui32Msg) + { + // + // The widget paint request has been sent. + // + case WIDGET_MSG_PAINT: + { + // + // Handle the widget paint request. + // + SlideMenuPaint(psWidget); + + // + // Return one to indicate that the message was successfully + // processed. + // + return(1); + } + + // + // A key event has been received. By convention, this widget will + // process the key events if ui32Param1 is set to this widget. + // Otherwise a different widget has the "focus" for key events. + // + case WIDGET_MSG_KEY_SELECT: + case WIDGET_MSG_KEY_UP: + case WIDGET_MSG_KEY_DOWN: + case WIDGET_MSG_KEY_LEFT: + case WIDGET_MSG_KEY_RIGHT: + { + // + // If this key event is for us, then process the event. + // + if((tWidget *)ui32Param1 == psWidget) + { + return(SlideMenuMove(psWidget, ui32Msg)); + } + } + + // + // An unknown request has been sent. This widget does not handle + // pointer events, so they get dumped here if they occur. + // + default: + { + // + // Let the default message handler process this message. + // + return(WidgetDefaultMsgProc(psWidget, ui32Msg, ui32Param1, + ui32Param2)); + } + } +} + +//***************************************************************************** +// +//! Initializes a slide menu widget. +//! +//! \param psWidget is a pointer to the slide menu widget to initialize. +//! \param psDisplay is a pointer to the display on which to draw the menu. +//! \param i32X is the X coordinate of the upper left corner of the canvas. +//! \param i32Y is the Y coordinate of the upper left corner of the canvas. +//! \param i32Width is the width of the canvas. +//! \param i32Height is the height of the canvas. +//! \param psDisplayOffA is one of two off-screen displays used for rendering. +//! \param psDisplayOffB is one of two off-screen displays used for rendering. +//! \param ui32ItemHeight is the height of a menu item +//! \param ui32Foreground is the foreground color used for menu item boundaries +//! and text. +//! \param ui32Background is the background color of a menu item. +//! \param ui32Highlight is the color of a highlighted menu item. +//! \param psFont is a pointer to the font that should be used for text. +//! \param psMenu is the initial menu to display +//! +//! This function initializes the caller provided slide menu widget. +//! +//! \return None. +// +//***************************************************************************** +void +SlideMenuInit(tSlideMenuWidget *psWidget, const tDisplay *psDisplay, + int32_t i32X, int32_t i32Y, int32_t i32Width, int32_t i32Height, + tDisplay *psDisplayOffA, tDisplay *psDisplayOffB, + uint32_t ui32ItemHeight, uint32_t ui32Foreground, + uint32_t ui32Background, uint32_t ui32Highlight, + tFont *psFont, tSlideMenu *psMenu) +{ + uint32_t ui32Idx; + + // + // Check the arguments. + // + ASSERT(psWidget); + ASSERT(psDisplay); + ASSERT(psDisplayOffA); + ASSERT(psDisplayOffB); + ASSERT(psFont); + ASSERT(psMenu); + + // + // Clear out the widget structure. + // + for(ui32Idx = 0; ui32Idx < sizeof(tSlideMenuWidget); ui32Idx += 4) + { + ((uint32_t *)psWidget)[ui32Idx / 4] = 0; + } + + // + // Set the size of the widget structure. + // + psWidget->sBase.i32Size = sizeof(tSlideMenuWidget); + + // + // Mark this widget as fully disconnected. + // + psWidget->sBase.psParent = 0; + psWidget->sBase.psNext = 0; + psWidget->sBase.psChild = 0; + + // + // Save the display pointer. + // + psWidget->sBase.psDisplay = psDisplay; + + // + // Set the extents of the display area. + // + psWidget->sBase.sPosition.i16XMin = i32X; + psWidget->sBase.sPosition.i16YMin = i32Y; + psWidget->sBase.sPosition.i16XMax = i32X + i32Width - 1; + psWidget->sBase.sPosition.i16YMax = i32Y + i32Height - 1; + + // + // Initialize the widget fields + // + psWidget->psDisplayA = psDisplayOffA; + psWidget->psDisplayB = psDisplayOffB; + psWidget->ui32MenuItemHeight = ui32ItemHeight; + psWidget->ui32ColorForeground = ui32Foreground; + psWidget->ui32ColorBackground = ui32Background; + psWidget->ui32ColorHighlight = ui32Highlight; + psWidget->psFont = psFont; + psWidget->psSlideMenu = psMenu; + + // + // Use the slide menu message handler to process messages to this widget. + // + psWidget->sBase.pfnMsgProc = SlideMenuMsgProc; +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** diff --git a/boards/ek-lm4f232/drivers/slidemenuwidget.h b/boards/ek-lm4f232/drivers/slidemenuwidget.h new file mode 100644 index 0000000..c7a1647 --- /dev/null +++ b/boards/ek-lm4f232/drivers/slidemenuwidget.h @@ -0,0 +1,457 @@ +//***************************************************************************** +// +// slidemenuwidget.h - Prototypes for a sliding menu widget. +// +// Copyright (c) 2011-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 EK-LM4F232 Firmware Package. +// +//***************************************************************************** + +#ifndef __SLIDEMENUWIDGET_H__ +#define __SLIDEMENUWIDGET_H__ + +//***************************************************************************** +// +//! \addtogroup slidemenuwidget_api +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +//! The structure that describes a menu item in the menu tree. +// +//***************************************************************************** +typedef struct _SlideMenuItem +{ + // + //! A pointer to text to be rendered within the node. + // + char *pcText; + + // + //! A child menu that is activated by this menu item, if any. Can be NULL. + // + struct _SlideMenu *psChildMenu; + + // + //! A child widget that is activated by this menu item, if any. Can be + //! NULL. If both child menu and child widget are specified, the child + //! menu will be used. + // + tWidget *psChildWidget; + + // + //! A color that is used when a child widget is activated. This is the + //! color that is used as a background when the menu slides off to make + //! the screen available for the child widget. By choosing this color to + //! match the background that is used in the child widget, the sliding + //! animation and widget painting appears smoother. + // + uint32_t ui32ChildWidgetColor; +} +tSlideMenuItem; + +//***************************************************************************** +// +//! The structure that describes a menu. +// +//***************************************************************************** +typedef struct _SlideMenu +{ + // + //! The parent menu of this menu. + // + struct _SlideMenu *psParent; + + // + //! The total number of items in this menu. + // + uint32_t ui32Items; + + // + //! A pointer to the array of menu item structures. + // + tSlideMenuItem *psSlideMenuItems; + + // + //! The menu item index of the item shown on the center of the screen. + //! Normally this is the same as the menu item that has the focus, but + //! can be different during the time when the menu is "sliding". When this + //! is 0, the first menu item is shown in the center of the screen and the + //! successive items are shown below it. When non-zero, then this menu + //! item is shown in the center, with preceding menu items shown above + //! and successive items shown below. + // + uint32_t ui32CenterIndex; + + // + //! The menu item index that has the focus. + // + uint32_t ui32FocusIndex; + + // + //! A flag to indicate if more than one menu item is selectable. + // + bool bMultiSelectable; + + // + //! A set of bit flags to indicate which menu items are selected. + // + uint32_t ui32SelectedFlags; +} tSlideMenu; + +//***************************************************************************** +// +//! The structure that describes a slide menu widget. +// +//***************************************************************************** +typedef struct +{ + // + //! The generic widget information. + // + tWidget sBase; + + // + //! A pointer to an off-screen display that is used for rendering the + //! menus prior to showing on the widget's area of the screen. There + //! are two off-screen displays. Each should be the size of the widget + //! area. The palette should include any colors that are used by this + //! widget. + // + tDisplay *psDisplayA; + + // + //! A pointer to a second off-screen display. + // + tDisplay *psDisplayB; + + // + //! The height, in pixels, of a single menu item (a cell). + // + uint32_t ui32MenuItemHeight; + + // + //! The color used for drawing menu item cell boundaries and text. + // + uint32_t ui32ColorForeground; + + // + //! The background color of menu item cells. + // + uint32_t ui32ColorBackground; + + // + //! The color of a highlighted menu item. + // + uint32_t ui32ColorHighlight; + + // + //! The font to use for menu text. + // + const tFont *psFont; + + // + //! The current menu to display. + // + tSlideMenu *psSlideMenu; + + // + // A function to call when a child widget becomes active or inactive + // + void (*pfnActive)(tWidget *psWidget, tSlideMenuItem *psMenuItem, + bool bActivated); +} +tSlideMenuWidget; + +//***************************************************************************** +// +//! Declares an initialized slide menu widget data structure. +//! +//! \param pParent is a pointer to the parent widget. +//! \param pNext is a pointer to the sibling widget. +//! \param pChild is a pointer to the first child widget. +//! \param pDisplay is a pointer to the off-screen display on which to draw. +//! \param i32X is the X coordinate of the upper left corner of the canvas. +//! \param i32Y is the Y coordinate of the upper left corner of the canvas. +//! \param i32Width is the width of the canvas. +//! \param i32Height is the height of the canvas. +//! \param psDisplayA is one of two off-screen displays for rendering menus. +//! \param psDisplayB is one of two off-screen displays for rendering menus. +//! \param ui32MenuItemHeight is the height of a menu item. +//! \param ui32Foreground is the foreground color for menu item boundaries and +//! text. +//! \param ui32Background is the background color of the menu items. +//! \param ui32Highlight is the color of a highlighted menu item. +//! \param psFont is the font to use for the menu text. +//! \param psMenu is the initial menu to display. +//! \param pfnWidgetActive is a pointer to a function that will be called when +//! a child widget is activated or deactivated. +//! +//! This macro provides an initialized slide menu widget data structure, which +//! can be used to construct the widget tree at compile time in global variables +//! (as opposed to run-time via function calls). This must be assigned to a +//! variable, such as: +//! +//! \verbatim +//! tSlideMenuWidget g_i16SlideMenu = SlideMenuStruct(...); +//! \endverbatim +//! +//! Or, in an array of variables: +//! +//! \verbatim +//! tSlideMenuWidget g_pi16SlideMenu[] = +//! { +//! SlideMenuStruct(...), +//! SlideMenuStruct(...) +//! }; +//! \endverbatim +//! +//! \return Nothing; this is not a function. +// +//***************************************************************************** +#define SlideMenuStruct(pParent, pNext, pChild, pDisplay, \ + i32X, i32Y, i32Width, i32Height, \ + psDisplayA, psDisplayB, \ + ui32MenuItemHeight, ui32Foreground, ui32Background, \ + ui32Highlight, psFont, psMenu, pfnWidgetActive) \ + { \ + { \ + sizeof(tSlideMenuWidget), \ + (tWidget *)(pParent), \ + (tWidget *)(pNext), \ + (tWidget *)(pChild), \ + pDisplay, \ + { \ + i32X, \ + i32Y, \ + (i32X) + (i32Width) - 1, \ + (i32Y) + (i32Height) - 1 \ + }, \ + SlideMenuMsgProc \ + }, \ + psDisplayA, \ + psDisplayB, \ + ui32MenuItemHeight, \ + ui32Foreground, \ + ui32Background, \ + ui32Highlight, \ + psFont, \ + psMenu, \ + pfnWidgetActive \ + } + +//***************************************************************************** +// +//! Declares an initialized variable containing a slide menu widget data +//! structure. +//! +//! \param i16Name is the name of the variable to be declared. +//! \param pParent is a pointer to the parent widget. +//! \param pNext is a pointer to the sibling widget. +//! \param pChild is a pointer to the first child widget. +//! \param pDisplay is a pointer to the off-screen display on which to draw. +//! \param i32X is the X coordinate of the upper left corner of the canvas. +//! \param i32Y is the Y coordinate of the upper left corner of the canvas. +//! \param i32Width is the width of the canvas. +//! \param i32Height is the height of the canvas. +//! \param psDisplayA is one of two off-screen displays for rendering menus. +//! \param psDisplayB is one of two off-screen displays for rendering menus. +//! \param ui32MenuItemHeight is the height of a menu item. +//! \param ui32Foreground is the foreground color for menu item boundaries and +//! text. +//! \param ui32Background is the background color of the menu items. +//! \param ui32Highlight is the color of a highlighted menu item. +//! \param psFont is the font to use for the menu text. +//! \param psMenu is the initial menu to display. +//! \param pfnWidgetActive is a pointer to a function that will be called when +//! a child widget is activated or deactivated. +//! +//! This macro declares a variable containing an initialized slide menu widget +//! data structure, which can be used to construct the widget tree at compile +//! time in global variables (as opposed to run-time via function calls). +//! +//! \return Nothing; this is not a function. +// +//***************************************************************************** +#define SlideMenu(i16Name, pParent, pNext, pChild, pDisplay, \ + i32X, i32Y, i32Width, i32Height, \ + psDisplayA, psDisplayB, \ + ui32MenuItemHeight, ui32Foreground, ui32Background, \ + ui32Highlight, psFont, psMenu, pfnWidgetActive) \ + tSlideMenuWidget i16Name = \ + SlideMenuStruct(pParent, pNext, pChild, pDisplay, \ + i32X, i32Y, i32Width, i32Height, \ + psDisplayA, psDisplayB, \ + ui32MenuItemHeight, ui32Foreground, ui32Background,\ + ui32Highlight, psFont, psMenu, pfnWidgetActive) + +//***************************************************************************** +// +//! Sets the active menu of the slide menu widget. +//! +//! \param psSlideMenuWidget is a pointer to the slide menu widget to modify. +//! \param psMenu is the new slide menu to make active. +//! +//! This function sets the active menu for the widget. +//! +//! \return None. +// +//***************************************************************************** +#define SlideMenuMenuSet(psSlideMenuWidget, psMenu) \ + do \ + { \ + (psSlideMenuWidget)->psSlideMenu = (psMenu); \ + } while(0) + +//***************************************************************************** +// +//! Sets the active callback function for a slide menu widget. +//! +//! \param psSlideMenuWidget is a pointer to the slide menu widget to modify. +//! \param pfnActivated is a function pointer to the function that should +//! be called when the menu system activates or deactivates a child widget. +//! +//! This function sets the child widget active callback function. +//! +//! \return None. +// +//***************************************************************************** +#define SlideMenuActiveCallbackSet(psSlideMenuWidget, pfnActivated) \ + do \ + { \ + (psSlideMenuWidget)->pfnActive = (pfnActivated); \ + } while(0) + +//***************************************************************************** +// +//! Gets the index of the menu item that has the focus. +//! +//! \param psSlideMenu is a pointer to the menu to query for item index. +//! +//! This function returns the index of the menu item that has the focus for +//! the specified menu. +//! +//! \return Index of the menu item that has the focus. +// +//***************************************************************************** +#define SlideMenuFocusItemGet(psSlideMenu) \ + ((psSlideMenu)->ui32FocusIndex) + +//***************************************************************************** +// +//! Gets the selected items mask for a menu. +//! +//! \param psSlideMenu is a pointer to the menu to query for selected items. +//! +//! This function returns a value that is a bit mask of any menu items that +//! are selected in the current menu. This is meant to work when a menu is +//! configured to be selectable. Then multiple menu items can be selected and +//! the selection mask indicates which are selected. +//! +//! \return Selection bit mask of selected menu items. +// +//***************************************************************************** +#define SlideMenuSelectedGet(psSlideMenu) \ + ((psSlideMenu)->ui32SelectedFlags) + +//***************************************************************************** +// +//! Sets the focus item index for a menu. +//! +//! \param psSlideMenu is a pointer to the menu to set the focus item. +//! \param ui32Focus is the index of the menu item that should have the focus. +//! +//! This function is used to specify which menu item should have the focus. +//! +//! \return None. +// +//***************************************************************************** +#define SlideMenuFocusItemSet(psSlideMenu, ui32Focus) \ + do \ + { \ + (psSlideMenu)->ui32FocusIndex = (ui32Focus); \ + (psSlideMenu)->ui32CenterIndex = (ui32Focus); \ + } while(0) + +//***************************************************************************** +// +//! Sets the selected items bit mask for a menu. +//! +//! \param psSlideMenu is a pointer to the menu to set the selection mask. +//! \param ui32Selected is a bit mask indicating which menu items should be +//! marked as selected. +//! +//! This function is used to specify which menu items are pre-selected. +//! +//! \return None. +// +//***************************************************************************** +#define SlideMenuSelectedSet(psSlideMenu, ui32Selected) \ + do \ + { \ + (psSlideMenu)->ui32SelectedFlags = (ui32Selected); \ + } while(0) + +//***************************************************************************** +// +// Prototypes for the slide menu widget APIs. +// +//***************************************************************************** +extern int32_t SlideMenuMsgProc(tWidget *psWidget, uint32_t ui32Msg, + uint32_t ui32Param1, uint32_t ui32Param2); +void SlideMenuDraw(tSlideMenuWidget *psMenuWidget, tContext *pContext, + int32_t i32OffsetY); +extern void SlideMenuInit(tSlideMenuWidget *psWidget, const tDisplay *pDisplay, + int32_t i32X, int32_t i32Y, int32_t i32Width, int32_t i32Height, + tDisplay *pDisplayOffA, tDisplay *pDisplayOffB, + uint32_t ui32ItemHeight, + uint32_t ui32Foreground, + uint32_t ui32Background, + uint32_t ui32Highlight, + tFont *psFont, tSlideMenu *psMenu); + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** + +#endif // __SLIDEMENUWIDGET_H__ diff --git a/boards/ek-lm4f232/drivers/stripchartwidget.c b/boards/ek-lm4f232/drivers/stripchartwidget.c new file mode 100644 index 0000000..60d9d37 --- /dev/null +++ b/boards/ek-lm4f232/drivers/stripchartwidget.c @@ -0,0 +1,672 @@ +//***************************************************************************** +// +// stripchartwidget.c - A simple strip chart widget. +// +// Copyright (c) 2011-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 EK-LM4F232 Firmware Package. +// +//***************************************************************************** + +#include +#include +#include "driverlib/debug.h" +#include "grlib/grlib.h" +#include "grlib/widget.h" +#include "stripchartwidget.h" + +//***************************************************************************** +// +//! \addtogroup stripchartwidget_api +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// This is a custom widget for drawing a simple strip chart. The strip +// chart can be configured with an X/Y grid, and data series can be added +// to and displayed on the strip chart. The strip chart can be "advanced" +// so that the grid lines will move on the display. Before advancing +// the chart, the application must update the series data in the buffers. +// The strip chart will only display whatever is in the series buffers, the +// application must scroll the data in the series data buffers. By adjusting +// the data in the series data buffers, advancing the strip chart, and +// repainting, the strip chart can be made to scroll the data across the +// display. +// +//***************************************************************************** + +//***************************************************************************** +// +//! Draws the strip chart into a drawing context, off-screen buffer. +//! +//! \param psChartWidget points at the StripsChartWidget being processed. +//! \param psContext points to the context where all drawing should be done. +//! +//! This function renders a strip chart into a drawing context. +//! It assumes that the drawing context is an off-screen buffer, and that +//! the entire buffer belongs to this widget. +//! +//! \return None. +// +//***************************************************************************** +void +StripChartDraw(tStripChartWidget *psChartWidget, tContext *psContext) +{ + tStripChartAxis *psAxisY; + int32_t i32Y; + int32_t i32Ygrid; + int32_t i32X; + int32_t i32GridRange; + int32_t i32DispRange; + int32_t i32GridMin; + int32_t i32DispMax; + tStripChartSeries *psSeries; + + // + // Check the parameters + // + ASSERT(psChartWidget); + ASSERT(psContext); + ASSERT(psChartWidget->psAxisY); + + // + // Get handy pointer to Y axis + // + psAxisY = psChartWidget->psAxisY; + + // + // Find the range of Y axis in Y axis units + // + i32GridRange = psAxisY->i32Max - psAxisY->i32Min; + + // + // Find the range of the Y axis in display units (pixels) + // + i32DispRange = (psContext->sClipRegion.i16YMax - + psContext->sClipRegion.i16YMin); + + // + // Find the minimum Y units value to be shown, and the maximum of the + // clipping region. + // + i32GridMin = psAxisY->i32Min; + i32DispMax = psContext->sClipRegion.i16YMax; + + // + // Set the fg color for the rectangle fill to match what we want as the + // chart background. + // + GrContextForegroundSet(psContext, psChartWidget->ui32BackgroundColor); + GrRectFill(psContext, &psContext->sClipRegion); + + // + // Draw vertical grid lines + // + GrContextForegroundSet(psContext, psChartWidget->ui32GridColor); + for(i32X = psChartWidget->i32GridX; i32X < psContext->sClipRegion.i16XMax; + i32X += psChartWidget->psAxisX->i32GridInterval) + { + GrLineDrawV(psContext, psContext->sClipRegion.i16XMax - i32X, + psContext->sClipRegion.i16YMin, + psContext->sClipRegion.i16YMax); + } + + // + // Draw horizontal grid lines + // + for(i32Ygrid = psAxisY->i32Min; i32Ygrid < psAxisY->i32Max; + i32Ygrid += psAxisY->i32GridInterval) + { + i32Y = ((i32Ygrid - i32GridMin) * i32DispRange) / i32GridRange; + i32Y = i32DispMax - i32Y; + GrLineDrawH(psContext, psContext->sClipRegion.i16XMin, + psContext->sClipRegion.i16XMax, i32Y); + } + + // + // Compute location of Y=0 line, and draw it + // + i32Y = ((-i32GridMin) * i32DispRange) / i32GridRange; + i32Y = i32DispMax - i32Y; + GrLineDrawH(psContext, psContext->sClipRegion.i16XMin, + psContext->sClipRegion.i16XMax, i32Y); + + // + // Iterate through each series to draw it + // + psSeries = psChartWidget->psSeries; + while(psSeries) + { + int idx = 0; + + // + // Find the starting X position on the display for this series. + // If the series has less data points than can fit on the display + // then starting X can be somewhere in the middle of the screen. + // + i32X = 1 + psContext->sClipRegion.i16XMax - psSeries->ui16NumItems; + + // + // If the starting X is off the left side of the screen, then the + // staring index (idx) for reading data needs to be adjusted to the + // first value in the series that will be visible on the screen + // + if(i32X < psContext->sClipRegion.i16XMin) + { + idx = psContext->sClipRegion.i16XMin - i32X; + i32X = psContext->sClipRegion.i16XMin; + } + + // + // Set the drawing color for this series + // + GrContextForegroundSet(psContext, psSeries->ui32Color); + + // + // Scan through all possible X values, find the Y value, and draw the + // pixel. + // + for(; i32X <= psContext->sClipRegion.i16XMax; i32X++) + { + // + // Find the Y value at each position in the data series. Take into + // account the data size and the stride + // + if(psSeries->ui8DataTypeSize == 1) + { + i32Y = + ((int8_t *)psSeries->pvData)[idx * psSeries->ui8Stride]; + } + else if(psSeries->ui8DataTypeSize == 2) + { + i32Y = + ((int16_t *)psSeries->pvData)[idx * psSeries->ui8Stride]; + } + else if(psSeries->ui8DataTypeSize == 4) + { + i32Y = + ((int32_t *)psSeries->pvData)[idx * psSeries->ui8Stride]; + } + else + { + // + // If there is an invalid data size, then just force Y value + // to be off the display + // + i32Y = i32DispMax + 1; + break; + } + + // + // Advance to the next position in the data series. + // + idx++; + + // + // Now scale the Y value according to the axis scaling + // + i32Y = ((i32Y - i32GridMin) * i32DispRange) / i32GridRange; + i32Y = i32DispMax - i32Y; + + // + // Draw the pixel on the display + // + GrPixelDraw(psContext, i32X, i32Y); + } + + // + // Advance to the next series until there are no more. + // + psSeries = psSeries->psNextSeries; + } + + // + // Draw a frame around the entire chart. + // + GrContextForegroundSet(psContext, psChartWidget->ui32Y0Color); + GrRectDraw(psContext, &psContext->sClipRegion); + + // + // Draw titles + // + GrContextForegroundSet(psContext, psChartWidget->ui32TextColor); + GrContextFontSet(psContext, psChartWidget->psFont); + + // + // Draw the chart title, if there is one + // + if(psChartWidget->pcTitle) + { + GrStringDrawCentered(psContext, psChartWidget->pcTitle, -1, + psContext->sClipRegion.i16XMax / 2, + GrFontHeightGet(psChartWidget->psFont), 0); + } + + // + // Draw the Y axis max label, if there is one + // + if(psChartWidget->psAxisY->pcMaxLabel) + { + GrStringDraw(psContext, psChartWidget->psAxisY->pcMaxLabel, -1, + psContext->sClipRegion.i16XMin + + GrFontMaxWidthGet(psChartWidget->psFont) / 2, + GrFontHeightGet(psChartWidget->psFont) / 2, 0); + } + + // + // Draw the Y axis min label, if there is one + // + if(psChartWidget->psAxisY->pcMinLabel) + { + GrStringDraw(psContext, psChartWidget->psAxisY->pcMinLabel, -1, + psContext->sClipRegion.i16XMin + + GrFontMaxWidthGet(psChartWidget->psFont) / 2, + psContext->sClipRegion.i16YMax - + (GrFontHeightGet(psChartWidget->psFont) + + (GrFontHeightGet(psChartWidget->psFont) / 2)), + 0); + } + + // + // Draw a label for the name of the Y axis, if there is one + // + if(psChartWidget->psAxisY->pcName) + { + GrStringDraw(psContext, psChartWidget->psAxisY->pcName, -1, + psContext->sClipRegion.i16XMin + 1, + (psContext->sClipRegion.i16YMax / 2) - + (GrFontHeightGet(psChartWidget->psFont) / 2), + 1); + } +} + +//***************************************************************************** +// +//! Paints the strip chart on the display. +//! +//! \param psWidget is a pointer to the strip chart widget to be drawn. +//! +//! This function draws the contents of a strip chart on the display. This is +//! called in response to a \b WIDGET_MSG_PAINT message. +//! +//! \return None. +// +//***************************************************************************** +static void +StripChartPaint(tWidget *psWidget) +{ + tStripChartWidget *psChartWidget; + tContext sContext; + + // + // Check the arguments. + // + ASSERT(psWidget); + ASSERT(psWidget->psDisplay); + + // + // Convert the generic widget pointer into a strip chart widget pointer. + // + psChartWidget = (tStripChartWidget *)psWidget; + + // + // Initialize a context for the primary off-screen drawing buffer. + // Clip region is set to entire display by default, which is what we want. + // + ASSERT(psChartWidget->psOffscreenDisplay); + GrContextInit(&sContext, psChartWidget->psOffscreenDisplay); + + // + // Render the strip chart into the off-screen buffer + // + StripChartDraw(psChartWidget, &sContext); + + // + // Initialize a drawing context for the display where the widget is to be + // drawn. This is the physical display, not an off-screen buffer. + // + GrContextInit(&sContext, psWidget->psDisplay); + + // + // Initialize the clipping region on the physical display, based on the + // extents of this widget. + // + GrContextClipRegionSet(&sContext, &(psWidget->sPosition)); + + // + // Now copy the rendered strip chart into the physical display + // + GrImageDraw(&sContext, psChartWidget->psOffscreenDisplay->pvDisplayData, + psWidget->sPosition.i16XMin, psWidget->sPosition.i16YMin); +} + +//***************************************************************************** +// +//! Advances the strip chart X grid by a certain number of pixels. +//! +//! \param psChartWidget is a pointer to the strip chart widget to be advanced. +//! \param i32Count is the number of positions to advance the grid. +//! +//! This function advances the X grid of the strip chart by the specified +//! number of positions. By using this function to advance the grid in +//! combination with updating the data in the series data buffers, the strip +//! chart can be made to appear to scroll across the display. +//! +//! \return None. +// +//***************************************************************************** +void +StripChartAdvance(tStripChartWidget *psChartWidget, int32_t i32Count) +{ + // + // Adjust the starting point of the X-grid + // + psChartWidget->i32GridX += i32Count; + psChartWidget->i32GridX %= psChartWidget->psAxisX->i32GridInterval; +} + +//***************************************************************************** +// +//! Adds a data series to the strip chart. +//! +//! \param psWidget is a pointer to the strip chart widget to be modified. +//! \param psNewSeries is a strip chart data series to be added to the strip +//! chart. +//! +//! This function will add a data series to the strip chart. This function +//! just links the series into the strip chart. It is up to the application +//! to make sure that the data series is initialized correctly. +//! +//! \return None. +// +//***************************************************************************** +void +StripChartSeriesAdd(tStripChartWidget *psWidget, + tStripChartSeries *psNewSeries) +{ + // + // If there is already at least one series in this chart, then link + // in to the existing chain. + // + if(psWidget->psSeries) + { + tStripChartSeries *psSeries = psWidget->psSeries; + while(psSeries->psNextSeries) + { + psSeries = psSeries->psNextSeries; + } + psSeries->psNextSeries = psNewSeries; + } + + // + // Otherwise, there is not already a series in this chart, so set this + // new series as the first series for the chart. + // + else + { + psWidget->psSeries = psNewSeries; + } + psNewSeries->psNextSeries = 0; +} + +//***************************************************************************** +// +//! Removes a data series from the strip chart. +//! +//! \param psWidget is a pointer to the strip chart widget to be modified. +//! \param psOldSeries is a strip chart data series that is to be removed +//! from the strip chart. +//! +//! This function will remove an existing data series from a strip chart. It +//! will search the list of data series for the specified series, and if +//! found it will be unlinked from the chain of data series for this strip +//! chart. +//! +//! \return None. +// +//***************************************************************************** +void +StripChartSeriesRemove(tStripChartWidget *psWidget, + tStripChartSeries *psOldSeries) +{ + // + // If the series to be removed is the first one, then find the next + // series in the chain and set it to be first. + // + if(psWidget->psSeries == psOldSeries) + { + psWidget->psSeries = psOldSeries->psNextSeries; + } + + // + // Otherwise, scan through the chain to find the old series + // + else + { + tStripChartSeries *psSeries = psWidget->psSeries; + while(psSeries->psNextSeries) + { + // + // If the old series is found, unlink it from the chain + // + if(psSeries->psNextSeries == psOldSeries) + { + psSeries->psNextSeries = psOldSeries->psNextSeries; + break; + } + else + { + psSeries = psSeries->psNextSeries; + } + } + } + + // + // Finally, set the "next" pointer of the old series to null so that + // there will not be any confusing chain fragments if this series is + // reused. + // + psOldSeries->psNextSeries = 0; +} + +//***************************************************************************** +// +//! Handles messages for a strip chart widget. +//! +//! \param psWidget is a pointer to the strip chart widget. +//! \param ui32Msg is the message. +//! \param ui32Param1 is the first parameter to the message. +//! \param ui32Param2 is the second parameter to the message. +//! +//! This function receives messages intended for this strip chart widget and +//! processes them accordingly. The processing of the message varies based on +//! the message in question. +//! +//! Unrecognized messages are handled by calling WidgetDefaultMsgProc(). +//! +//! \return Returns a value appropriate to the supplied message. +// +//***************************************************************************** +int32_t +StripChartMsgProc(tWidget *psWidget, uint32_t ui32Msg, uint32_t ui32Param1, + uint32_t ui32Param2) +{ + // + // Check the arguments. + // + ASSERT(psWidget); + + // + // Determine which message is being sent. + // + switch(ui32Msg) + { + // + // The widget paint request has been sent. + // + case WIDGET_MSG_PAINT: + { + // + // Handle the widget paint request. + // + StripChartPaint(psWidget); + + // + // Return one to indicate that the message was successfully + // processed. + // + return(1); + } + + // + // Deliberately ignore all button press messages. They may be handled + // by another widget. + // + case WIDGET_MSG_KEY_SELECT: + case WIDGET_MSG_KEY_UP: + case WIDGET_MSG_KEY_DOWN: + case WIDGET_MSG_KEY_LEFT: + case WIDGET_MSG_KEY_RIGHT: + { + return(0); + } + + // + // An unknown request has been sent. + // + default: + { + // + // Let the default message handler process this message. + // + return(WidgetDefaultMsgProc(psWidget, ui32Msg, ui32Param1, + ui32Param2)); + } + } +} + +//***************************************************************************** +// +//! Initializes a strip chart widget. +//! +//! \param psWidget is a pointer to the strip chart widget to initialize. +//! \param psDisplay is a pointer to the display on which to draw the chart. +//! \param i32X is the X coordinate of the upper left corner of the canvas. +//! \param i32Y is the Y coordinate of the upper left corner of the canvas. +//! \param i32Width is the width of the canvas. +//! \param i32Height is the height of the canvas. +//! \param pcTitle is the label text for the strip chart +//! \param psFont is the font to use for drawing text on the chart. +//! \param ui32BackgroundColor is the colr of the background for the chart. +//! \param ui32TextColor is the color used for drawing text. +//! \param ui32Y0Color is the color used for drawing the Y=0 line and the frame +//! around the chart. +//! \param ui32GridColor is the color of the X/Y grid +//! \param psAxisX is a pointer to the X-axis object +//! \param psAxisY is a pointer to the Y-axis object +//! \param psOffscreenDisplay is a pointer to an offscreen display that will +//! be used for rendering the strip chart prior to drawing it on the +//! physical display. +//! +//! This function initializes the caller provided strip chart widget. +//! +//! \return None. +// +//***************************************************************************** +void +StripChartInit(tStripChartWidget *psWidget, const tDisplay *psDisplay, + int32_t i32X, int32_t i32Y, int32_t i32Width, int32_t i32Height, + char * pcTitle, tFont *psFont, + uint32_t ui32BackgroundColor, + uint32_t ui32TextColor, + uint32_t ui32Y0Color, + uint32_t ui32GridColor, + tStripChartAxis *psAxisX, tStripChartAxis *psAxisY, + tDisplay *psOffscreenDisplay) +{ + uint32_t ui32Idx; + + // + // Check the arguments. + // + ASSERT(psWidget); + ASSERT(psDisplay); + ASSERT(psAxisX); + ASSERT(psAxisY); + ASSERT(psOffscreenDisplay); + + // + // Clear out the widget structure. + // + for(ui32Idx = 0; ui32Idx < sizeof(tStripChartWidget); ui32Idx += 4) + { + ((uint32_t *)psWidget)[ui32Idx / 4] = 0; + } + + // + // Set the size of the widget structure. + // + psWidget->sBase.i32Size = sizeof(tStripChartWidget); + + // + // Mark this widget as fully disconnected. + // + psWidget->sBase.psParent = 0; + psWidget->sBase.psNext = 0; + psWidget->sBase.psChild = 0; + + // + // Save the display pointer. + // + psWidget->sBase.psDisplay = psDisplay; + + // + // Set the extents of the display area. + // + psWidget->sBase.sPosition.i16XMin = i32X; + psWidget->sBase.sPosition.i16YMin = i32Y; + psWidget->sBase.sPosition.i16XMax = i32X + i32Width - 1; + psWidget->sBase.sPosition.i16YMax = i32Y + i32Height - 1; + + // + // Initialize the widget fields + // + psWidget->pcTitle = pcTitle; + psWidget->psFont = psFont; + psWidget->ui32BackgroundColor = ui32BackgroundColor; + psWidget->ui32TextColor = ui32TextColor; + psWidget->ui32Y0Color = ui32Y0Color; + psWidget->ui32GridColor = ui32GridColor; + psWidget->psAxisX = psAxisX; + psWidget->psAxisY = psAxisY; + psWidget->psOffscreenDisplay = psOffscreenDisplay; + + // + // Use the strip chart message handler to process messages to this widget. + // + psWidget->sBase.pfnMsgProc = StripChartMsgProc; +} + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** + diff --git a/boards/ek-lm4f232/drivers/stripchartwidget.h b/boards/ek-lm4f232/drivers/stripchartwidget.h new file mode 100644 index 0000000..2c64f6a --- /dev/null +++ b/boards/ek-lm4f232/drivers/stripchartwidget.h @@ -0,0 +1,392 @@ +//***************************************************************************** +// +// stripchartwidget.h - Prototypes for a strip chart widget. +// +// Copyright (c) 2011-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 EK-LM4F232 Firmware Package. +// +//***************************************************************************** + +#ifndef __STRIPCHARTWIDGET_H__ +#define __STRIPCHARTWIDGET_H__ + +//***************************************************************************** +// +//! \addtogroup stripchartwidget_api +//! @{ +// +//***************************************************************************** + +//***************************************************************************** +// +// If building with a C++ compiler, make all of the definitions in this header +// have a C binding. +// +//***************************************************************************** +#ifdef __cplusplus +extern "C" +{ +#endif + +//***************************************************************************** +// +//! A structure that represents a data series to be shown on the strip chart. +// +//***************************************************************************** +typedef struct _StripChartSeries +{ + // + //! A pointer to the next series in the chart. + // + struct _StripChartSeries *psNextSeries; + + // + //! A pointer to the brief name of the data set + // + char *pcName; + + // + //! The color of the data series. + // + uint32_t ui32Color; + + // + //! The number of bytes of the data type (1, 2, or 4) + // + uint8_t ui8DataTypeSize; + + // + //! The stride of the data. This can be used when this data set is + //! part of a larger set of samples that appear in a large array + //! interleaved at a regular interval. Use a value of 1 if the data set + //! is not interleaved. + // + uint8_t ui8Stride; + + // + //! The number of items in the data set + // + uint16_t ui16NumItems; + + // + //! A pointer to the first data item. + // + void *pvData; +} +tStripChartSeries; + +//***************************************************************************** +// +//! A structure that represents an axis of the strip chart. +// +//***************************************************************************** +typedef struct _StripChartAxis +{ + // + //! A brief name for the axis. Leave null for no name to be shown. + // + char *pcName; + + // + //! Label for the minimum extent of the axis. Leave null for no label. + // + char *pcMinLabel; + + // + //! Label for the max extent of the axis. Leave null for no label. + // + char *pcMaxLabel; + + // + //! The minimum units value for the axis. + // + int32_t i32Min; + + // + //! The maximum units value for the axis + // + int32_t i32Max; + + // + //! The grid interval for the axis. Use 0 for no grid. + // + int32_t i32GridInterval; +} tStripChartAxis; + +//***************************************************************************** +// +//! A structure that represents a strip chart widget. +// +//***************************************************************************** +typedef struct _StripChartWidget +{ + // + //! The generic widget information. + // + tWidget sBase; + + // + //! The title for the strip chart. Leave null for no title. + // + char *pcTitle; + + // + //! The font to use for drawing text on the chart. + // + const tFont *psFont; + + // + //! The background color of the chart. + // + uint32_t ui32BackgroundColor; + + // + //! The color for text that is drawn on the chart (titles, etc). + // + uint32_t ui32TextColor; + + // + //! The color of the Y-axis 0-crossing line. + // + uint32_t ui32Y0Color; + + // + //! The color of the grid lines. + // + uint32_t ui32GridColor; + + // + //! The X axis + // + tStripChartAxis *psAxisX; + + // + //! The Y axis + // + tStripChartAxis *psAxisY; + + // + //! A pointer to the first data series for the strip chart. + // + tStripChartSeries *psSeries; + + // + //! A pointer to an off-screen display to be used for rendering the chart. + // + const tDisplay *psOffscreenDisplay; + + // + //! The current X-grid alignment. This value changes in order to give the + //! appearance of the grid moving as the strip chart advances. + // + int32_t i32GridX; +} tStripChartWidget; + +//***************************************************************************** +// +//! Declares an initialized strip chart widget data structure. +//! +//! \param psParent is a pointer to the parent widget. +//! \param psNext is a pointer to the sibling widget. +//! \param psChild is a pointer to the first child widget. +//! \param psDisplay is a pointer to the off-screen display on which to draw. +//! \param i32X is the X coordinate of the upper left corner of the canvas. +//! \param i32Y is the Y coordinate of the upper left corner of the canvas. +//! \param i32Width is the width of the canvas. +//! \param i32Height is the height of the canvas. +//! \param pcTitle is a string for the chart title, NULL for no title. +//! \param psFont is the font used for rendering text on the chart. +//! \param ui32BackgroundColor is the background color for the chart. +//! \param ui32TextColor is the color of text (titles, labels, etc.) +//! \param ui32Y0Color is the color of the Y-axis gridline at Y=0 +//! \param ui32GridColor is the color of grid lines. +//! \param psAxisX is a pointer to the axis structure for the X-axis. +//! \param psAxisY is a pointer to the axis structure for the Y-axis. +//! \param psOffscreenDisplay is a buffer for rendering the chart before +//! showing on the physical display. The dimensions of the off-screen display +//! should match the drawing area of psDisplay. +//! +//! This macro provides an initialized strip chart widget data structure, which +//! can be used to construct the widget tree at compile time in global +//! variables (as opposed to run-time via function calls). This must be +//! assigned to a variable, such as: +//! +//! \verbatim +//! tStripChartWidget g_sStripChart = StripChartStruct(...); +//! \endverbatim +//! +//! Or, in an array of variables: +//! +//! \verbatim +//! tStripChartWidget g_psStripChart[] = +//! { +//! StripChartStruct(...), +//! StripChartStruct(...) +//! }; +//! \endverbatim +//! +//! \return Nothing; this is not a function. +// +//***************************************************************************** +#define StripChartStruct(psParent, psNext, psChild, psDisplay, \ + i32X, i32Y, i32Width, i32Height, \ + pcTitle, psFont, ui32BackgroundColor, ui32TextColor, \ + ui32Y0Color, ui32GridColor, psAxisX, psAxisY, \ + psOffscreenDisplay) \ + { \ + { \ + sizeof(tStripChartWidget), \ + (tWidget *)(psParent), \ + (tWidget *)(psNext), \ + (tWidget *)(psChild), \ + psDisplay, \ + { \ + i32X, \ + i32Y, \ + (i32X) + (i32Width) - 1, \ + (i32Y) + (i32Height) - 1 \ + }, \ + StripChartMsgProc \ + }, \ + pcTitle, psFont, ui32BackgroundColor, ui32TextColor, ui32Y0Color, \ + ui32GridColor, psAxisX, psAxisY, 0, psOffscreenDisplay, 0 \ + } + +//***************************************************************************** +// +//! Declares an initialized variable containing a strip chart widget data +//! structure. +//! +//! \param sName is the name of the variable to be declared. +//! \param psParent is a pointer to the parent widget. +//! \param psNext is a pointer to the sibling widget. +//! \param psChild is a pointer to the first child widget. +//! \param psDisplay is a pointer to the off-screen display on which to draw. +//! \param i32X is the X coordinate of the upper left corner of the canvas. +//! \param i32Y is the Y coordinate of the upper left corner of the canvas. +//! \param i32Width is the width of the canvas. +//! \param i32Height is the height of the canvas. +//! \param pcTitle is a string for the chart title, NULL for no title. +//! \param psFont is the font used for rendering text on the chart. +//! \param ui32BackgroundColor is the background color for the chart. +//! \param ui32TextColor is the color of text (titles, labels, etc.) +//! \param ui32Y0Color is the color of the Y-axis gridline at Y=0 +//! \param ui32GridColor is the color of grid lines. +//! \param psAxisX is a pointer to the axis structure for the X-axis. +//! \param psAxisY is a pointer to the axis structure for the Y-axis. +//! \param psOffscreenDisplay is a buffer for rendering the chart before +//! showing on the physical display. The dimensions of the off-screen display +//! should match the drawing area of psDisplay. +//! +//! This macro declares a variable containing an initialized strip chart widget +//! data structure, which can be used to construct the widget tree at compile +//! time in global variables (as opposed to run-time via function calls). +//! +//! \return Nothing; this is not a function. +// +//***************************************************************************** +#define StripChart(sName, psParent, psNext, psChild, psDisplay, \ + i32X, i32Y, i32Width, i32Height, \ + pcTitle, psFont, ui32BackgroundColor, ui32TextColor, \ + ui32Y0Color, ui32GridColor, psAxisX, psAxisY, \ + psOffscreenDisplay) \ + tStripChartWidget sName = \ + StripChartStruct(psParent, psNext, psChild, psDisplay, \ + i32X, i32Y, i32Width, i32Height, \ + pcTitle, psFont, ui32BackgroundColor, \ + ui32TextColor, ui32Y0Color, ui32GridColor, \ + psAxisX, psAxisY, psOffscreenDisplay) + +//***************************************************************************** +// +//! Sets the X-axis of the strip chart. +//! +//! \param psStripChartWidget is a pointer to the strip chart widget to modify. +//! \param psAxis is the new X-axis structure for the strip chart. +//! +//! This function sets the X-axis for the widget. +//! +//! \return None. +// +//***************************************************************************** +#define StripChartXAxisSet(psStripChartWidget, psAxis) \ + do \ + { \ + (psStripChartWidget)->psAxisX = psAxis; \ + } while(0) + +//***************************************************************************** +// +//! Sets the Y-axis of the strip chart. +//! +//! \param psStripChartWidget is a pointer to the strip chart widget to modify. +//! \param psAxis is the new Y-axis structure for the strip chart. +//! +//! This function sets the Y-axis for the widget. +//! +//! \return None. +// +//***************************************************************************** +#define StripChartYAxisSet(psStripChartWidget, psAxis) \ + do \ + { \ + (psStripChartWidget)->psAxisY = psAxis; \ + } while(0) + +//***************************************************************************** +// +// Prototypes for the strip chart widget APIs. +// +//***************************************************************************** +extern int32_t StripChartMsgProc(tWidget *psWidget, uint32_t ui32Msg, + uint32_t ui32Param1, uint32_t ui32Param2); +extern void StripChartInit(tStripChartWidget *psWidget, + const tDisplay *psDisplay, + int32_t i32X, int32_t i32Y, + int32_t i32Width, int32_t i32Height, + char * pcTitle, tFont *psFont, + uint32_t ui32BackgroundColor, + uint32_t ui32TextColor, + uint32_t ui32Y0Color, + uint32_t ui32GridColor, + tStripChartAxis *psAxisX, tStripChartAxis *psAxisY, + tDisplay *psOffscreenDisplay); +extern void StripChartSeriesAdd(tStripChartWidget *psWidget, + tStripChartSeries *psSeries); +extern void StripChartSeriesRemove(tStripChartWidget *psWidget, + tStripChartSeries *psSeries); +extern void StripChartAdvance(tStripChartWidget *psChartWidget, + int32_t i32Count); + +//***************************************************************************** +// +// Mark the end of the C bindings section for C++ compilers. +// +//***************************************************************************** +#ifdef __cplusplus +} +#endif + +//***************************************************************************** +// +// Close the Doxygen group. +//! @} +// +//***************************************************************************** + +#endif // __STRIPCHARTWIDGET_H__ diff --git a/boards/ek-lm4f232/drivers/usb_sound.c b/boards/ek-lm4f232/drivers/usb_sound.c new file mode 100644 index 0000000..332f556 --- /dev/null +++ b/boards/ek-lm4f232/drivers/usb_sound.c @@ -0,0 +1,804 @@ +//***************************************************************************** +// +// usb_sound.c - USB host audio handling functions. +// +// Copyright (c) 2012-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 EK-LM4F232 Firmware Package. +// +//***************************************************************************** + +#include +#include +#include "inc/hw_types.h" +#include "inc/hw_memmap.h" +#include "drivers/usb_sound.h" +#include "driverlib/gpio.h" +#include "driverlib/sysctl.h" +#include "driverlib/udma.h" +#include "driverlib/usb.h" +#include "usblib/usblib.h" +#include "usblib/usbmsc.h" +#include "usblib/host/usbhost.h" +#include "usblib/host/usbhaudio.h" + +//***************************************************************************** +// +// The size of the host controller's memory pool in bytes. +// +//***************************************************************************** +#define HCD_MEMORY_SIZE 768 + +//***************************************************************************** +// +// The memory pool to provide to the Host controller driver. +// +//***************************************************************************** +uint8_t g_pHCDPool[HCD_MEMORY_SIZE]; + +//***************************************************************************** +// +// The instance data for the USB host audio driver. +// +//***************************************************************************** +tUSBHostAudioInstance *g_psAudioInstance = 0; + +//***************************************************************************** +// +// Declare the USB Events driver interface. +// +//***************************************************************************** +DECLARE_EVENT_DRIVER(g_sUSBEventDriver, 0, 0, USBHCDEvents); + +//***************************************************************************** +// +// This structure holds the state information for the USB audio device. +// +//***************************************************************************** +static struct +{ + // + // Save the application provided callback function. + // + tUSBBufferCallback pfnCallbackOut; + + // + // Save the application provided callback function. + // + tUSBBufferCallback pfnCallbackIn; + + // + // The event callback for the application. + // + tEventCallback pfnCallbackEvent; + + // + // Volume control multipliers calculated from the information received + // from the audio device. + // + uint32_t pui32Steps[3]; + + // + // The currently pending audio device events. + // + uint32_t ui32EventFlags; + + // + // The current state for the audio device. + // + volatile enum + { + // + // No device is present. + // + STATE_NO_DEVICE, + + // + // Audio device is ready. + // + STATE_DEVICE_READY, + + // + // An unsupported device has been attached. + // + STATE_UNKNOWN_DEVICE, + + // + // A power fault has occurred. + // + STATE_POWER_FAULT + } eState; + +} g_sAudioState; + +//***************************************************************************** +// +// These defines are used with the ui32EventFlags in the g_sAudioState structure. +// +//***************************************************************************** +#define EVENT_OPEN 0x00000001 +#define EVENT_CLOSE 0x00000002 + +//***************************************************************************** +// +// The global that holds all of the host drivers in use in the application. +// In this case, only the host audio class is loaded. +// +//***************************************************************************** +static tUSBHostClassDriver const * const g_ppHostClassDrivers[] = +{ + &g_sUSBHostAudioClassDriver + ,&g_sUSBEventDriver +}; + +//***************************************************************************** +// +// This global holds the number of class drivers in the g_ppHostClassDrivers +// list. +// +//***************************************************************************** +static const uint32_t g_ui32NumHostClassDrivers = + sizeof(g_ppHostClassDrivers) / sizeof(tUSBHostClassDriver *); + +//***************************************************************************** +// +// The control table used by the uDMA controller. This table must be aligned +// to a 1024 byte boundary. In this application uDMA is only used for USB, +// so only the first 6 channels are needed. +// +//***************************************************************************** +#if defined(ewarm) +#pragma data_alignment=1024 +tDMAControlTable g_sDMAControlTable[64]; +#elif defined(ccs) +#pragma DATA_ALIGN(g_sDMAControlTable, 1024) +tDMAControlTable g_sDMAControlTable[64]; +#else +tDMAControlTable g_sDMAControlTable[64] __attribute__ ((aligned(1024))); +#endif + +//***************************************************************************** +// +// This function was the callback function registered with the USB host audio +// class driver. The only two events that are handled at this point are the +// USBH_AUDIO_EVENT_OPEN and USBH_AUDIO_EVENT_CLOSE which indicate that a new +// audio device has been found or that an existing audio device has been +// disconnected. +// +//***************************************************************************** +static void +AudioCallback(tUSBHostAudioInstance *psAudioInstance, + uint32_t ui32Event, + uint32_t ui32MsgParam, + void *pvBuffer) +{ + switch(ui32Event) + { + // + // New USB audio device has been enabled. + // + case USBH_AUDIO_EVENT_OPEN: + { + // + // Set the EVENT_OPEN flag and let the main routine handle it. + // + HWREGBITW(&g_sAudioState.ui32EventFlags, EVENT_OPEN) = 1; + + break; + } + + // + // USB audio device has been removed. + // + case USBH_AUDIO_EVENT_CLOSE: + { + // + // Set the EVENT_CLOSE flag and let the main routine handle it. + // + HWREGBITW(&g_sAudioState.ui32EventFlags, EVENT_CLOSE) = 1; + + break; + } + default: + { + } + } +} + +//***************************************************************************** +// +// Initializes the sound output. +// +// \param ui32Flags is unused as this point but is included for future +// functionality. +// \param pfnCallback is the event callback function for audio devices. +// +// This function prepares the sound driver to enumerate an audio device and +// prepares to play audio once a valid audio device is detected. The +// \e pfnCallback function can be used to receive callbacks when there are +// changes related to the audio device. The ui32Event parameter to the callback +// will be one of the SOUND_EVENT_* values. +// +// \return None +// +//***************************************************************************** +void +USBSoundInit(uint32_t ui32Flags, tEventCallback pfnCallback) +{ + // + // Enable the peripherals used by this example. + // + SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA); + + // + // Set the USB power pins to be controlled by the USB controller. + // + GPIOPinTypeUSBDigital(GPIO_PORTA_BASE, GPIO_PIN_6 | GPIO_PIN_7); + + // + // Enable the uDMA controller and set up the control table base. + // + SysCtlPeripheralEnable(SYSCTL_PERIPH_UDMA); + uDMAEnable(); + uDMAControlBaseSet(g_sDMAControlTable); + + // + // Initialize the USB stack mode to OTG. + // + USBStackModeSet(0, eUSBModeOTG, 0); + + // + // Register the host class drivers. + // + USBHCDRegisterDrivers(0, g_ppHostClassDrivers, g_ui32NumHostClassDrivers); + + // + // Open an instance of the audio class driver. + // + g_psAudioInstance = USBHostAudioOpen(0, AudioCallback); + + // + // Initialize the power configuration. This sets the power enable signal + // to be active high and does not enable the power fault. + // + USBHCDPowerConfigInit(0, USBHCD_VBUS_AUTO_HIGH | USBHCD_VBUS_FILTER); + + // + // Initialize the USB controller for OTG operation with a 2ms polling + // rate. + // + USBOTGModeInit(0, 2000, g_pHCDPool, HCD_MEMORY_SIZE); + + // + // Save the event callback function. + // + g_sAudioState.pfnCallbackEvent = pfnCallback; +} + +//***************************************************************************** +// +// Sets the volume of the audio device. +// +// \param ui32Percent is the volume percentage, which must be between 0% +// (silence) and 100% (full volume), inclusive. +// +// This function sets the volume of the sound output to a value between +// silence (0%) and full volume (100%). +// +// \return None. +// +//***************************************************************************** +void +USBSoundVolumeSet(uint32_t ui32Percent) +{ + uint32_t ui32Value; + + // + // Ignore volume changes if there is no device present. + // + if(g_sAudioState.eState == STATE_DEVICE_READY) + { + // + // Scale the voltage percentage to the decibel range provided by the + // USB audio device. + // + ui32Value = (g_sAudioState.pui32Steps[1] * ui32Percent) / 100; + USBHostAudioVolumeSet(g_psAudioInstance, 0, 1, ui32Value); + + ui32Value = (g_sAudioState.pui32Steps[2] * ui32Percent) / 100; + USBHostAudioVolumeSet(g_psAudioInstance, 0, 2, ui32Value); + } +} + +//***************************************************************************** +// +// Returns the current volume level. +// +// \param ui32Channel is the 0 based channel number to query. +// +// This function returns the current volume, specified as a percentage between +// 0% (silence) and 100% (full volume), inclusive. The \e ui32Channel value +// starts with 0 which is the master audio volume control interface. The +// remaining \e ui32Channel values provide access to various other audio +// channels, with 1 and 2 being left and right audio channels. +// +// \return Returns the current volume. +// +//***************************************************************************** +uint32_t +USBSoundVolumeGet(uint32_t ui32Channel) +{ + uint32_t ui32Volume; + + // + // Initialize the return value in case there is no USB device present. + // + ui32Volume = 0xffffffff; + + // + // Ignore volume request if there is no device present. + // + if(g_sAudioState.eState == STATE_DEVICE_READY) + { + ui32Volume = USBHostAudioVolumeGet(g_psAudioInstance, 0, ui32Channel); + } + + return(ui32Volume); +} + +//***************************************************************************** +// +// This will set the current output audio format of the USB audio device. +// +// \param ui32SampleRate is the sample rate. +// \param ui32BitsPerSample is the number of bits per sample. +// \param ui32Channels is the number of channels. +// +// This sets the current audio format for the USB device that is currently +// connected. If there is no USB device connected or the format is not +// supported then the function will return a non-zero value. The function +// will return zero if the USB audio device was successfully configured to the +// requested audio format. +// +// \return Returns zero if the format was successfully set or returns an +// non-zero value if the format was not able to be set. +// +//***************************************************************************** +uint32_t +USBSoundOutputFormatSet(uint32_t ui32SampleRate, + uint32_t ui32BitsPerSample, uint32_t ui32Channels) +{ + // + // Just return if there is no device at this time. + // + if(g_sAudioState.eState != STATE_DEVICE_READY) + { + return(1); + } + + // + // Call the USB Host Audio function to set the format. + // + return(USBHostAudioFormatSet(g_psAudioInstance, ui32SampleRate, + ui32BitsPerSample, ui32Channels, + USBH_AUDIO_FORMAT_OUT)); +} + +//***************************************************************************** +// +// This will set the current input audio format of the USB audio device +// +// \param ui32SampleRate is the sample rate. +// \param ui32BitsPerSample is the number of bits per sample. +// \param ui32Channels is the number of channels. +// +// This sets the current format for the USB device that is currently connect. +// If there is no USB device connected or the format is not supported then the +// function will return 0. The function will return 1 if the USB audio device +// was successfully configured to the requested format. +// +// \return Returns 1 if the format was successfully set or returns 0 if the +// format was not changed. +// +//***************************************************************************** +uint32_t +USBSoundInputFormatSet(uint32_t ui32SampleRate, + uint32_t ui32BitsPerSample, uint32_t ui32Channels) +{ + // + // Just return if there is no device at this time. + // + if(g_sAudioState.eState != STATE_DEVICE_READY) + { + return(0); + } + + return(USBHostAudioFormatSet(g_psAudioInstance, ui32SampleRate, + ui32BitsPerSample, ui32Channels, + USBH_AUDIO_FORMAT_IN)); +} + +//***************************************************************************** +// +// Returns the current sample rate. +// +// This function returns the sample rate that was set by a call to +// USBSoundSetFormat(). This is needed to retrieve the exact sample rate that is +// in use in case the requested rate could not be matched exactly. +// +// \return The current sample rate in samples/second. +// +//***************************************************************************** +uint32_t +USBSoundOutputFormatGet(uint32_t ui32SampleRate, uint32_t ui32Bits, + uint32_t ui32Channels) +{ + // + // Just return if there is no device at this time. + // + if(g_sAudioState.eState != STATE_DEVICE_READY) + { + return(0); + } + + return(USBHostAudioFormatGet(g_psAudioInstance, ui32SampleRate, ui32Bits, + ui32Channels, USBH_AUDIO_FORMAT_OUT)); +} + +//***************************************************************************** +// +// Returns the current sample rate. +// +// This function returns the sample rate that was set by a call to +// USBSoundSetFormat(). This is needed to retrieve the exact sample rate that is +// in use in case the requested rate could not be matched exactly. +// +// \return The current sample rate in samples/second. +// +//***************************************************************************** +uint32_t +USBSoundInputFormatGet(uint32_t ui32SampleRate, uint32_t ui32Bits, + uint32_t ui32Channels) +{ + // + // Just return if there is no device at this time. + // + if(g_sAudioState.eState != STATE_DEVICE_READY) + { + return(0); + } + + return(USBHostAudioFormatGet(g_psAudioInstance, ui32SampleRate, ui32Bits, + ui32Channels, USBH_AUDIO_FORMAT_IN)); +} + +//***************************************************************************** +// +// This is the generic callback from host stack. +// +// \param pvData is actually a pointer to a tEventInfo structure. +// +// This function will be called to inform the application when a USB event has +// occurred that is outside those related to the audio device. At this +// point this is used to detect unsupported devices being inserted and removed. +// It is also used to inform the application when a power fault has occurred. +// This function is required when the g_USBGenerii8EventDriver is included in +// the host controller driver array that is passed in to the +// USBHCDRegisterDrivers() function. +// +// \return None. +// +//***************************************************************************** +void +USBHCDEvents(void *pvData) +{ + tEventInfo *psEventInfo; + + // + // Cast this pointer to its actual type. + // + psEventInfo = (tEventInfo *)pvData; + + switch(psEventInfo->ui32Event) + { + // + // Unknown device detected. + // + case USB_EVENT_UNKNOWN_CONNECTED: + { + // + // An unknown device was detected. + // + g_sAudioState.eState = STATE_UNKNOWN_DEVICE; + + // + // Call the general event handler if present. + // + if(g_sAudioState.pfnCallbackEvent) + { + g_sAudioState.pfnCallbackEvent(SOUND_EVENT_UNKNOWN_DEV, 1); + } + + break; + } + + // + // Device unplugged. + // + case USB_EVENT_DISCONNECTED: + { + // + // Handle the case where an unknown device is disconnected. + // + if(g_sAudioState.eState == STATE_UNKNOWN_DEVICE) + { + g_sAudioState.eState = STATE_NO_DEVICE; + + // + // Call the general event handler if present. + // + if(g_sAudioState.pfnCallbackEvent) + { + g_sAudioState.pfnCallbackEvent(SOUND_EVENT_UNKNOWN_DEV, 0); + } + } + else + { + // + // Call the general event handler if present. + // + if(g_sAudioState.pfnCallbackEvent) + { + g_sAudioState.pfnCallbackEvent(SOUND_EVENT_DISCONNECT, 0); + } + } + + break; + } + + // + // A power fault has occurred. + // + case USB_EVENT_POWER_FAULT: + { + // + // No power means no device is present. + // + g_sAudioState.eState = STATE_POWER_FAULT; + + break; + } + default: + { + break; + } + } +} + +//***************************************************************************** +// +// This function passes along a buffer callback from the USB host audio driver +// so that the application can process or release the buffers. +// +//***************************************************************************** +void +USBHostAudioCallback(tUSBHostAudioInstance *psAudioInstance, + uint32_t ui32Event, uint32_t ui32Param, void *pvBuffer) +{ + // + // Only call the callback if it is actually present. + // + if(g_sAudioState.pfnCallbackOut) + { + g_sAudioState.pfnCallbackOut(pvBuffer, ui32Event); + } + + // + // Only call the callback if it is actually present. + // + if(g_sAudioState.pfnCallbackIn) + { + g_sAudioState.pfnCallbackIn(pvBuffer, ui32Event); + } +} + +//***************************************************************************** +// +// Starts output of a block of PCM audio samples. +// +// \param pvBuffer is a pointer to the audio data to play. +// \param ui32Size is the length of the data in bytes. +// \param pfnCallback is a function to call when this buffer has be played. +// +// This function starts the output of a block of PCM audio samples. +// +// \return This function returns a non-zero value if the buffer was accepted, +// and returns zero if the buffer was not accepted. +// +//***************************************************************************** +uint32_t +USBSoundBufferOut(const void *pvBuffer, uint32_t ui32Size, + tUSBBufferCallback pfnCallback) +{ + // + // If there is no device present or there is a pending buffer then just + // return with a failure. + // + if(g_sAudioState.eState != STATE_DEVICE_READY) + { + return(0); + } + + // + // Save this buffer callback. + // + g_sAudioState.pfnCallbackOut = pfnCallback; + + // + // Pass the buffer aint32_t to the USB host audio driver for playback. + // + return(USBHostAudioPlay(g_psAudioInstance, (void *)pvBuffer, ui32Size, + USBHostAudioCallback)); +} + +//***************************************************************************** +// +// Requests a new block of PCM audio samples from a USB audio device. +// +// \param pvBuffer is a pointer to a location to store the audio data. +// \param ui32Size is the size of the pvData buffer in bytes. +// \param pfnCallback is a function to call when this buffer has new data. +// +// This function request a new block of PCM audio samples from a USB audio +// device. +// +// \return This function returns a non-zero value if the buffer was accepted, +// and returns zero if the buffer was not accepted. +// +//***************************************************************************** +uint32_t +USBSoundBufferIn(const void *pvBuffer, uint32_t ui32Size, + tUSBBufferCallback pfnCallback) +{ + // + // If there is no device present or there is a pending buffer then just + // return with a failure. + // + if(g_sAudioState.eState != STATE_DEVICE_READY) + { + return(0); + } + + // + // Save this buffer callback. + // + g_sAudioState.pfnCallbackIn = pfnCallback; + + // + // Pass the buffer aint32_t to the USB host audio driver for input. + // + return(USBHostAudioRecord(g_psAudioInstance, (void *)pvBuffer, ui32Size, + USBHostAudioCallback)); +} + +//***************************************************************************** +// +// This function reads the audio volume settings for the USB audio device and +// saves them so that the volume can be scaled correctly. +// +//***************************************************************************** +static void +GetVolumeParameters(void) +{ + uint32_t ui32Max, ui32Min, ui32Res, ui32Channel; + + for(ui32Channel = 0; ui32Channel < 3; ui32Channel++) + { + ui32Max = USBHostAudioVolumeMaxGet(g_psAudioInstance, 0, ui32Channel); + ui32Min = USBHostAudioVolumeMinGet(g_psAudioInstance, 0, ui32Channel); + ui32Res = USBHostAudioVolumeResGet(g_psAudioInstance, 0, ui32Channel); + + g_sAudioState.pui32Steps[ui32Channel] = (ui32Max - ui32Min) / ui32Res; + } +} + +//***************************************************************************** +// +// The main routine for handling USB audio, this should be called periodically +// by the main program and pass in the amount of time in milliseconds that has +// elapsed since the last call. +// +//***************************************************************************** +void +USBMain(uint32_t ui32Ticks) +{ + // + // Tell the OTG library code how much time has passed in + // milliseconds since the last call. + // + USBOTGMain(ui32Ticks); + + switch(g_sAudioState.eState) + { + // + // This is the running state where buttons are checked and the + // screen is updated. + // + case STATE_DEVICE_READY: + { + if(HWREGBITW(&g_sAudioState.ui32EventFlags, EVENT_CLOSE)) + { + HWREGBITW(&g_sAudioState.ui32EventFlags, EVENT_CLOSE) = 0; + g_sAudioState.eState = STATE_NO_DEVICE; + + // + // Call the general event handler if present. + // + if(g_sAudioState.pfnCallbackEvent) + { + g_sAudioState.pfnCallbackEvent(SOUND_EVENT_DISCONNECT, 0); + } + } + break; + } + + // + // If there is no device then just wait for one. + // + case STATE_NO_DEVICE: + { + if(HWREGBITW(&g_sAudioState.ui32EventFlags, EVENT_OPEN)) + { + g_sAudioState.eState = STATE_DEVICE_READY; + + HWREGBITW(&g_sAudioState.ui32EventFlags, EVENT_OPEN) = 0; + + GetVolumeParameters(); + + // + // Call the general event handler if present. + // + if(g_sAudioState.pfnCallbackEvent) + { + g_sAudioState.pfnCallbackEvent(SOUND_EVENT_READY, 0); + } + } + break; + } + + // + // An unknown device was connected. + // + case STATE_UNKNOWN_DEVICE: + { + break; + } + + // + // Something has caused a power fault. + // + case STATE_POWER_FAULT: + { + break; + } + + default: + { + break; + } + } +} diff --git a/boards/ek-lm4f232/drivers/usb_sound.h b/boards/ek-lm4f232/drivers/usb_sound.h new file mode 100644 index 0000000..04bf459 --- /dev/null +++ b/boards/ek-lm4f232/drivers/usb_sound.h @@ -0,0 +1,81 @@ +//***************************************************************************** +// +// usb_sound.h - USB host audio handling header definitions. +// +// Copyright (c) 2012-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 EK-LM4F232 Firmware Package. +// +//***************************************************************************** + +#ifndef USB_SOUND_H_ +#define USB_SOUND_H_ + +//***************************************************************************** +// +// The following are defines for the ui32Event value that is returned with the +// tEventCallback function provided to the USBSoundInit() function. +// +//***************************************************************************** + +// +// A USB audio device has been connected. +// +#define SOUND_EVENT_READY 0x00000001 + +// +// A USB device has been disconnected. +// +#define SOUND_EVENT_DISCONNECT 0x00000002 + +// +// An unknown device has been connected. +// +#define SOUND_EVENT_UNKNOWN_DEV 0x00000003 + +typedef void (* tUSBBufferCallback)(void *pvBuffer, uint32_t ui32Event); +typedef void (* tEventCallback)(uint32_t ui32Event, uint32_t ui32Param); + +extern void USBMain(uint32_t ui32Ticks); + +extern void USBSoundInit(uint32_t ui32EnableReceive, + tEventCallback pfnCallback); +extern void USBSoundVolumeSet(uint32_t ui32Percent); +extern uint32_t USBSoundVolumeGet(uint32_t ui32Channel); + +extern uint32_t USBSoundOutputFormatGet(uint32_t ui32SampleRate, + uint32_t ui32Bits, + uint32_t ui32Channels); +extern uint32_t USBSoundOutputFormatSet(uint32_t ui32SampleRate, + uint32_t ui32Bits, + uint32_t ui32Channels); +extern uint32_t USBSoundInputFormatGet(uint32_t ui32SampleRate, + uint32_t ui32BitsPerSample, + uint32_t ui32Channels); +extern uint32_t USBSoundInputFormatSet(uint32_t ui32SampleRate, + uint32_t ui32Bits, + uint32_t ui32Channels); + +extern uint32_t USBSoundBufferOut(const void *pvData, + uint32_t ui32Length, + tUSBBufferCallback pfnCallback); + +extern uint32_t USBSoundBufferIn(const void *pvData, + uint32_t ui32Length, + tUSBBufferCallback pfnCallback); + +#endif -- cgit v1.3.1